суббота, 19 октября 2013 г.

[prog] Ссылка на небольшой рассказ про компьютерную систему управления новым американским эсминцем

Вот статья: The Navy’s newest warship is powered by Linux.

Небольшая верхнеуровневая схема компонентов системы оттуда:

В статье говорится о шести миллионах строк кода системы. Только я не понял, включен ли в этот объем код middleware-компонентов. Думаю, что нет. Там и для только прикладного кода шести миллионов строк может оказаться недостаточно, имхо. В общем, тот, кто выполняет такой заказ еще долго без работы не останется -- это же хозяйство еще и сопровождать нужно :)))

Что еще бросилось в глаза: давно не слышал про CORBA, а там она, видимо, применяется в полный рост. Что не удивительно, т.к. такая монстрообразная штука может выжить разве что в военных разработках ;)

[life.business] Если кому-то кажется, что $250 за Lightroom -- это дорого...

Покупателю из Беларусси покупка лицензионной версии Lightroom обойдется в $250. Но, если кому-то кажется, что это крутое наебал не совсем честно, то значит, вы еще не видели более примечательных примеров.

Вот, скажем, есть такой известный бизнес-консультант и писатель Ицхак Адизес. В конце своей книги "Стили менеджмента - эффективные и неэффективные" он указал, что определить стиль своего менеджмента можно с помощью специального инструмента на сайте Института Адизеса.

Действительно, есть там такая возможность. За использование которой просят, ни много, ни мало, $150.

А хотите посмотреть, что из себя представляет этот инструмент на самом деле? Да это обычный опросник, реализация которого в виде Web-приложения у хорошего разработчика займет вряд ли больше нескольких рабочих дней (на все: и на серверную, и на клиентскую части, на тестирование и деплоймент в продакшен).

Ни за что не поверю, что за показанным выше Management Styles Indicator-ом стоит хоть какая-то ручная обработка ответов обманутого вкладчика наивного пользователя. Разве что кто-то вручную поставит роспись на каком-нибудь качественно распечатанном бланке с итоговым вердиктом :)

Вот это я понимаю, вот это эффективный подход к бизнесу. После такого кажется, что Adobe и их белорусско-российским ритейлерам нужно еще учится и учится.

пятница, 18 октября 2013 г.

[management.book] Адизес: Стили менеджмента - эффективные и неэффективные

Под влиянием очень интересной книги Ицхака Адизеса "Управление жизненным циклом корпорации" (о которой я рассказывал здесь) закупил себе еще пару книг этого автора. Одну из них, "Стили менеджмента - эффективные и неэффективные", на днях буквально проглотил за два присеста.

Ну что сказать. Книга читается легко и с удовольствием. Но если вдумчиво читал до этого "Управление жизненным циклом корпорации" то особо нового ничего не узнаешь. Все тоже самое -- четыре составляющие: P (исполнитель), A (администратор), E (предприниматель) и I (интегратор). Только в этой книге сделан упор на обсуждение особенностей стиля работы руководителей того или иного типа. Если интересна эта тема, то книгу можно покупать смело.

Но если не интересно или же жизненный опыт после прочтения "Жизненного цикла" и так уже подсказал яркие примеры тех или иных типов руководителей, то я бы не стал советовать ее. Разве что, если захочется лучше понять свой собственный стиль. Я вот, например, пришел к выводу, что у меня стиль P-E- (т.е. ярко ярко выраженные составляющие "исполнителя" и "предпринимателя", зато полное отсутствие "администратора" и "интегратора", такое сочетание Адизес называет "Основоположник" или "Неудавшийся руководитель из профессионалов"). Хотя, возможно, здесь проявляется эффект медицинского справочника: при его чтении легко находишь у себя симптомы всех описываемых там болезней ;)

Так что потраченного на книгу времени и денег не жалко. Но сложилось впечатление, что чего-то сильно полезного я из нее не вынес.

[life] Еще одна иллюстрация за-e-business-а на Adobe-овском Lightroom-е

В продолжение вчерашней темы. Нашел таки интернет-магазин, в котором физическое лицо из Республики Беларусь может приобрести Adobe Lightroom. От цены, правда, слегка офигел:

