вторник, 1 января 2030 г.

О блоге

Более двадцати лет я занимался разработкой ПО, в основном как программист и тим-лид, а в 2012-2014гг как руководитель департамента разработки и внедрения ПО в компании Интервэйл (подробнее на LinkedIn). Поэтому в моем блоге много заметок о работе, в частности о программировании и компьютерах, а так же об управлении.

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

понедельник, 31 декабря 2029 г.

[life.photo] Характерный портрет: вы и ваш мир моими глазами. Безвозмездно :)

Вы художник? Бармен или музыкант? Или, может быть, коллекционер? Плотник или столяр? Кузнец или слесарь? Владеете маленьким магазинчиком или управляете большим производством? Реставрируете старинные часы или просто починяете примус? Всю жизнь занимаетесь своим любимым делом и хотели бы иметь фото на память?

Предлагаю сделать портрет в обстановке, связанной с вашей работой или увлечением. Абсолютно бесплатно. Очень уж мне нравится фотографировать людей в их естественной среде. Происходить это может так...

воскресенье, 26 июня 2016 г.

[life.business] Очень понравилось про конкуренцию по цене...

...в книге Карла Сьюэлла и Пола Брауна "Клиенты на всю жизнь":

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

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

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

[life.photo] Адам Дакворт "Фотосъемка со вспышкой. Практическое руководство"

Осилил в конце-концов замечательную книжицу Адами Дакворта "Фотосъемка со вспышкой. Практическое руководство". Всем фотолюбителям, которые знают о фотовспышках лишь по наслышке, читать обязательно. Автор книги простым языком, с большим количеством примеров, рассказывает что, как и зачем. После прочтения проффи, конечно же, не станешь, но понимания прибавится. Я бы даже сказал, что прибавится в разы.

Отмечу одну особенность: книга производит впечатление небольшой, но концентрация полезной информации там настолько высокая, что у меня не получалось читать более двух-четырех страничек за раз. Прочитаешь очередной совет или описание процедуры съемки того или иного кадра, и несколько подвисаешь. Требуется время, чтобы в голове все уложилось. Если пытаться читать "запоем", то ничего не запоминается.

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

Резюмируя: для начинающих фотолюбителей must have & must read. Хотя не исключено, что после прочтения с фотовспышкой просто не захочется связываться. Или, напротив, захочется приобрести себе 3-4 штуки с радиосинхронизаторами, софт- и стрипбоксами, и снимать все только с полностью контролируемым светом :)

пятница, 24 июня 2016 г.

[prog.c++11] Как можно получить результат доставки сообщения до агента-адресата?

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

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

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

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

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

Второй способ базируется на том, что результат доставки приходит к отправителю в виде дополнительных сообщений-уведомлений. В простейшем случае таких сообщений может быть два: одно сигнализирует об успешной доставке (уведомление delivered), второе -- о неудачной (уведомление lost). Эти уведомления будут отсылаться в разные моменты жизненного цикла отосланного сообщения:

  • уведомление delivered должно отсылаться агентом-адресатом после того, как он завершил обработку интересующего нас сообщения. Это принципиальный момент. Никто кроме агента-адресата не знает, когда эта обработка может считаться законченной;
  • а вот уведомление lost отсылается в деструкторе интересующего нас прикладного сообщения. Деструктор прикладного сообщения вызывается всегда, вне зависимости от того, было оно доставлено до адресата или нет. Соответственно, в деструкторе можно проверить некий флаг и, если этот флаг не выставлен, решить, что сообщение доставлено не было и отослать уведомление lost.

Получается нехитрая логика: в прикладном сообщении заводятся дополнительные поля (как минимум mbox для уведомлений + флаг успешности доставки). Когда агент-адресат получает прикладное сообщение и успешно обрабатывает его, то агент-адресат выставляет флаг и отсылает уведомление delivered. Затем в деструкторе прикладного сообщения флаг успешности доставки проверяется и, при необходимости, отсылается уведомление lost.

