четверг, 7 сентября 2017 г.

[prog.actors] Хотите решить задачу с помощью акторов? Спросите меня как! :)

После того, как мне довелось разным людям в разных местах рассказывать про Модель Акторов вообще и про SObjectizer в частности, сложилось впечатление, что продвижению Модели Акторов в массы препятствует две вещи:

  1. Отсутствие понимания того, что такое Модель Акторов вообще. Это, на самом-то деле, совсем не проблема. Очевидно, что всего на свете знать нельзя, а объяснить основные принципы работы Модели Акторов можно буквально на пальцах (что, кстати говоря, подтверждается практикой).
  2. Отсутствие понимания того, как эту самую Модель Акторов, принципы которой можно объяснить на пальцах, применить для решения практических задач.

Тут можно провести аналогию с молотком: понять как действовать молотком не сложно, не сложно и научить им бить. Гораздо сложнее разобраться куда же именно и с какой силой стукнуть молотком дабы получить нужный результат. Вот с Моделью Акторов, имхо, происходит тоже самое. Когда у человека есть конкретная задача, то не факт, что он может представить себе, как же ее решение будет выглядеть на акторах. Ибо понимать принцип -- это одно, а сделать декомпозицию конкретной задачи -- это другое.

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

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

Зачем это нужно мне? Очевидно, что мои цели исключительно корыстные ;) Прежде всего мне нужен материал, на основе которого можно было бы убедительно рассказывать людям о том, где применение Модели Акторов уместно, а где нет. Кстати говоря, неуместность применения Модели Акторов -- это актуальный вопрос. Бывает, что люди слушая про Модель Акторов теряют представление о том, что данная модель применима далеко не всегда. И хорошо бы уметь вовремя различать, где имеет смысл брать акторов, а где этого делать не нужно. Так же мне полезно прикидывать, насколько наш SObjectizer пригоден для решения тех или иных задач. Опыт показывает, что это сильно идет на пользу SObjectizer-у. А т.к. сам SObjectizer распространяется под BSD-лицензией (бездвоздме т.е. даром), то это пойдет на пользу и всем, кто воспользуется SObjectizer-ом.

Зачем это нужно вам? Ну мало ли :) Может вы хотите убедиться, какая все-таки гадость, эта ваша Модель Акторов, а вот вы молодец, когда придумали свое решение без использования акторов ;) Или может вы правда ломаете голову над чем-то и не прочь бы посоветоваться с умным человеком простофилей, который готов тратить свое время бесплатно. Ну или вам просто захотелось пообщаться ;)

В общем, если есть задачка и желание ее обсудить, то милости прошу. Описывайте свои задачки в комментариях к этой заметке (можно в G+), либо по почте eao197 на gmail тчк com, либо со мной можно связаться через FB, LinkedIn или Habrhabr.

PS. Запись специально повисит вверху до сентября. Но, если дело пойдет, можно будет заказать продление ;)

пятница, 26 мая 2017 г.

[flame] Егор Бугаенко в DevZen подкасте (послешоу)

Дослушал таки послешоу подкаста DevZen, в котором участвовал Егор Бугаенко. Впечатления сильно двойственные.

Первые минут 40-50 тов.Бугаенко говорил весьма толково. Если убрать излишнюю категоричность и метафоричность, то получается вменяемый рассказ от вменяемого человека о том, в каких условиях ему приходится работать и как он с этим справляется.

В принципе, здесь я услышал то, что и рассчитывал услышать. Стало лучше понятно, что за компания у Бугаенко. Появилось впечатление, что это даже не классический аутсорсинг. Это, скорее, какой-то маленький маркетплейс для фрилансеров. Только особенность этого маркетплейса в том, что он находится под жестким модерированием создателя, т.е. самого Егора Бугаенко. Он приносит на маркетплейс заказы (окучивая потенциальных заказчиков), он же запускает или выгоняет с этого маркеплейса фрилансеров. Но суть, как мне показалось, именно в том, что под Бугаенко есть некая маленькая биржа труда, на которую с одной стороны вываливаются задачи, а с другой пасутся прикормленные и отдрессированные исполнители.

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


А вот то, что началось где-то с 50-й минуты или позже, когда речь пошла о тенденциях, о менеджменте, о будущих продуктах-платформах, как будто совсем другой человек начал говорить. Как будто вместо здравомыслящего практика микрофон взял совершенно упоротый маркетолог. Тут начались такие же подтасовки и передергивания, как и в рассказах Бугаенко про ООП.

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

  • "Не будут нанимать фрилансера с соседней улицы". Речь шла о том, что ситуация меняется и наступает время, когда нанимать будут не по знакомству или по соседству, а исходя из рыночных реалий. Мол, если такой же спец есть в Китае за меньшие деньги, то брать соседа в Сан-Франциско не будут. Отчасти это так, но все не так просто. Даже не будем рассматривать основную причину, т.е. неравенство доходов в разных концах мира. Ситуация станет сильно другой, когда за одну и ту же работу в США и в Малайзии начнут платить сравнимые деньги. Но есть еще такая вещь, как репутация. Нанять фрилансера в Интернете вовсе не значит гарантировать себе результат. По факту может быть такое, что дешевле было бы нанять соседа задорого, но быть уверенным в том, что работа будет сделано качественно и в срок. В принципе, за примерами далеко не нужно ходить. На рынке стоматологических услуг уже не первый десяток лет услуги предлагают и одиночки, и мелкие кабинеты, и небольшие поликлиники и большие клиники. Только вот мы же не бежим к самому дешевому врачу. Или, скажем, если вам приходилось сталкиваться с ремонтом и вы хотели найти хорошего плиточника, вы же не выбирали самое дешевое предложение в газете частных объявлений. Да и сам Бугаенко признался, что клиенты к нему приходят из-за его репутации, хотя услуги его компании, по его же словам, обходятся недешево. Так что этот тезис ну очень спорен. Хотя с тем, что рынок становится глобальным, и что конкурировать нужно будет с поставщиками таких же услуг из разных концов света, спорить не приходится, это уже свершившийся факт;
  • "Над ними стоит менеджмент, который ничего не делает". Речь про то, что работу работают узкие специалисты (вроде программистов или продавцов), а менеджмент просто паразитирует на их работе. Ну тут можно только посочувствовать человеку, который сталкивался только с таким менеджментом. Дебилы, лентяи, карьеристы и просто случайные люди встречаются везде. И среди программистов, и среди менеджеров. Конечно, когда менеджером становиться дебил-карьерист, то последствия могут быть тяжелыми. Но, тем не менее, ни один сложный и большой проект не способен завершиться успешно без менеджмента. Как бы вы лично к менеджменту не относились, это так. Ну и когда вы сами станете менеджерами и начнете нести ответственность за результат, тогда лучше поймете, делает ли менеджер что-нибудь или нет;
  • "Любой менеджмент должен быть заменен тулзами". Речь про то, что различного рода программы и программые системы, завязанные на правильные методологии, способны устранить промежуточное звено в виде менеджмента. Что не так. Если отбросить категорию "менеджеров", которые занимаются только расстановкой точек в MS Project-е и сбором отчетов о ежедневной загруженности, или же являются всего лишь точкой коммуникаций между руководством и исполнителями, то менеджмент -- он же про работу с людьми. Создание условий для людей, учет их мнений и пожеланий, обучение, решение их проблем, предотвращение конфликтов, устранение последствий конфликтов и т.д. Кто-то всерьез хочет переложить работу с людьми на автоматические тулзы? Ну вперед, чё :)

А вообще, есть замечательная книга Игоря Ашманова "Жизнь внутри пузыря". Там есть целая глава про магов. Так вот, когда я слушаю рассказы Бугаенко про ООП или про то, куда должна двигаться методология разработки программных проектов, я вспоминаю этих самых магов из книжки Ашманова. Чего и вам желаю ;)

четверг, 25 мая 2017 г.

[prog] Интересный момент при проектировании round-robin mbox-а.

Работаю над такой штукой для SObjectizer-а как round-robin mbox. Т.е. почтовый ящик, на который могут подписаться N агентов, но доставка сообщений к ним будет осуществляться по очереди, т.е. сперва первому агенту, затем второму, затем третьему и т.д. Эта штука должна быть удобной, например, при реализации балансировки нагрузки, когда требующие обработки сообщения отсылаются в один и тот же mbox, а распределяться они будут при этом на N агентов-воркеров, прозрачным для отправителя образом.

Подобные вещи и раньше можно было делать, но вручную. А теперь есть возможность предоставить round-robin mbox прямо "из коробки".

Однако, в процессе продумывания реализации round-robin mbox-а обнаружилась неожиданная засада. Дело в том, что в mbox-ах есть такая штука, как delivery filters, т.е. фильтры, которые определяют, имеет ли смысл доставлять конкретное сообщение до конкретного получателя.

Например, представим себе, что у нас есть mbox, в который некий агент время от времени отсылает текущие показатели температуры воздуха в комнате. И у нас есть два агента, которые заинтересованы в получении этих сообщений. Один из этих агентов управляет обогревом комнаты и он хочет получать все сообщения (ему нужно понять когда температура снизилась слишком сильно чтобы включить обогрев и нужно понять, когда температура поднялась достаточно высоко, чтобы выключить обогрев). А второй заинтересован только в сообщениях со слишком высокой температурой, дабы инициировать пожарную тревогу. Вот второй агент установит фильтр доставки, в котором будет проверяться значение в сообщении. Если это значение недостаточно высокое, то второму агенту этот экземпляр сообщения доставляться не будет.