Если учесть, что курс y.e. в этом магазине 9400BYR (тогда как курс продажи в банках порядка 9250-9280BYR), то реально выходит даже больше $250.

Хреново во всем этом даже не то, что из-за непонятных моему разуму причин житель РБ должен заплатить на 100y.e. больше, чем житель Болгарии, Кипра или Эстонии, хотя софт и ключ для него будет взят из одного и того же хранилища где-то на серверах Adobe. Хреново то, что граница в $150 является для меня психологическим барьером для текущего качества Lightroom 5.2. Его тормоза выбешивают. А когда за них нужно еще и переплатить $100, то выбешивают еще сильнее.

С другой стороны, работа по перелопачиванию пары последних LR-каталогов под какую-то другую софтину, обойдется мне еще дороже (если попробовать перевести в деньги время и нервы).

четверг, 17 октября 2013 г.

[life] Ну вот что за ё* в*** м***?!!!

Заканчивается ознакомительный период Adobe Lightroom 5. Решил прикупить лицензионный ключ.

Попытался купить в Adobe-овском online-магазине из под своего аккаунта. Не вышло. Не понравилась ему моя страна:

Попробовал купить не логинясь и задействовать другой email для нового ID-шника. И что Adobe мне предложил в списке стран?!!!

Где, блин, Belarus или, хотя бы, Russia? А если я выберу, скажем, Болгарию, то примет ли магазин мою карту, по PAN-у которой понятно, что она выпущена в РБ?

И что мне после этого, покупать LR в российских Интернет-магазинах, где он стоит почему-то дороже, чем на сайте Adobe (порядка 5700RUR вместо ожидаемых 4500RUR)?

Чего-той я недопонимаю... Толи это за-e-business, то ли на-e-business...

[prog.c++] Возможно, в SObjectizer 5.3 появится синхронное взаимодействие агентов

В SObjectizer-е всегда взаимодействие между агентами осуществлялось через асинхронный обмен сообщениями. И это постоянно вызывало вопросы и просьбы добавить в SObjectizer какую-то форму синхронного взаимодействия агентов друг с другом. До сих пор ни одна эта просьба не была удовлетворена :) Основными причинами тому были мое непоколебимое убеждение в том, что единственной идеологически правильной формой взаимодействия является асинхронная, а так же неумение найти способ хоть как-то реализовать синхронные вызовы в SObjectizer-4. Из-за этого, по наследству, отсутствие синхронности перешло и в SObjectizer-5. Но вопросы и сожаления пользователей остались :) Так что мысли продолжали возвращаться к этой теме.

Вчера из-за вынужденного безделья в поезде появилась мысль о том, как можно добавить синхронное взаимодействие агентов в SObjectizer-5 без серьезной переделки ядра SObjectizer-а. В попытках ее зафиксировать были рождены и отвергнуты несколько вариантов. Ниже я опишу тот, на котором я пока остановился.

Синхронное взаимодействие в SObjectizer будет осуществляться посредством "сервисов" (лучшего термина я не придумал). Один агент предоставляет синхронный сервис, другой агент его использует. Главное требование -- поставщик и пользователь синхронного сервиса должны работать на разных рабочих нитях.

Поставщик сервиса -- это агент, который должен быть унаследован не от общего базового типа so_5::rt::agent_t, а от специального базового типа so_5::rt::a_service_provider_t.

Далее, все предоставляемые агентом сервисы должны быть описаны внутри агента в виде специальных атрибутов:

class a_my_service_t : public so_5::rt::a_service_provider_t
{
      typedef so_5::rt::a_service_provider_t base_type_t;

   private :
      // Это сервис, который предоставляет агент.
      so_5::rt::service_handle_t< Result, Argument > svc_my;

Такие атрибуты должны быть специальным образом инициализированы в конструкторе агента (нужно установить связь между хендлом сервиса и агентом, который реализует данный сервис).