Данный способ не имеет недостатков первого способа, основанного на request_value. Но здесь так же есть свои особенности. Во-первых, тут на самом прикладном программисте лежит контроль за тем, сколько же агентов-адресатов получат прикладное сообщение (когда отсылка идет на MPMC-mbox отправитель не знает, сколько реального агентов подписано на сообщение).

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

На Bitbucket-е выложен небольшой пример, показывающий, как воплотить второй подход в жизнь: registered_delivery_example. Показанные там классы delivered, lost и message_base из пространства имен registered_delivery вполне можно копипастить к себе и использовать для подобных целей, благо это шаблонные классы, предназначенные именно для этого :)

понедельник, 20 июня 2016 г.

[life.sport.darts] А руки-то помнят... :)

Очень давно не постил ничего подобного, но тут нужно. А то ведь может никогда такого уже и не повторю.

Для тех, кто не в теме -- это закрытие 157 очков, одно из "гроссмейстерских", если можно так сказать :)

ЗЫ. Мишени уже около 2-х лет. В лучшие же годы у меня мишень жила не больше 8-9 месяцев, а в такое состояние я ее приводил месяца за 4.

воскресенье, 19 июня 2016 г.

[prog.c++14] Еще один способ конкатенации строк в compile-time

Недавно у себя в G+ ленте я дал ссылку на свою первую попытку реализации конкатенации строк в compile-time: https://godbolt.org/g/GWLTN8. Эта версия работала под GCC, но не работала под clang. Причем, как мне представляется, прав в этой ситуации именно clang: ведь constexpr-функция может быть запущенна не только в compile-time, но и в run-time. И clang мог посчитать, что в каких-то контекстах операции, выполняющие обработку аргументов функции, не могут быть использованы.

Дабы избавиться от этой проблемы я нашел другой способ подсчета размерности результирующией строки. В результате код собирается компиляторами clang 3.5-3.8 и gcc 5.1-6.1 с ключиком -std=c++14. Поиграться с кодом можно здесь: https://godbolt.org/g/G5wdyD (так же полный код примера под катом).

Отдельно стоит сказать про выхлоп компилятора. Очевидно, что содержимое результирующей строки формируется в compile-time, иначе бы не работали проверки в static_assert. Но вот как это содержимое добавляется в код зависит от компилятора: clang явно размещает результирующую строку как строковый литерал и затем использует адрес этого литерала. А вот gcc использует серию команд movb для инициализации значения в run-time.

Задачка эта всплыла в большущем LOR-овском флейме. Еще один товарищ из этого обсуждения предложил несколько своих вариантов. Перечислены они здесь: https://www.linux.org.ru/forum/development/12649936?cid=12674932 (пояснительный текст с ссылками на godbolt) и здесь: https://www.linux.org.ru/forum/development/12649936?cid=12675192 (полные тексты). Данные решения используют либо ключи -std=c++1z (т.е. требуют фич из не утвержденного еще стандарта C++17), либо используют GNU-расширения языка. Последнее из решений, в котором используется GNU-тое расширение для формирование compile-time строковых литералов посредством суффикса _ct, дает для clang и GCC одинаковый выхлоп: инициализация строки в run-time через movl.

Какой-то практической значимости у этой форумной задачки не видно. Может быть, подобные фокусы смогут оказаться полезными, когда в программу нужно вшивать base64 представления каких-то строк. Или если в программе нужны строки для представления URL или имен MQ-шных топиков, склеенные из частей, которые известны на этапе компиляции. Но лично я бы в таких случаях предпочел бы pre-compile-time генерацию строковых литералов.

Однако, в плане того, чтобы поразбираться с фичами современного C++ эта задачка очень полезная. Т.к. в интернете можно нагуглить несколько вариантов решения подобной задачи. И далеко не всегда понятно, как и почему это все работает. Ну и самым полезным результатом лично для меня стало открытие вот такой конструкции:

template< std::size_t ...L >
constexpr auto
ct_concat( const char (&...args)[L] )

Эта конструкция позволяет записать шаблон функции с переменным количеством аргументов, аргументами которой должны быть строковые литералы.

Ну а теперь, собственно, то, что у меня получилось.