Чем же мешают фильтры доставки в round-robin mbox-е?

Как в принципе должен работать round-robin mbox? У него должен быть список подписчиков на каждый тип сообщения. В этом списке должен быть явно отмечен текущий элемент -- тот подписчик, которому должно быть доставлено следующее сообщение. Когда сообщение приходит, оно отсылается этому подписчику, после чего текущим элементом становится следующий подписчик (ну или первый, если мы дошли до конца). Все просто.

Но это мы пока не рассматривали фильтры доставки. В случае с фильтрами доставки мы должны для текущего элемента спросить у его фильтра "А можно ли доставлять сообщение этому подписчику?" Если можно, то все хорошо, работает привычная схема. А вот если фильтр говорит "Нет"? Что делать тогда?

Вырисовываются следующие варианты:

  1. Просто выбросить этот экземпляр сообщения. Т.е. текущему агенту в списке сообщение не доставляется (что естественно, т.к. фильтр запрещает доставку) и не делается попытка доставить сообщение следующему агенту в списке. Текущим становится следующий агент в списке (или первый, если достигли конца списка).
  2. Попытаться выбрать другого получателя. Т.е. сразу перейти к следующему агенту и спросить его фильтр доставки. Потом к следующему и т.д. до тех пор, пока получатель не будет найден. Может быть вообще ничего не найдем, но тогда данный экземпляр сообщения просто выбрасывается.
  3. Тупой запрет на использование фильтров доставки в случае round-robin mbox-а. Тогда проблемы нет в принципе.
  4. Update. Объединить все фильтры доставки в один комбо-фильтр. Когда появляется сообщение, оно сперва пропускается через этот комбо-фильтр (т.е. через все фильтры). И только если комбо-фильтр пропускает сообщение, только тогда оно доставляется текущему получателю.

Лично я пока склоняюсь к первому варианту. Логика такая: round-robin предполагает, что пытаемся доставлять по очереди. Сейчас очередь у агента X. Если X отказывается принимать сообщение, то он все равно свою очередь использовал и для следующего сообщения очередь перейдет к другому получателю.

Вот только не уверен, что это не будет сбивать пользователей с толку. Кто что думает?

После небольшого обсуждения и дополнительного обдумывания появился вариант №4, который сейчас и кажется наиболее уместным: сообщение должно удовлетворять всех получателей и только тогда можно выбрать очередного получателя для сообщения.

Кстати, попутно еще один вопрос: а кроме round-robin еще какие-нибудь политики доставки для N агентов кому-нибудь нужны/интересны?

понедельник, 22 мая 2017 г.

[prog.flame] Егор Бугаенко в DevZen подкасте

Есть в Рунете такой подкаст: DevZen. Я его практически никогда не слушаю. За исключением некоторых отдельных случаев: один раз там обсуждали именно что мой пост в моем блоге, один раз там говорили про модный и молодежный взгляд на ООП вообще и ООП в C++ в частности, один раз обсуждали акторов в C++, один раз послушал фрагмент DevZen с участием Григория Демченко и пара выпусков про Лондон и стартапы. Хотя ссылки, которые там накидывают в комментариях стараюсь просматривать, бо временами встречается интересное.

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

Намедни в DevZen заглянул некто Егор Бугаенко. Я хз кто это такой и чем он знаменит. Но что-то последние пару лет это имя слишком часто всплывает в этих наших Интернетах, дай, думаю, послушаю, приобщусь. Выкроил часок, послушал. Получил некоторое впечатление, которое имеет две или даже три составляющие:

пятница, 19 мая 2017 г.

[business] Где можно посмотреть примеры текстов коммерческих лицензий на ПО?

Обращаюсь за помощью к своим читателям. Мы думаем некоторые свои разработки распространять под двойной лицензией, т.е. GNU GPL или GNU Affero GPL для использования в OpenSource-проектах + коммерческая лицензия для использования в закрытых проектах. Как раз сейчас работаем над текстом этой самой коммерческой лицензии.

У нас есть несколько текстов коммерческих лицензий от производителей ПО, которые сами продают свое ПО под двойной лицензией. Но это слишком маленькая выборка. Хотелось бы больше.

Посему просьба к читателям блога, у которых случайно завалялся текст какой-нибудь коммерческой лицензии к какому-нибудь OpenSource-софту: могли бы вы поделиться текстом (вычеркнув оттуда всю конфиденциальную информацию, естественно)? Или ссылочкой на подобные тексты в Интернете?

Может быть кто-то может подсказать координаты юристов или юридических компаний в РБ, у которых есть опыт подготовки такого рода лицензий? Именно в РБ.

Связаться со мной можно по мылу eao197 на stiffstream тчк com или eao197 на gmail com.

четверг, 18 мая 2017 г.

[prog] Почему-то сильно не хочется делать CMake основным build-tool-ом

Под влиянием вот этого доклада с C++ CoreHard Spring 2017 решил попробовать еще раз посмотреть в сторону CMake как основного своего build-tool-а. Сам CMake, как по мне, говном был, говном и остался. Но, поскольку люди всерьез интересуются такими построенными поверх CMake вещами, как Conan.io и Hunter, то может пришло время зажать нос и научиться обмазываться CMake-ом?

В чем у меня специфика? В том, что под Windows у меня сейчас, например, десять(!) вполне себе актуальных версий GCC под x64: 4.8, 4.9, 5.1, 5.2, 5.3, 5.4, 6.1, 6.2, 6.3 и 7.1. Плюс к тому три версии Visual Studio (каждая из которых как в x86, так и в x64). Плюс две версии clang (3.9 и 4.0).

Под каждую версию компилятора у меня есть свой bat-файл, в котором настраиваются все пути и все окружение. И для каждого батничка свой ярлык на рабочем столе. Нужен мне, скажем, gcc-4.8, я кликаю на ярлык, попадаю в нужную среду, захожу в нужный мне каталог, запускаю ruby build.rb или ruby some/project/prj.rb. И все.

среда, 17 мая 2017 г.

[prog.thoughts] По мотивам одного из докладов с C++ CoreHard Spring 2017

На прошедшей на днях конференции C++ CoreHard Spring C++ был один весьма неоднозначный доклад. Это доклад Василия Вяжевича "Модульность и управляемая многопоточность встраиваемых С++ приложений — трудности, проблемы, решения". Доклад, пожалуй, самый слабый из всех докладов этой конференции. Тем не менее, если тема многопоточности в C++ интересна всерьез, то с докладом ознакомиться имеет смысл (если смотреть на youtube, то имеет смысл увеличить скорость до 1.25 или даже до 1.5, иначе слушать будет совсем грустно).

У меня впечатления от доклада, хоть и неоднозначные, но в большей степени негативные.

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

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

Во-первых, многопоточность выбирается для реализации приложения не просто так. По крайнем мере, если мы говорим об опытных разработчиках, которые понимают, что делают, а не хватаются за std::thread просто потому, что только что прочитали об этом в документации. Как я уже неоднократно говорил, многопоточность используется либо для нужд parallel computing, либо для нужд concurrent computing. И в обоих случаях мы получаем сильно разную клиническую картину:

  • в случае parallel computing количество рабочих потоков у нас будет ограничиваться количеством вычислительных ядер. При этом мы заинтересованы в том, чтобы какой-либо обмен данными между рабочими потоками был сведен к самому минимуму. В идеале, рабочие потоки должно работать над совершенно независимыми и непересекающимися наборами данных. Поэтому отладка таких многопоточных приложений не так сложна, как это может показаться. Ведь каждая нить представляет из себя, по сути, небольшой самостоятельный однопоточный процесс, который очень мало взаимодействует с внешним миром. Следовательно, нас мало волнуют ситуации, когда параллельный поток убежал куда-то вперед или немного подотстал. Но самое главное другое: если у нас задача сократить общее время расчета (а для этого и нужен parallel computing), то мы можем использовать либо многопоточность, либо многопроцессность. И для одного, и для другого есть свои показания и протовопоказания. Но смысл в том, что для parallel computing в каких-то условиях выбор в пользу многопоточности будет единственно верным. И это не зависит о того, нравится ли нам многопоточность и умеем ли мы отлаживать многопоточный код;
  • в случае concurrent computing количество рабочих потоков ограничивается лишь степенью нашей распущенности :) Параллельные потоки в concurrent computing мы используем либо для того, чтобы снизить степень влияния одной независимой задачи на другую независимую задачу (например, запись в файл не должна блокировать запрос к БД), либо для того, чтобы упростить реализацию какой-то независимой задачи. Так, какую-то последовательность действий нам может быть проще записать в виде простой последовательности синхронных вызовов, чем делать то же самое посредством конечного-автомата с размазыванием логики между отдельными callback-ами. Проблем с многопоточностью в случае concurrent computing гораздо больше, поскольку:
    • нашим задачам, как правило, придется оперировать над какими-то общими разделяемыми данными. Соответственно, если это мутабельные данные, то у нас начинается головная боль по защите разделяемых мутабельных данных и по обеспечению их консистентности;
    • поскольку часть наших задач будет так или иначе зависеть друг от друга и взаимодействовать друг с другом, то нам важна будет синхронизация по времени в каких-то узловых точках. Т.е. если мы делаем задачу A, а параллельно выполняется задача B, результат которой когда-то потребуется в задаче A, то для нас может быть важно, чтобы задача B не затормозила и была выполнена до того момента, когда внутри A мы обратимся к результатам B.
    И вот все это в совокупности и приводит к тому, что отладка многопоточных приложений превращается в сплошной геморрой. Ведь нам приходится иметь дело и с разделяемыми мутабельными данными, которые могут поменяться в любой момент извне. И с "времянкой", когда параллельно выполняющиеся потоки либо сильно притормаживают, либо уходят далеко вперед.