   public :
      // Конструктор для агента.
      a_my_service_t(
         so_5::rt::so_environment_t & env )
         :  base_type_t( env )
            // Сервис должен быть связан с агентом.
            // Метод self_service_provider унаследован от
            // a_service_provider_t.
         ,  svc_my( self_service_provider() )
         {}

Сервис реализуется методами агента, по аналогии с обычными событиями. Но, в отличии от обработчиков событий, сервисные методы должны иметь возвращаемое значение. Кроме того, как и с обработчиками событий, если у агента есть несколько состояний, то в каждом из них сервисный метод может быть свой:

class a_my_service_t : public so_5::rt::a_service_provider_t
{
   private :
      // Это сервис, который предоставляет агент.
      so_5::rt::service_handle_t< Result, Argument > svc_my;

      // Состояния, в которых может находится агент.
      so_5::rt::agent_state_t st_free;
      so_5::rt::agent_state_t st_busy;

   public :
      ...

      // Этот обработчик события реализует сервис в состоянии st_free.
      std::unique_ptr< Result >
      svc_my_when_free( const so_5::rt::event_data_t< Argument > & a );

      // Этот обработчик события реализует сервис в состоянии st_busy.
      std::unique_ptr< Result >
      svc_my_when_busy( const so_5::rt::event_data_t< Argument > & a );
};

Увязать все это вместе (т.е. хендл сервиса, состояние агента и сервисные методы) разработчик должен в штатном методе so_define_agent по аналогии с подпиской событий на сообщения:

void
a_my_service_t::so_define_agent()
{
   so_define_service( svc_my )
      .implement( st_free, &a_my_service_t::svc_my_when_free )
      .implement( st_busy, &a_my_service_t::svc_my_when_busy );

   // Остальные действия...
   ...
}

Метод so_define_agent вызывается у агентов в процессе выполнения регистрации кооперации, в которую входит агент. Далее SObjectizer распределяет агентов по их рабочим нитям (для этого каждому из агентов назначается привязка к тому или иному диспетчеру). На стадии этой привязки диспетчеры будут выполнять дополнительные действия. Диспетчер будет смотреть, является ли агент наследником a_service_provider. И если является, то диспетчер будет брать у агента список его сервисов (список объектов-хендлов) и каждому хендлу будет указывать идентификатор рабочей нити агента. Этот идентификатор затем будет использоваться для защиты от дедлоков.

Для того, чтобы какой-то агент мог использовать синхронный сервис, должен быть доступен хендл этого сервиса. Т.е. ссылка/указатель на объект типа service_handle_t<R, A>. Каким образом пользователь будет получать этот хендл -- это забота пользователя. Например, показанный выше a_my_service_t может предоставлять метод-getter вида:

so_5::rt::service_handle_t< Result, Argument >
a_my_service_t::get_svc_handle()
{
   return svc_my;
}

Или же агент a_my_service_t может отсылать этот хендл в каком-то своем сообщении. Например, когда агент переходит из состояния st_busy в st_free он может отослать сообщение msg_i_am_free, в которое поместит хендл своего сервиса:

struct msg_i_am_free : public so_5::rt::message_t
{
   so_5::rt::service_handle_t< Result, Argument > svc;
   ...
}

void
a_my_service_t::switch_to_st_free()
{
   so_change_state( st_free );

   std::unique_ptr< msg_i_am_free > msg( new msg_i_am_free() );
   msg->svc = svc_my;
   ...
   m_my_mbox->deliver_message( std::move( msg ) );
}

Когда пользователь сервиса получает хендл сервиса, он имеет возможность обратиться к сервису двумя способами. Первый способ -- с использованием идиомы future.

// Обработчик уведомления о том, что агент-сервис освободился.
void
a_service_user_t::evt_service_free(
   const so_5::rt::event_data_t< msg_i_am_free > & msg )
{
   // Запрашиваем сервис...
   so_5::rt::future_t< Result > f = msg->svc.async_request( new Argument(...) );
   // ... Выполняем какие-то другие действия и даем сервису
   // время выполнить наш запрос...
   ...
   // Получаем результат запроса.
   std::unique_ptr< Result > r = f.get();
   ... 
}

В этом случае синхронность проявляется, по сути, только при обращении к future_t::get(). Полностью же синхронное обращение к сервису выполняется посредством метода sync_request:

// Обработчик уведомления о том, что агент-сервис освободился.
void
a_service_user_t::evt_service_free(
   const so_5::rt::event_data_t< msg_i_am_free > & msg )
{
   // Запрашиваем сервис и сразу получаем результат.
   std::unique_ptr< Result > r = msg->svc.sync_request( new Argument(...) );
   ...
}

Хотя тут напрашивается простая реализация sync_request в виде простой обертки вокруг async_request и future_t::get:

std::unique_ptr< Result >
sync_request( std::unique_ptr< Argument > a )
{
   so_5::rt::future_t< Result > f = async_request( std::move(a) );
   return f.get();
}

Как бы то ни было, и async_request и sync_request дают пользователю SObjectizer возможность, которой не было ранее, а именно: внутри обработчика события обратиться к другому агенту и тут же получить результат этого обращения. До сих пор программистам для этого нужно было разбивать свой обработчик события на два: в первом инициируется обращение к другому агенту, во втором получается и обрабатывается результат обращения. До сих пор нужно делать так:

// Первая часть обработки.
void
a_some_agent_t::evt_something_happened( event_data_t< SomeInfo > & msg )
{
   // Какая-то первая часть обработки...
   ...
   // Тут пришло время обратиться к другому агенту.
   m_another_agent_mbox->deliver_message( new SomeRequest(...) );
   // На этом обработка заканчивается до ожидания ответа другого агента.
}

// Вторая часть обработки.
void
a_some_agent_t::evt_another_agent_reply( event_data_t< SomeReply > & msg )
{
   // Вторая часть обработки...
   ...
}

С добавлением описанного выше синхронного взаимодействия можно будет писать так:

void
a_some_agent_t::evt_something_happened( event_data_t< SomeInfo > & msg )
{
   // Какая-то первая часть обработки...
   ...
   // Тут пришло время обратиться к другому агенту.
   std::unique_ptr< SomeReply > r = m_another_agent_svc.sync_request(
         new SomeRequest(...) );
   // Вторая часть обработки...
   ...
}

Теперь несколько слов о том, как все это может быть реализовано "под капотом". В самом простейшем виде.

Когда агент создает у себя хендл сервиса, то этот хендл автоматически регистрирует в SObjectizer-е анонимный mbox, ссылка на который будет хранится внутри хендла сервиса.

Когда агент связывает сервисные методы с хендлом сервиса в so_define_agent() происходит подписка этого агента на специальные сообщения в заданных состояниях для анонимного mbox-а хендла сервиса.

Когда какой-то агент обращается к сервису происходит отсылка сообщения на mbox хендла сервиса. Это сообщение обычным образом диспетчируется и передается в очередь агента на обработку. Но когда инициируется обработка этого сообщения, происходит несколько больше действий, чем с обычным сообщением:

  • вызывается не сервисный метод напрямую, а специальная обертка. Внутри которой вызывается сервисный метод и обрабатывается результат его работы;
  • после вызова сервисного метода обертка передает результат его работы в future_t, который связан с вызовом, после чего дает сигнал о том, что сервис обработал.

На стороне пользователя сервиса все самое главное происходит в методе future_t::get(). Там выполняется ожидание сигнала о завершении обработки сервиса или же истечение тайм-аута операции. Тайм-аут нужен для ряда случаев: сервис не был обработан вовсе (предоставляющий сервис агент был дерегистрирован или находился не в том состоянии, очередь заявок к этому агенту была слишком большой) или же произошел деадлок.

Защита от деадлоков -- это отдельный вопрос. В простейшем случае она может быть реализована в виде пары предохранительных мер:

  1. Проверки того, что пользователь и поставщик сервиса работают на разных нитях (эта проверка может быть сделана в самом начале async_request/sync_requst, т.к. в хендле сервиса хранится идентификатор его рабочей нити). Такая проверка позволит сразу диагностировать деадлоки, возникающие из-за работы на одной нити;
  2. Тайм-аутов. Истечение времени ожидания ответа может означать наличие более сложного деадлока. Например, агент A обращается к сервису агента B, который обращается к сервису агента C, который обращается к сервису агента A.

Думаю, что для самой первой реализации синхронного взаимодействия этого будет вполне достаточно. Причем работать это будет довольно шустро. В последующих реализациях можно будет перейти к более сложным схемам, например, к хранению для рабочих нитей списков ожидающих их нитей с проверкой наличия циклов в этих списках. Но тут уже нужно будет смотреть на накладные расходы, а так же на актуальность такого точного контроля.

Вот такая черновая схема получилась в общих чертах. Понятно, что дьявол будет скрываться в пока еще не известных деталях. Но, по первым впечатлениям, вариант вполне работоспособный и реализуемый.

вторник, 15 октября 2013 г.

[life.photo.humour] По случаю...

Забавно даже не то, что в кадр попала не совсем по-русски написанная фраза. А то, что я это на снимке увидел больше чем через месяц после его обработки и публикации:

PS. Снимок сделан в конце августа, в Минске, в торговом комплексе "Столица". Там была какая-то культурная программа с участием артистов из Шери-Ланки.

понедельник, 14 октября 2013 г.

[prog.irony] Подразумевает ли шильдик Microsoft MVP наличие какого-то кругозора?

Или же Microsoft Most Valuable Professional -- это как звание лучшего продавца года?

А то как-то дико читать вот такие высказывания профессионала:

realtime — это что за зверь такой?

PS. Таки да, это вновь тот самый gandjustas. Не перестает радовать внимательных читателей :)