Так вот проблема доклада Василия Вяжевича в том, что он не обозначил явным образом то, что речь будет идти только о специфике задач concurrent computing. И что представляемое слушателям решение возможно потому, что у задач из категории concurrent computing есть интересное свойство: зачастую им вообще не нужен параллелизм, можно обойтись квазипараллелизмом. Как раз то, что было в ранних версиях Windows 3.*, работавших в реальном режиме процессора.

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

  • использованием какого-то из вариантов объекта с коллбэками. Т.е. есть объект, у которого некий фреймворк дергает тот или иной коллбэк. И работа фреймворка не может продолжиться, пока объект не вернет управление назад. По этому принципу работают самые распространенные акторные фрейворки для C++ (QP/C++, CAF, SObjectizer) и не только для C++ (например, Akka);
  • использование сопрограмм, которые фреймворк может приостанавливать и возобновлять. Например, когда из сопрограммы дергается какой-то вызов самого фреймворка и фреймворк получает возможность заморозить текущую сопрограмму и разморозить какую-то другую сопрограмму. По этому принципу работают, например, Boost.Fiber и Synca для C++.

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

Во-вторых, то, что показывал Василий Вяжевич в своем докладе, на мой взгляд, является отличной иллюстрацией того, о чем я говорил в конце своего доклада "Шишки, набитые за 15 лет использования акторов в C++":

...реализовать в своем фреймворке какую-то идею и показать ее работоспособность — это не так уж и сложно. Можно потратить несколько месяцев труда и получить вполне себе работающий и интересный инструмент. Это все делается на чистом энтузиазме. Буквально: понравилась идея, захотел и сделал.
А вот оснащение того, что получилось, всякими вспомогательными средствами, вроде сбора статистики или трассировки сообщений — это уже скучная рутина, на которую не так то и просто найти время и желание.

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

У вас есть проблема. Вы думаете над ее решением и вам в голову приходит отличная мысль:
-- Да тут же можно использовать регулярные выражения!
Все. Теперь у вас есть две проблемы.

Вот так и с самодельными фреймворками для диспетчеризации задач. Вначале они решают ваши проблемы. Потом сами становятся вашими проблемами. Так что если вы сталкиваетесь с ситуацией, когда для concurrent computing вам нужно множество объектов-тасков с коллбэками, а так же какой-то диспетчер для них, посмотрите сперва по сторонам. Возможно, инструменты вроде QP/C++, CAF, SObjectizer или даже Intel TBB уже содержат то, что вам нужно. Уверяю, посмотреть по сторонам будет быстрее и дешевле, чем налабать на коленке что-то за пару дней, а потом саппортить это на протяжении нескольких лет, а то и дольше.

Кроме того, хоть я и сам без пиетета отношусь к формальному делению на какие-то модели, вроде Actor Model, CSP или что-то еще, но. Не могу не отметить, что когда признаки той или иной модели легко проявляются в некоем фреймворке, то гораздо проще понять, на что способен фреймворк и как этот фреймворк использовать. Так, если мне говорят про Actor Model, то это одни подходы к использованию. Если про CSP-шные каналы, то другие.

У Василия Вяжевича же получилась какая-то гремучая смесь, в которой таски (они же "модели" в его понимании) похожи одновременно и на акторов и на какое-то отдаленное подобие гороутин. А порты -- это что-то среднее между CSP-шным каналом и почтовым ящиком. Т.е. при желании разобраться можно будет. Но т.к. грани сильно размыты, то нужно будет приложить некоторые усилия для того, чтобы понять, как этим пользоваться.


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

понедельник, 15 мая 2017 г.

[prog.c++] SObjectizer 5.5.19.1

Как оказалось, в коде SO-5 уже давным-давно жило несколько лишних точек с запятой, которые вызывали ошибку компиляции в gcc при совместном использовании ключей -Wpedantic и -Werror. Дабы устранить эту проблему мы сделали тег 5.5.19.1, в которой эти точки с запятой удалены. Код версии 5.5.19.1 собирается gcc и clang с ключами -Wpedantic и -Werror. Для gcc 6.* и 7.* может потребоваться добавить ключ -Wno-unused-function, иначе в одном из мест у gcc сносит крышу и он ругается на то, на что ругаться не должен.

Взять 5.5.19.1 можно либо из svn, либо с github-а, либо в виде архива с SourceForge.

На SourceForge ахив бинарников для Windows с версией 5.5.19.1 не делал, т.к. у Visual C++ подобных проблем не наблюдалось вообще. Но если кому-то нужно, то дайте знать, сделаем.

воскресенье, 14 мая 2017 г.

[life.photo] Эх, давно я не брал в руки шашек... Или краткие впечатления от съемки на зеркалку

Вчера подвернулся случай взять в руки и поснимать на большую чОрную зеркалку с большим чОрным и тяжелым объективом :) Спустя какое-то невероятно долгое время. Могу ошибаться, но думается, что последний раз я фотографировал что-то более-менее серьезное на цифрозеркалку около года назад, на "Дне красного носа 2016". А по сути, последние полтора года снимаю только на беззеркальную камеру Fujifilm x30. И кратковременное возвращение с беззеркалки на зеркалку -- это интересный опыт.

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

Качество картинки, которое выдает более-менее современный ФФ-сенсор и возможность беспрепятственно снимать на ISO выше 1000 после x30 -- это какой-то космос. Сложно передать насколько это все важно для репортажа, когда ты не контролируешь освещение и должен лупить кадры как пулемет, чтобы затем получился приличный фотоотчет из нескольких десятков хороших кадров (выбраковка при этом достигает более 90%, а времени на тщательную обработку оставшихся кадров нет).

Долгое время жизни аккумулятора. Более 500 отснятых кадров, просмотр их после съемки прямо на камере, сама камера постоянно включена более 5 часов подряд... И исчезла только одна рисочка из пяти на индикаторе заряда.

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

Так что есть ощущение, что ТОПовая репортажная беззеркалка, появись такая на рынке, может в разы облегчить работу репортажного фотографа.


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

corehard_spring_2017_two_portraits

В очередной раз подумалось о том, что жил бы я в более крупном городе, хотя бы размером с Минск, можно было бы рискнуть и сделать что-то вроде "Студии негламурного портрета". Где целью съемки было бы не получение парадно-выходного или гламурно-отфотошопленного портрета, а попытка передачи характера или эмоции портретируемого. Что-то вроде "характерного портрета в профессиональном интерьере". Понятное дело, что это мало кому нужно. Но в большом городе это хотя бы можно было бы вывести в ноль. Т.е. рассматривать в качестве хобби, но не разорительного хобби. В маленьком же городе это вообще никому не понадобиться, как мне представляется.

пятница, 12 мая 2017 г.

[fury] Ну и еще за RSDN

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

1. Очень удивлен тому, что на RSDN меня еще помнят. Тем не менее, я вне RSDN-а уже гораздо дольше, чем был на RSDN-е. Пора бы уже перестать говорить про значимость или какой-то там вклад в RSDN персонажа под ником eao197.

2. Что-то не меняется. Например, пара свежих высказываний от AndrewVK. Номер раз:

Он, кстати, емнип, в итоге признал что был не прав.

И номер два:

Вот только даже мне приходилось регулярно отправлять его в бан за оскорбления.

RSDN-у всегда не хватало того, чтобы люди, обличенные там властью, следили за своими словами. Ибо, по поводу инцидента 2009-го года, когда я высказал VladD2 все что думаю не оглядываясь на рамки приличий, я признал свою неправоту лишь в том, что не оглядывался на эти самые рамки. Но высказать то, что высказал, нужно было.

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

3. Почему-то я вижу, что о судьбе RSDN-а беспокоятся те, кого я уважаю как профессионалов и как людей (например, kochetkov.vladimir и kaa.python). Но не те, кто приложил усилия к закапыванию RSDN-а. Т.е. то, что Володя и Александр переживают за RSDN меня совсем не удивляет. Удивляет, почему переживают только они.

4. Есть ощущение, что RSDN похож на обычное предприятие, попавшее в обычный кризис: внешние условия поменялись, выпускаемая предприятием продукция продается все хуже и хуже, а перестроиться и приспособиться к новым условиям не получается.

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

Конечно, не мне советовать, что делать ресурсу в данной ситуации. Но, если рассматривать случай с RSDN-ом с точки зрения обычной ситуации с обычным жизненным циклом обычного предприятия (как это было, скажем, с Крайслером в 80-х перед приходом туда Ли Яккока, как было с Эппл после ухода оттуда Стива Джобса, как было с LEGO в начале 2000-х), то думается, что кому-то нужно всерьез озадачиться поисками ответов на пару-тройку важных вопросов:

  1. Зачем и для чего ресурс существует?
  2. В чем уникальность ресурса? Т.е. почему в современных условиях пользователи должны предпочитать RSDN альтернативным площадкам?
  3. На чем нужно сконцентрироваться для изменения ситуации, а от чего нужно избавиться?

Жизненный и профессиональный опыт подсказывает, что ответы на эти вопросы не ищутся коллективными усилиями. Тут важна роль личности. Лидера, который сможет сформировать видение и убедить всех остальных в правильности этого самого видения.

Есть ли такой лидер в команде RSDN?

А вот это мне уже совсем не интересно. Выживет RSDN -- ну и хорошо, будет больше профильных ресурсов в Рунете. Не выживет, ну бывает, такова жизнь.

четверг, 11 мая 2017 г.

[prog] Послесловие к релизу SObjectizer-5.5.19

Сегодня мы сделали релиз очередной версии SObjectizer-а. Основной анонс здесь, небольшие пояснения по поводу столь длительной паузы между версиями здесь. Так же сделаны анонсы на reddit-е и hacker-news (кто может поспособствовать +1, не сочтите за труд), не говоря уже про LOR и RSDN. Еще запланирована статья на Habr-е, но это уже не сегодня.

Здесь же мне хочется сказать о двух вещах.

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

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

Ну и еще один маленький ;) повод сбегать в магазин: SObjectizer-у в этом году исполняется 15 лет. Если мне не изменяет склероз, то основные работы над кодом SObjectizer-4.0.0 закончились в конце апреля 2002-го. А в мае 2002 на SObjectizer-4 я уже начал делать что-то для продакшена. Такой вот небольшой юбилей.

[fury] Про RSDN и аккаунт so5team

Тут на RSDN.ru начали выяснять, является ли аккаунт so5team реинкарнацией аккаунта eao197. Вынужден сказать по этому поводу следующее.

Аккаунт so5team был создан специально для контекстного маркетинга SObjectizer-а.

Написанное из под so5team, имеет целью принести пользу, прямую или косвенную, проекту SObjectizer и стоящей за ним команде.

Поэтому, следует рассматривать персонаж so5team только лишь как одного из команды разработчиков SObjectizer-а. Не важно какого именно. Upd. Из под so5team на RSDN пишет не один человек.

Если бы eao197 хотел высказывать свое мнение на RSDN, то он бы делал это как eao197. Точно так же, как он продолжает делать это на LOR-е, Habr-е, FB и других ресурсах.

суббота, 6 мая 2017 г.

[book.business] Интересная книга "Что не убило компанию LEGO, а сделало ее сильнее. Кирпичик за кирпичиком"

Закончил читать интересную книгу Билла Брина и Дэвида Робертсона "Что не убило компанию LEGO, а сделало ее сильнее. Кирпичик за кирпичиком". Книга о том, как компания LEGO достигла своего расцвета в середине 1990-х, затем затеяла целую волну инноваций, чуть не вылетела в трубу в начале 2000-х, но смогла перестроиться и пережить кризис.

Книга интересная, но читается достаточно тяжело. Мне с трудом дались первые страниц семьдесят. Ибо авторы выбрали достаточно специфический подход к изложению материала. Сначала они описали проблемы, с которыми LEGO столкнулась во второй половине 1990-х. Затем описали шаги для преодоления этих проблем, предпринятые руководством компании и перечислили достоинства и преимущества этих самых шагов. И вот тут у меня зачастую возникало ощущение, похоже на "что за фигня?", ибо здравый смысл подсказывал, что ничего хорошего не должно было произойти... А авторы пишут про положительные результаты... Не было понятно, то ли я идиот (что весьма вероятно), то ли авторы врут (во что не верилось), то ли нужно было набраться терпения и посмотреть, что будет дальше.

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

По ходу чтения неоднократно возникало ощущение, что описываемое в книге очень сильно перекликается с тем, о чем говорится в замечательной книге "Живая компания". В частности, мне показалось, что предпринятые LEGO шаги по выходу из катастрофического пике в 2003-2004 годах, полностью соответствуют, как минимум, трем принципам, описанным Ари де Гиусом:

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

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

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

пятница, 5 мая 2017 г.

[prog.humour] Ну реально: "Why do all this RAII or GC shit, if you just can manage your runtime as a round robin?"

По наводке из G+ ленты Meeting C++ вышел на интересное на reddit-е:

Here is something that was described to me as a real production configuration that was done to solve memory leaking everywhere.

It was a Java service taking fairly high amount of traffic. In order to get consistent response times they setup this configuration in each machine:

1) Each machine runs 4 JVMs. 2) 1 JVM that is starting up 3) 1 JVM that is shutting down 4) 2 JVMs that are serving traffic. 5) Every 2 minutes a JVM starts/stops. 6) No JVM lives for more than 8 minutes.

I found that to be both horrifying and a rather clever way to work around the problem.

Т.е. рассказывают по некую систему на Java, которая должна была обрабатывать изрядный поток трафика. И для того, чтобы не бороться с утечками памяти люди просто сделали так, что у них одновременно работает четыре JVM: одна стартует, вторая завершается, две другие нормально работают и обслуживают трафик. Каждые 2 минуты одну из работающих JVM заглушают, а на ее место запускают новую JVM. В итоге ни одна из JVM не работает дольше 8 минут.

Был бы я лет на 10 помоложе, наверняка бы постебался на тему криворуких программистов в частности и атрофии головного мозга, которую вызывает использование Java вообще. Но количество набитых шишек все-таки дает о себе знать. Поэтому сейчас мне кажется, что это отличное инженерное решение. Ну что поделать, shit happens. А если можно построить железобетонное решение, которое работает не смотря на этот самый shit, то это просто здорово.

В связи с чем вспоминается две похожие истории.

Первая связана с патерном Disruptor, о котором много говорили в узких кругах несколько лет назад. Помнится, компания Lmax, которая Disruptor и описала, рассказывала, что у них JVM, внутри которой массированная обработка событий посредством патерна Disruptor и крутилась, просто-напросто раз в сутки перезапускалась. На сутки RAM для этой JVM хватало, а потом следовал простой "освежающий рестарт" и следовали очередные сутки работы нагруженного приложения.

Вторая история связана с одним из написанных на C++ проектов в компании Интервэйл. Там был родительский процесс диспетчер и N дочерних процессов. Каждый дочерний процесс выполнял запросы к удаленному серверу по HTTPS. Но время от времени, иногда после нескольких часов, иногда после нескольких дней непрерывной работы какой-нибудь из дочерних процессов тупо повисал. Непонятно почему. Просто зависал и все. Естественно, это обнаруживалось и процесс прибивался, но т.к. запрос не был выполнен, то это сказывалось на пользователе, чей запрос не обрабатывался. И хотя таких сбойных запросов оказывалось всего ничего, какие-то тысячные доли процента, но все равно неприятно.

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

PS. Пока писал, вспомнил еще одну историю. Совсем древнюю, относящуюся к временам, когда Ruby-On-Rails произвел эффект разорвавшейся бомбы. Помниться, читал какой-то блог пост, в котором автор описывал как они решали проблему обслуживания большого количества запросов в RoR-приложении. Способ был примитивный: на сервере запускалось несколько десятков серверов lighttpd и отдельный балансировщик разруливал нагрузку между ними. Но важно то, что RoR вместе с lighttpd не всегда работали устойчиво и иногда падали. Поэтому у них на серверах работал по крону специальный скрипт, который опрашивал инстансы lighttpd и, если обнаруживал отсутствие оного, то просто рестартовал упавший инстанс заново. Самая мякотка была в том, что рестарты происходили с темпом где-то раз в минуту. Т.е. раз в минуту какой-то инстанс RoR-приложения и lighttpd просто переставал работать. Ну, по крайней мере, я так запомнил :)

четверг, 4 мая 2017 г.

[prog.tale] Сегодняшнее. Hа тему "ну как жопой чувствовал..."

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

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

В общем, с одной стороны, повезло. С другой -- интуиция не подвела, что не может не радовать :)

вторник, 2 мая 2017 г.

[prog.c++] Пример асинхронного однопоточного http-сервера на базе so-5.5, restinio и asio

Подготовка к релизу SO-5.5.19 вышла на финишную прямую. Есть надежда, что за неделю завершим подготовку документации и сопроводительных материалов, и после майских праздников выкатим официальный релиз. Пока же попробую на примитивном примере показать две основные фичи версии 5.5.19: способность SObjectizer-а работать только на одной рабочей нити и распространение мутабельных сообщений. Более того, в этом примере будет использоваться такой вариант SObjectizer Environment, который использует asio-шный event-loop в качестве бэк-энда. Подробнее обо всем этом ниже в посте.

Пример представляет из себя примитивнейший http-сервер, который при выполнении запроса к URL '/' генерирует простенькую html-страничку. Но генерирует с задержкой, которая постепенно увеличивается. При этом, не смотря на то, что обработка отдельного http-запроса "тормозит", http-сервер спокойно занимается приемом и обработкой параллельных запросов.