[prog.c++] Б.Страуструп на GoingNative-2013: The Essence of C++: With Examples in C++84, C++98, C++11, and C++14

Вот здесь лежит видеозапись и слайды выступления Б.Страуструпа на GoingNative-2013 с темой "The Essence of C++: With Examples in C++84, C++98, C++11, and C++14".

Видео я не смотрел, а вот слайды презентации пролистал. Очень интересно. Интересующимся развитием языка C++ рекомендую.

Не могу судить, насколько сильно продвинут вперед новые concept-ы (которые в презентации называются так же constraint-ы). Но вот появившиеся в C++11 rvalue references и ставшая благодаря им тривиальной реализация move-семантики, на мой взгляд, перевели C++ на совершенно другой уровень. Боюсь, что любители Java (а может и C#) забросают меня гнилыми помидорами, но на момент появления Java плюсы были намного более мощным и выразительным языком. И сейчас картина повторяется еще раз. Остается только пожалеть, что выхода C++11 пришлось ждать так долго. И надеяться, что с C++14 и последующими этот горький опыт будет учтен.

воскресенье, 13 октября 2013 г.

[life.photo.book] Школа фотографии Майкла Фримана: Цифровая обработка фотографий

Дочитал книгу Майкла Фримана "Цифровая обработка фотографий" из цикла "Школа фотографии Майкла Фримана". Для начинающих фотолюбителей книга из разряда must read (т.е. обязательна к прочтению).

Очень жалею, что чего-то подобного у меня не было год назад, когда я серьезно стал подходить к обработке RAW-файлов сначала в Nikon-овской Capture NX, затем в Adobe Lightroom (до этого я снимал в JPEG и делал лишь минимальную коррекцию снимков в IrfanView). Такая книга определенно сэкономила бы мне массу сил и времени. А так пришлось до многих очень просто и наглядно описанных в книге вещей доходить своим умом, методом многих проб и ошибок. Так что еще раз повторюсь: если вы только подошли к тому, чтобы начать заниматься обработкой RAW-файлов в Lightroom/Aperture/Capture One/Capture NX/AfterShot и планируете затем осваивать Photoshop или PaintShop, то имеет смысл прочитать эту книгу для того, чтобы сразу понимать, что и как можно/нужно делать в RAW-конвертере, а что оставлять программам обработки цифровых изображений.

Даже не смотря на то, что в том же Lightroom-е многие вещи из описанных в книге я освоил самостоятельно, все равно для меня в книге оказалось много приятных и полезных открытий. Так что для меня книга оказалась весьма и весьма полезной. Потому о потраченных на ее приобретение деньгах совершенно не жалею. И настоятельно рекомендую ее всем начинающим фотолюбителям.