В качестве http-сервера используется наш restinio, который мы как раз и создавали для того, чтобы иметь возможность легко и непринужденно делать асинхронную обработку http-запросов. Так, благодаря архитектуре restinio мы имеем возможность делегировать обработку запроса SObjectizer-овскому агенту (хотя сам restinio к SObjectizer вообще не привязан и может использоваться отдельно). В примере задействована находящаяся в активной разработке версия restinio-0.2. В публичный ее репозиторий актуальные изменения мы пока еще не влили, вероятно сделаем это ближе к дате релиза SO-5.5.19.

Основная фишка данного примера в том, что в нем все работает на одной общей нити: и asio, и restinio, и SObjectizer. Т.е. SObjectizer не создает никакой дополнительной инфраструктуры, для диспетчеризации событий агентов и таймеров используется asio и евоный event-loop.

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

Итак, сначала подключаем необходимые заголовочные файлы:

воскресенье, 30 апреля 2017 г.

[life.cinema] Очередной кинообзор (2017/04)

Незаметно пролетел целый месяц и подошло время очередного кинообзора. В начале идут те фильмы, которые понравились больше. Затем те, что понравились меньше. Плюс отдельно несколько слов по фильму "Волынь", который нельзя включать в какую-то из категорий, он сам по себе.

Время первых (2017). К сожалению, не шедевр. Но очень хороший фильм.

Собачья жизнь (A Dog's Purpose, 2017). Милый, прямолинейный и сентиментальный фильм для семейного просмотра.

Грешники и праведники (Outlaws and Angels, 2016). Весьма суровый и атмосферный фильм. Жалко только, что несколько нудноват.

Человек с тысячью лиц (El hombre de las mil caras, 2016). Немного скучновато, но такое европейское кино лично мне нравится. Поэтому я посмотрел с удовольствием.

Сплит (Split, 2016). Если бы я в начале понимал, что это чистой воды фэнтези, то впечатление было бы другим. А так начинал смотреть как нормальный триллер, поэтому ближе к концу пришлось воскликнуть "ну чё за фигня?!!" Правда, разочарование чуть-чуть было компенсировано эпизодическим появлением Брюса Уиллиса в самом конце с отсылкой к "Неуязвимому" от 2000-го года. В общем, смотреть нужно как фантастику или фэнтези, в которой возможно все.

Призрак в доспехах (Ghost in the Shell, 2017). Перед просмотром этого фильма посмотрел оригинальным мультфильм от 1995-го года. Не могу сказать, что мне сильно понравилось что-то из этого. Как по мне, первые 3/4 нового фильма гораздо лучше старого мультфильма. Просто из-за более крутой визуальной составляющей. Но развязка в новом фильме -- это просто полный отстой.

Бессоная ночь (Sleepless, 2017). Вроде бы и актеров подтянули, и событий наворотили, но получилась какая-то невразумительная муть.

Ценный груз (Precious Cargo, 2016). Незамысловатое, чисто развлекательное кино.


Волынь (Wolyn, 2016). Фильм, в котором нельзя выделить какую-то выдающуюся актерскую игру или работу оператора, или какие-то тонкие сюжетные ходы, или еще что-то художественное. Тем не менее, сочетание очень простой и прямой формы подачи материала с звериной жестокостью происходящего на экране производит очень сильное впечатление. Не берусь сравнивать с советским "Иди и смотри", ибо смотрел последний ну очень давно и духу пересмотреть все равно не хватит. Но по силе воздействия на зрителя они должны быть сравнимы.

суббота, 29 апреля 2017 г.

[prog.memories] Немало времени требуется, чтобы использование фич языка вошло в привычку

C++11 вышел уже очень давно, скоро появится C++17 и C++11 начнет терять свою актуальность. Тем не менее, есть несколько фич C++11, к повседневному использованию которых лично я пока еще не пришел. В первую очередь это касается final и noexcept, а так же, отчасти, constexpr.

В этой связи мне вспоминается, как году эдак в 1993-ем или 1994-ом заставлял себя использовать const-ы для определения типов параметров функций/методов. Ведь начинали мы в 1991-ом с обычного C, который даже C89, наверное, не был. Основным инструментом был Turbo C 2.0 выпуска 1988-го года. Поэтому писать в стиле int mystrlen(const char *) тогда было не принято. Тем не менее, со временем сумел выработать у себя привычку использовать const для обозначения неизменяемых аргументов-указателей и аргументов-ссылок. Что в последствии неоднократно помогало.

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

Потом, когда компиляторы начали более-менее поддерживать C++98, пытался приобщиться к спецификации исключений в C++98. Ну это которая через throw(A,B,C) делалась. Тут, правда, не шибко хорошо пошло. Ибо быстро выяснилось, что в C++ важно просто знать, бросаются ли исключения вообще, а вот от их точного перечня пользы не было. Скорее даже один вред. Поэтому где-то еще, наверное, живет старый код, в котором используется throw(). Но писать в таком стиле в привычку не вошло.

А вот с C++11 получилось любопытно. Какие-то вещи, вроде лямбд, rvalue references и variadic templates практически сразу же начали использоваться. Что называется легко и непринужденно. Тогда как final, noexcept и constexpr оставались где-то в стороне. В первую очередь потому, что приходилось оглядываться на VC++, в котором с noexcept и constexpr до недавнего времени было совсем плохо. Да и вообще C++11 по сравнению с C++98 очень сильно изменился, поэтому потребовалось приличное время, чтобы в голове все это уложилось.

Тем не менее, потихоньку ловлю себя на том, что уже задумываюсь, а будет ли класс/структура расширяться в будущем? Может стоит ее сразу пометить как final? Или может ли метод в принципе бросать исключения? А если не может, то почему же я не обозначаю его как noexcept. Ну и т.д. Потихоньку, но процесс идет. Глядишь, к выходу C++20 совсем уже хорошо освоюсь с фичами C++11 и, может быть, даже с фичами C++14 :)

четверг, 27 апреля 2017 г.

[business.book] Еще одна любопытная книга про бизнес: Михаил Шейтельман "Не такой как Тиньков"

На минувших выходных (у нас в РБ их было аж четыре подряд), прочитал еще одну книгу по бизнесу, которая, на мой взгляд, заслуживает внимания. Это небольшая книжица "Не такой как Тиньков" за авторством Михаила Шейтельмана.

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

Хотя некоторое неоднозначное впечатление все-таки остается: есть ощущение, что достижения автора оказались возможны, во-первых, в областях, связанных с оказанием услуг. И, во-вторых, в областях, в которых не требуется высокая квалификация и не требуется длительное время на получение этой самой квалификации. Все-таки создать рекламное агенство или же построить небольшое русскоязычное Интернет СМИ в Латвии -- это совсем не то, что стать глазным хирургом или главным инженером на заводе по производству прокатных станов. Так что к описанным в книге рекомендациям нужно относиться с изрядной долей скептицизма, если вы не собираетесь продавать самодельные праздничные открытки с оригинальным дизайном, а думаете открыть частную хирургическую клинику или создаете высокотехнологичное промышленное производство.

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

среда, 26 апреля 2017 г.

[prog.thoughts] Вероятно, наступило время языков, на которых можно "просто педалить код"...

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

Тем не менее, есть ощущение, что такие языки, как JavaScript и Go (в особенности Go), становятся все более и более востребованными в нашей индустрии... Ну, если и не восстребованными, то одними из самых обсуждаемых. Хочется разобраться, почему так происходит и, если получится, понять, чем это грозит и, может быть, придумать, как этим можно воспользоваться.

Итак, вот есть язык Go. Который, на первый взгляд, выглядит очень простым и практичным. Я бы, правда, сказал, что он примитивный и убогий, ну да я старый маразматик, мои слова все равно ничего не изменят ;) Вот только на второй взгляд, выясняется, что в Go так же есть приличное количество своих косяков и неоднозначностей. Так что мифы о простоте Go, наверное, несколько преувеличены. Тем не менее, большое количество людей Go пользуется, пользуется с удовольствием и, что удивительно, не особо хочет чего-то другого.

Недавно у меня возникло ощущение, что я таки окончательно понял, почему именно так.

воскресенье, 23 апреля 2017 г.

[business.book] Прочел книгу "Инкубатор Twitter. Подлинная история денег, власти, дружбы и предательства"

Вчера за полдня буквально проглотил книгу Ника Болтона "Инкубатор Twitter. Подлинная история денег, власти, дружбы и предательства". Ну просто отличное чтиво! :)

Увлекательный и легко написанный производственный роман на тему борьбы пауков в банке истории появления и развития до 2012-го года компании Twitter. Начинаешь читать и не можешь оторваться.

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

Мне показалось, что одного персонажа в книге вывели ну уж очень чернушным. Типа он весь в дерьме, а остальные Д'Артаньяны. На самом деле, полагаю, хороши были все, но не все смогли приложить столько же усилий к выживанию. Да и вообще, надо думать, в реальности все было еще веселее, но пока Twitter еще жив и шаволится, глубже вряд ли кто-то будет копать.

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

среда, 19 апреля 2017 г.

[soft.business] Как и где удобнее всего продавать коммерческие лицензии на ПО?

У нас начинает маячить на горизонте момент, когда можно будет начинать продавать коммерческие лицензии на разработанные нами C++ные библиотеки. Соответственно, возник вопрос как и где это лучше всего делать. Пока представляется, что есть два основных варианта:

1. Со своего сайта, но через платежных агрегаторов, вроде Ассиста или Робокассы. В принципе, так поступают хостеры, когда продают виртуалки физическим лицам.

2. Через специализированные интернет-магазины по продаже программного обеспечения (вроде allsoft.ru).

Если кто-то проходил через выбор инструмента для продажи собственного ПО, то может поделитесь опытом или подскажете, на что имеет смысл смотреть в первую очередь? Или вот такой момент: есть ли какие-то подводные камни для белорусского юридического лица при продаже ПО через иностранный интернет-магазин?

В общем, буду признателен за любую помощь.

вторник, 18 апреля 2017 г.

[life.books] Пару слов о [не]прочитанных за последнее время книгах

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

Первой была книга Игоря Манна "Маркетинг на 100%". Я подписан на рассылку издательства "Манн, Иванов и Фербер", в которой время от времени (сейчас уже гораздо реже, чем вначале) проскакивают описания книг, вызывающие желание прочитать что-нибудь. Как раз через рассылку и пришла ссылка на очередное переиздание "Маркетинга на 100%". Клюнул на большое количество хороших отзывов, плюс к тому была большая потребность для самого себя разобраться в том, что же такое маркетинг, какова его роль, чем маркетинг отличается от рекламы, когда в маркетинг нужно вкладываться очень серьезно, чего ждать от маркетинга и т.д.

Прочел около 3/4 книги, потом сдался. Книга, может быть, хорошая. Но предназначена для тех, кто профессионально занимается маркетингом или собирается этим профессионально заниматься. Если же вы начинающий бизнесмен-производственник и хотите разобраться в том, что такое маркетинг и какую пользу маркетинг должен приносить вашему бизнесу, то ответов на свои вопросы в книге не найдете. Скорее даже вопросов у вас станет больше. По крайней мере я так и не понял, что же это за зверь такой :(

Второй книгой стала "К черту всё! Берись и делай! Полная версия" Ричарда Брэнсона. Уж не помню, что именно толкнуло меня на ее покупку. Но одним из главных факторов были хорошие воспоминания об очень интересной книге "Теряя невинность" того же Брэнсона, которую я с большим интересом и удовольствием прочитал лет 15 назад. Кстати, если кто-то не читал "Теряя невинность", то очень зря. Действительно интересно.

А вот с "К черту всё!..." у меня не пошло. Половину осилил, может даже больше, а потом сдался. Как по мне, такую книгу хорошо читать в 17 лет. Или в 25. Ну, может быть, в 30. Но когда тебе за сорок и ты уже несколько раз всерьез переосмысливал то, чего ты хотел, что получил, к чему стремился и к чему пришел, куда и как хочешь идти, на что ты ради этого готов, чем ты можешь рискнуть, от чего ты не можешь оказаться и т.д, и т.п., то пользы от жизнеописания и рассуждений на разные темы от какого-то чувака до которого тебе, по большому счету, нет никакого дела... В общем, не ощущал я никакой пользы от чтения "К черту всё!..." Заканчиваешь главу, задумываешься о том, а что же в сухом остатке? И обнаруживаешь, что запомнил всего какой-то один фактик о том, как Бренсон в очередной раз чудом спасся в каком-то очередном своем приключении. В общем, быстро понял, что мне жалко времени, которое я трачу на чтение этой книги. Еще какое-то время я заставлял себя читать дальше в надежде, что должно же что-то такое быть, чтобы "Бах!" и "О, вот оно, ради этого и читал, это и заставит взглянуть на жизнь и мир вокруг немного иначе". Но не нашел ничего подобного. В итоге сказал сам себе "Ну и к черту её! Займись тем, что тебе больше нравится. Прямо сейчас" ;)

Третья книга -- это "Как работает Google" от Эрика Шмидта, Алана Игла и Джонатана Розенберга. Прочитал совсем чуть-чуть. Показалось, что написано интересно. Но не для меня нынешнего. То, что описывает Эрик Шмидт про Google актуально для тех, кто работает и руководит коллективами в больших компаниях. Т.е. для меня это могло бы быть полезным во время работы в Интервэйле, особенно когда под моим началом было 100 человек. Но сейчас, когда мы втроем пытаемся запустить свой маленький свечной заводик (ключевое слово маленький), читать о принципах организации работы в Google -- это изучать вещи, которые тебе гарантированно не понадобятся в течении ближайших 5 лет даже при самом благоприятном стечении обстоятельств. В итоге, отложил "Как работает Google" до лучших времен. Но, думаю, что тем, кто работает в больших продуктовых компаниях, вроде Yandex-а, Лаборатории Касперского, Wargaming-а или даже Сбертеха ;), может быть и интересно, и полезно. Прошу заметить, аутсорсеров, вроде ЕПАМа или Luxsoft-а я в этот список не включил, у гребцов на галерах свои проблемы, а у их надсмотрщиков -- свои :)))

Четвертой книгой оказалась "The Everything Store. Джефф Безос и эра Amazon" за авторством Бреда Стоуна. Вот ее я дочитал до конца.

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

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

Возможно я ошибаюсь, и Джефф Безос держал весь Амазон жесткой рукой за яйца, как это делал Стив Джобс в Apple, но вот у меня после прочтения книги такого ощущения не возникло. Т.е. там было такое количество действующих лиц, такая движуха, такое почти броуновское движение, что роль Безоса там воспринимается просто как направляющая. Ну вот есть у Амазон вот такой лидер. Ну и есть. Как мне показалось, вклад команды юристов, которые выискивали лазейки в законодательстве США, позволявшие Амазону не платить налоги, которые приходилось платить офлайновым ритейлерам, в общий успех Амазона был отнюдь не меньше идей самого Безоса.

Вот что действительно стало откровением и заставило посмотреть на какие-то вещи в жизни совсем по-другому, так это тот факт, что Амазон в течении, как минимум, семи лет был просто убыточным предприятием. Т.е. компания привлекала сотни миллионов сторонних инвестиций, вышла на IPO и получила еще огромные средства от продажи акций, но при этом несла огромные убытки. При этом сам Безос уже в это время стал вполне себе обеспеченным человеком, покупающим дома за 10 миллионов долларов и летающем на частном самолете. При этом главной политикой компании была экономия на всем, включая и сотрудников, к которым относились как к говну в прямом смысле слова (кто не верит, пусть прочитает про экономию на системах кондиционирования на распределительных узлах Амазона). Т.е. владелец убыточной на продолжении многих лет компании, в которой зажимают деньги даже на то, чтобы обеспечить нормальные условия работы своих сотрудников, по ходу дела становится миллионером... Очевидно, что до прочтения "The Everything Store. Джефф Безос и эра Amazon" я ничего не понимал в бизнесе.

Ну и кстати про сотрудников Amazon и про условия работы там. Очевидно, что грызня "пауков в банке" была еще та. Сильно напомнило Интервэйл времен 2013-2014 годов. Еще раз довелось убедиться в том, что говно не тонет эффективный менеджмент есть везде. У нас его, наверное, еще не так много, как в развитых странах :)

В общем, книга не простая, читается с трудом, но местами весьма полезная. Тем не менее, я бы рекомендовал ее тем, кому интересно заниматься именно "куплей-продажей". Ведь Amazon, не смотря на всю свою технологичность, -- это компания, основной бизнес которой в том, чтобы здесь купить, а там продать. И все крутится именно вокруг этого. Если же вы ищите себя в производстве или в конструкторской деятельности, то для вас объем полезной информации будет гораздо меньше. Еще книгу можно порекомендовать как раз тем, кто видит себя на поприще "эффективных" менеджеров, которым пофигу, чем управлять -- системой распределения товаров на складе или же компанией по выводу на европейский рынок новой линейки интимных смазок. Научиться хамскому поведению по отношению к подчиненным и к раздаче пинков "нерадивым" сотрудникам вполне получится. Только запомните, пожалуйста, в мире еще встречаются люди вроде меня, которые воспринимают повышение голоса на подчиненных и ругань в их адрес как проявление непрофессионализма (каких бы успехов при этом не добился тот же самый Безос). И когда вы кому-то скажете что-то вроде "вы и правда настолько тупы, чтобы прийти ко мне с такими дурацкими предложениями", то будьте готовы услышать в ответ что-то вроде "Если я настолько туп, то как у вас хватило ума нанять меня на работу?" :)

понедельник, 17 апреля 2017 г.

[prog.c++] Шаблоны против копипасты 6: просто шаблоны и просто перегрузка функций

Очередная часть серии "шаблоны против копипасты", которая, как обычно, получилась в результате рефакторинга имевшегося и работавшего кода (предыдущая часть серии здесь). Правда, в этом случае я буду показывать не реальный код, ибо тогда пост получится перегруженными никому не интересными деталями. А уже максимально упрощенная и сокращенная версия. Но все равно получилось довольно объемно, поэтому все фрагменты кода упрятаны под кат.

Итак, суть в том, что было несколько семейств функций send, send_delayed и send_periodic. В каждом семействе была одна "как бы главная" функция, получавшая самый общий набор аргументов. А все остальные функции были всего лишь обертками вокруг главной функции, но обертками, заточенными под определенный тип получателя. Обертки эти нужны были для того, чтобы сделать код, использующий send-ы, единообразным. Чтобы отсылка сообщения в какой-то конкретный mbox синтаксически не отличалась от отсылки сообщения в какой-то mchain. Ибо такое синтаксическое однообразие очень и очень сильно упрощает написание шаблонного кода.

В общем, за несколько лет развития данные семейства функций приобрели, схематично, следующий вид:

четверг, 13 апреля 2017 г.

[prog.c++] А кому-нибудь нужна поддержка MSVS2013 (aka VC++12) в SObjectizer?

Вопрос более чем серьезный. При работе над новой версией SO-5.5.19 приходится много работать с шаблонами и проблемы с уровнем поддержки С++11 в MSVS2013 стали уже совсем комом в горле.

Если MSVS2013 никому не нужен, то мы бы могли ограничиться только MSVS2015 и MSVS2017.

Ну а если MSVS2013 нужен, то будем искать, как выкручиваться из ситуации...

вторник, 11 апреля 2017 г.

[prog.flame] C++ никто не заменит! C++ незаменим! :)

Ибо в каком еще языке можно выражать свои мысли столь витиевато и велеречиво?

templatetypename T >
struct message_payload_type
   :  public message_payload_type_impl< T,
         is_classical_message<
               typename ::so_5::details::message_mutability_traits<T>::payload_type >::value >
   {
   };

Ну и да, шаблоны в C++ -- это чистой воды программирование на динамически-типизированном языке: пока unit-тестами все не покроешь, не можешь быть уверен в правильности работы :)

понедельник, 10 апреля 2017 г.

[prog.thoughts] Очередная итерация вокруг movable/modifiable сообщений. Нужно сделать непростой выбор из двух(?) вариантов...

Тема movable/modifiable сообщений для SObjectizer-а, поднятая некоторое время назад, и, казалось бы, начавшая уже самостоятельно дышать, по мере своего развития стала получать серьезные удары. Один из них был обозначен вчера. Сегодня случился еще один. Посему есть желание еще раз подумать о том, а не следует ли что-нибудь подправить в консерватории?

Итак, был попробован подход, в котором создавались пары похожих, но несовместимых между собой сущностей: mbox_t и unique_mbox_t, mchain_t и unique_mchain_t.

Основное достоинство этого подхода в том, что в compile-time контролируется невозможность отсылки shared-сообщения в unique_mbox/mchain. Это очень сильное преимущество в сравнении с другими вариантами, поэтому именно с этого подхода и началась попытка реализации movable/modifiable сообщений в SO-5.5.19. Однако, чем дальше, тем больше шансов, что это достоинство будет нивелировано необходимостью иметь дело с разными типами mbox-ов и mchain-ов. Т.е. там, где раньше разработчик просто использовал mbox_t, сейчас ему придется заботиться и о mbox_t, и о unique_mbox_t. Например, если раньше могло быть что-то вроде:

template<typename MSG, typename... ARGS>
void make_and_send_to(
   const mbox_t & dest,
   const some_common_arg_type & common_arg,
   ARGS && ...args)
{
   so_5::send<MSG>(to, common_arg, std::forward<ARGS>(args)...);
}
...
if(has_free_workers)
   make_and_send_to<handle_request>(processor, request);
else if(can_be_delayed(request))
   make_and_send_to<delay_request>(wait_queue, request, delaying_options);
else
   make_and_send_to<reject_request>(rejector, request, no_free_workers, unable_to_delay, default_error_code);

То сейчас dest придется передавать шаблонным параметром. Т.е. делать что-то вроде:

template<typename MSG, typename MBOX_HANDLE, typename... ARGS>
void make_and_send_to(
   const MBOX_HANDLE & dest,
   const some_common_arg_type & common_arg,
   ARGS && ...args)
{
   so_5::send<MSG>(to, common_arg, std::forward<ARGS>(args)...);
}
...

К сожалению, в таком виде в качестве первого параметра для make_and_send_to можно будет передать вообще все, что угодно. Даже int. И получить затем портянку ошибок с отсутствием должного варианта so_5::send().

Но если в случае с mbox_t/unique_mbox_t деление на shared- и unique-mbox еще оправдано наличием как взаимодействия 1:N, так и 1:1, то вот для mchain-ов разделение на обычный (т.е. shared-) и unique-mchain уже достаточно сложно объяснить. Поскольку главная причина такого деления возникает из-за необходимости сохранять совместимость с предшествующими версиями SO-5, а отнюдь не из-за требований какой-то общепризнанной теоретической модели.

Поэтому я все больше и больше склоняюсь к тому, чтобы текущее направление развития movable/modifiable сообщений признать тупиковым. И сделать вариант, который основан на маркере unique_msg при отсылке и при получении сообщения.

Так, для того, чтобы отослать unique-сообщение единственному получателю потребуется сделать вызов so_5::send<so_5::unique_msg<M>>(dest, args...). А для получения сообщения нужно будет использовать so_5::mhood_t<so_5::unique_msg<M>>. Для обычных агентов это может выглядеть, например, так:

class demo final : public so_5::agent_t {
public :
   demo(context_t ctx) : so_5::agent_t(std::move(ctx)) {
      so_subscribe_self()
         // Подписываем агента на иммутабельное сообщение типа K.
         .event([this](const K & cmd) {...})
         // Подписываем агента на иммутабельное сообщение типа L.
         .event([this](mhood_t<L> cmd) {...})
         // Подписываем агента на мутабельное сообщение типа M.
         .event([this](mhood_t<unique_msg<M>> cmd) {...});
   }

   virtual void so_evt_start() override {
      // При старте отсылаем самому себе сообщения K, L и M.
      // Сообщения K и L идут как иммутабельные.
      so_5::send<K>(*this, ...);
      so_5::send<L>(*this, ...);
      // Сообщение M идет как мутабельное.
      so_5::send<unique_msg<M>>(*this, ...);
   }
};

При этом можно обратить внимание на то, что и иммутабельные, и мутабельное сообщение отсылается в один и тот же direct-mbox агента-получателя. В первом подходе, который уже частично реализован, это невозможно. Там нужно для агента создавать отдельный unique_mbox, подписывать обработчик события на этот unique_mbox и сообщение отсылать не в обычный direct_mbox, а в отдельный unique_mbox.

Для mchain-ов может выглядеть так:

auto ch = create_mchain(env);

// Отсылаем три сообщения.
// Сообщения K и L идут как иммутабельные.
so_5::send<K>(ch, ...);
so_5::send<L>(ch, ...);
// Сообщение M идет как мутабельное.
so_5::send<so_5::unique_msg<M>>(ch, ...);

// Обрабатываем все сообщения из канала.
receive(from(ch),
   // Обработчик для иммутабельного K.
   [](const K & cmd) {...},
   // Обработчик для иммутабельного L.
   [](so_5::mhood_t<L> cmd) {...},
   // Обработчик для мутабельного M.
   [](so_5::mhood_t<so_5::unique_msg<M>> cmd) {...});

В общем, как мне думается, все достаточно наглядно и видно, где отсылается unique-сообщение и где ожидается именно unique-сообщение.

Однако, вот что в таком подходе не нравится:

  • нет проверок в compile-time. Т.е. если пользователь сделает send<unique_msg<M>> в multi-producer/multi-consumer mbox, то получит исключение в run-time, а не ошибку во время компиляции.
  • в один и тот же mbox можно отослать и иммутабельное, и мутабельное сообщение типа M, и эти экземпляры попадут в разные обработчики:

    so_5::send<M>(ch, ...);
    so_5::send<so_5::unique_msg<M>>(ch, ...);
    receive(from(ch),
       [](so_5::mhood_t<M>) { std::cout << "immutable M" << std::endl; },
       [](so_5::mhood_t<so_5::unique_msg<M>>) { std::cout << "mutable M" << std::endl; });

    И такая возможность лично мне представляется нормальной. Но вот что может приводить к путанице и ошибкам, так это вот такие вещи:

    // Отсылаем как иммутабельное сообщение.
    so_5::send<M>(ch, ...);
    ...
    receive(from(ch),
       // А получить пытаемся как мутабельное.
       [](so_5::mhood_t<so_5::unique_msg<M>>) {...});

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

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

Ранее я так же думал, что у этого подхода есть еще недостаток, связанный с тем, что различия между иммутабельными и мутабельными сообщениями могут мешать писать обобщенный код, вроде показанной выше шаблонной функции make_and_send_to. Однако, затем подумалось, что если ввести шаблон immutable_msg<M> то с его помощью можно сделать вызовы send<M> и send<immutable_msg<M>> синонимами. Что позволит писать обобщенный код вот в таком виде:

template<typename MSG, typename... ARGS>
void make_and_send_to(
   const mbox_t & dest,
   const some_common_arg_type & common_arg,
   ARGS && ...args)
{
   so_5::send<MSG>(to, common_arg, std::forward<ARGS>(args)...);
}
...
if(has_free_workers)
   make_and_send_to<unique_msg<handle_request>>(processor, request);
else if(can_be_delayed(request))
   make_and_send_to<unique_msg<delay_request>>(wait_queue, request, delaying_options);
else
   make_and_send_to<immutable_msg<reject_request>>(rejector, request, no_free_workers, unable_to_delay, default_error_code);

Так что возможность писать обобщенный код, которому без разницы, отсылает ли он иммутабельные или unique-сообщения, сохраняется.

Итак, сейчас стоит дилемма: продолжать ли непростой путь в сторону mbox/unique_mbox+mchain/unique_mchain или же нужно начать все сначала и двинуться в сторону send<unique_msg<M>>? Если у кого-то есть соображения, то прошу высказываться. Реальная возможность повлиять на вектор развития SObjectizer-а :)

PS. По ходу написания текста поста сам себя поймал на том, что лучше оперировать понятиями immutable_msg и mutable_msg, нежели понятиями shared- и unique-сообщения. Так что если второй подход получит право на жизнь, то будет использоваться нотация send<mutable_msg<M>>.

UPD. Еще один большой минус наличия mbox/unique_mbox и mchain/unique_mchain, это усложнение жизни тех пользователей, которые делают собственные реализации mbox-ов и mchain-ов. Например, собственная реализация mbox-а может понадобиться для балансировки нагрузки: пользователь может написать свой mbox, который будет адресовать очередное сообщение тому агенту, который меньше загружен. Соответственно, при появлении деления на mbox/unique_mbox такие трюки будет проделывать сложнее.

воскресенье, 9 апреля 2017 г.

[prog] На тему сложности проектирования: внезапная проблема в попытке подружить unique-сообщения и message chains

Продолжение темы добавления в SO-5 такой штуки, как unique-сообщения. Unique-сообщение -- это сообщение, которое:

  • идет строго одному получателю (т.е. используется исключительно при взаимодействии 1:1);
  • дает получателю право менять экземпляр сообщения как ему вздумается (это нужно для ситуаций, когда сообщение большое и его нужно править "по месту", либо же когда в сообщении перемещаются move-only данные, которые из сообщения нужно забрать, например, в сообщении передается экземпляр типа File или unique_ptr).

Для того, чтобы unique-сообщения можно было отсылать агентам, в SO-5.5.19 добавляется новый тип почтового ящика -- unique_mbox. Только при подписке на unique_mbox можно повесить обработчик для unique-сообщения. Таким образом еще в компайл-тайм обеспечивается гарантия того, что нельзя взять shared-сообщение из обычного mbox-а, изменить это сообщение и отправить измененный экземпляр другому агенту.

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

Мне показалось разумным, что периодическое сообщение не может быть unique-сообщением. Поскольку:

  • получатель сообщения не является единоличным владельцем указателя на экземпляр сообщения. Еще один указатель есть у таймера. Соответственно, может получиться ситуация, когда получатель в момент времени T обрабатывает экземпляр периодического сообщения M (которое ему было отослано таймером некоторое время назад, но долго простояло в очереди), а в этот же момент таймер ставит в очередь получателя этот же самый экземпляр сообщения еще раз. Получится, что получаетль будет править объект, который находится у него в очереди. Что, может и не страшно, но как-то странно, по меньшей мере;
  • получатель сообщения не имеет препятствий к тому, чтобы переслать этот экземпляр unique-сообщения кому-то другому. Но, в этом случае сообщение в прямом смысле перестает быть unique-сообщением, т.к. оно в буквально начинает адресоваться сразу двум получателям. Первый -- это исходный получатель, которому периодическую доставку сообщения осуществляет таймер. Второй -- это тот, кому первый получатель переадресовал сообщение.

Поэтому на уровне API в SO-5.5.19 отсылка периодических сообщений в unique_mbox сейчас просто запрещена. И это правильно, как мне думается.

Теперь пришло время подружить unique-сообщения с message chains (mchains в терминологии SO-5). Mchains -- это реализация концепции каналов из модели CSP. При этом сообщения из mchain-ов всегда доставляются только одному получателю, этим mchain-ы принципиально отличаются от multi-producer/multi-consumer mbox-ов.

Казалось бы, раз mchain -- это всегда multi-producer/single-consumer канал, то нет смысла создавать дихотомию shared_mchain (или обычный mchain) и unique_mchain. Можно просто разрешить пользователю отсылать и получать unique-сообщения в обычный mchain. Т.е. можно просто выполнить send<Msg>(mchain,params) и получить этот Msg через unique_mhood_t<Msg> (т.е. получить сообщение как unique-сообщение).

Однако, здесь встречаются грабли, связанные с периодическими сообщениями. Сейчас можно отослать периодическое сообщение в mchain. Но, если любое сообщение из mchain можно получить через unique_mhood_t (т.е. как unique-сообщение), то значит и периодическое сообщение так же может быть извлечено как unique-сообщение. Что не есть хорошо (см. две вышеобозначенные причины).

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

Но тогда возникает вполне резонный вопрос: а как объяснять пользователю, зачем нужны mchain и unique_mchain, если по сути это одно и то же? И есть подозрение, что объяснить будет не так-то просто. А раз так, то пользователю будет сложнее использовать SO-5, а это не есть хорошо.


Возможно, подходить к проблеме unique-сообщений нужно было по-другому. Сейчас описанные выше сложности возникают из-за того, что исходная отсылка shared-сообщения и unique-сообщения ничем не отличается. Соответственно, когда в очередь агента или в буфер mchain-а стал объект типа Msg, то при вызове обработчика этого сообщения есть только объект Msg, но нет информации о том, отсылался ли этот объект как shared-сообщение или как unique-сообщение. Отсюда и возникающие сложности.

Можно было бы пойти другим путем. Например, заставить пользователя для отсылки unique-сообщений использовать специальную шаблонную обертку, вроде unique_msg<Msg>. Соответственно, не потребовалось бы делить mbox-ы на обычные mbox-ы и unique_mbox-ы. Не пришлось бы думать над тем, нужно ли делить mchain-ы на обычные mchain-ы и unique_mchain-ы. Запрет отсылки периодических unique-сообщений решался бы не по типу получателя (mbox/unique_mbox или mchain/unique_mchain), а по типу сообщения -- если отсылается unique_msg<Msg>, значит запрет.

Однако, такой подход так же имеет свои слабые стороны:

  • попытку отослать unique-сообщение в multi-producer/multi-consumer mbox можно было бы обнаружить только в run-time. А ошибка в run-time гораздо хуже, чем ошибка в compile-time;
  • усложнилось бы написание шаблонного кода. Допустим, сейчас можно написать шаблонную функцию make_and_send_msg, которая будет конструировать какое-то прикладное сообщение и отсылать его в указанный канал или mbox. При наличии шаблона-обертки unique_msg<Msg> мы уже не сможем просто так использовать эту функцию для отсылки как shared-, так и unique-сообщений.

Поэтому-то сейчас и был использован подход на базе дихотомии mbox/unique_mbox, mchain/unique_mchain.


Для чего был написан этот пост? Прежде всего для того, чтобы проверить, правильно ли я сам для себя понимаю возникшую проблему. Если бы я ее недостаточно понимал, то связного текста просто бы не получилось.

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

пятница, 7 апреля 2017 г.

[prog.c++] Тема movable/modifiable сообщений в SObjectizer задышала

В конце февраля, после C++ Russia 2017, возникла тема добавления в SObjectizer поддержки не константных экземпляров сообщений. Суть в том, что в SObjectizer из-за первоначальной направленности на взаимодействие в режиме 1:N, все сообщения доставлялись получателям в виде константных объектов. Получатель имел константную ссылку на пришедшее к нему сообщение и не должен был менять этот объект, т.к. в это же время то же самое сообщение мог обрабатывать еще кто-то.

Для некоторых сценариев это оказалось не очень хорошо. Например, если цепочка агентов выстраивается в конвейер, по которому движется большой объект, а каждый из агентов должен что-то в этом объекте поменять и передать измененный объект дальше. Или когда один агент должен передать "тяжелый" объект другому агенту, но использовать shared_ptr для этих целей не выгодно.

В итоге мы начали думать, как дать возможность пересылать не константные объекты-сообщения при взаимодействии агентов в режиме 1:1. Сначала идеи крутились вокруг movable-сообщений, т.е. сообщений, содержимое которых можно перемещать между экземплярами (например, когда кто-то делает send, то содержимое сообщение сразу же конструируется где-то в заранее созданном буфере у агента-получателя). Но затем была выбрана, как мне представляется, более простая идея: мы применили к сообщениям тот же подход, который в C++ используется для динамически-созданных объектов и unique_ptr. Класс unique_ptr говорит разработчику, что есть только один "владеющий" указатель на объект. Нельзя расплодить unique_ptr, можно лишь передавать право владения так, что только один unique_ptr будет владеть динамически созданным объектом.

Мы добавили в SObjectizer такое понятие, как unique_mbox. Т.е. специальный тип mbox-а, отсылка сообщения в который приводит к передаче не константного объекта-сообщения. Для того, чтобы получить не константное сообщение из unique_mbox-а, обработчик сообщения должен использовать специальный новый тип unique_mhood_t<Msg>. Это тонкая шаблонная обертка, похожая на уже существующий mhood_t, но она позволяет модифицировать полученный объект-сообщение. Так же unique_mhood_t позволяет переслать не константное сообщение дальше.

Вот небольшой кусок реального unit-теста из SObjectizer, который проверяет работу этого механизма. Там агент отправляет самому себе сообщение типа std::string. Получив сообщение, агент меняет текст сообщения и перепосылает измененный объект. При этом проверяется то, что повторно приходит именно тот же самый std::string, но с другим содержимым.