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

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

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

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

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

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

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

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

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

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

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

суббота, 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, но с другим содержимым.

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

[prog.c++] Альфа-версия RESTinio, инструмента для реализации REST API на C++

Мы долго смотрели по сторонам на то, что есть в C++ для разработки HTTP-сервисов и REST-сервисов в частности. И решили все-таки попробовать сделать что-то свое. Попробовали. Сегодня выкатываем в мир первую альфа-версию небольшого, header-only, кросс-платформенного инструмента под названием RESTinio. Его главная задача -- упростить асинхронную обработку запросов. Чтобы, грубо говоря, обработчик спокойно мог потратить 15 секунд на формирование ответа, но это бы не влияло на параллельные запросы.

В основе лежит Asio и http_parser из NodeJS. SObjectizer для работы RESTinio не нужен. Но обработка запросов легко может делегироваться из RESTinio в SObjectizer. Пример того, как это делается можно найти в репозитории.

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

Ну и это еще одно подтверждение того, что мы уже несколько раз говорили на конференциях в статьях: мы больше смотрим в сторону того, чтобы дать возможность агентам общаться с внешним миром посредством де-факто стандартных протоколов, вроде HTTP ;) При этом планов привязать RESTinio намертво к SObjectizer-у у нас нет. Тут все просто: из SObjectizer должно быть удобно пользоваться RESTinio, но самому RESTinio SObjectizer для работы не нужен.

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

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

[prog.c++] Аннотированный код нового примера для SObjectizer-5.5.19

Вот уже пару месяцев идет активная работа над новой версией SObjectizer -- 5.5.19. Одна из основных фич этой версии уже вполне себе заработала. Речь про возможность запустить SObjectizer Environment в однопоточном режиме. Кратко поясню, в чем суть.

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

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

Как раз для поддержки подобных случаев в SO-5.5.19 добавляется возможность создать такой SObjectizer Environment, который будет все свои действия выполнять на одной-единственной нити. Т.е. диспетчер по умолчанию, таймер и окончательная дерегистрация будут работать на той самой нити, на которой был произведен вызов so_5::launch().

Фича эта уже работает, но мы пока еще не проверили ее во всех сценариях, для которых она предназначалась. Поэтому пока не можем считать ее готовой к релизу. Но в процессе ее реализации в список примеров SObjectizer-а был добавлен еще один пример. Мне кажется, он достаточно интересен и демонстрирует использование многопоточности вообще без агентов. Только голые нити и CSP-шные каналы (называющиеся у нас mchain-ы). Ну и очередная разновидность ping-pong-а, только на этот раз с использованием таймеров. Пример, снабженный комментариями, под катом. Кому интересно, милости прошу посмотреть и высказать свое фи авторитетное мнение.

Напоследок скажу, что в скоуп версии 5.5.19 входит еще одна важная фича -- это moveable-сообщения, о которых речь заходила с месяц назад. Работы здесь еще очень много. Так что пока даже не рискну предположить предполагаемую дату релиза. Хорошо бы успеть к концу апреля, но загадывать не берусь. Жаль, что работы над 5.5.19 так затянулись, но однопоточный SObjectizer Environment -- это настолько переворачивающая все с ног на голову переделка SO-5, что торопиться ну очень не хочется.

Итак, сам код:

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

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

Подошло время очередного кинообзора. На этот раз в списке всего два нормальных фильма (и это,  к сожалению, отнюдь не первоапрельская шутка). Остальное просто шлак, на который можно не тратить свое время.
Невидимый гость (Contratiempo, 2016). Европейский криминальный фильм. Снятый в своей, очень отличающейся от голливудской, стилистике. Посмотрел с большим удовольствием.
Гуляй, Вася (2017). Вот просто на удивление неплохой фильм. Понравилось. Хотя, подозреваю, фильм сильно на любителя, и не могу утверждать, что он понравится еще кому-то.
Закон ночи (Live by Night, 2016). Очень тщательно сделанный фильм. Смотришь и получаешь визуальное наслаждение от того, как фильм снят и какая там картинка. Но вот все остальное довольно уныло и неинтересно, даже никому из героев фильма сопереживать не хочется.
Новогодний корпоратив (Office Christmas Party, 2016). После трейлера ожидал, что будет такой же треш и угар, как в "Мальчишнике в Вегасе". Но получилось весьма уныло и практически не смешно.
Видели ночь (All Nighter, 2017). Посмотрел из-за участия Дж.К.Симмонса в главных ролях. Но его одного не хватило, фильм получился довольно посредственным.
Логан (Logan, 2017). По отзывам критиков перед фильмом ждал чего-то другого. Оказалось, что как был фильм по комиксам, так он и остался. Трейлер для "Логана" оказался намного интереснее и суровее самого "Логана".
Конг: Остров черепа (Kong: Skull Island, 2017). Красочно. Но накал идиотии просто зашкаливает. Потраченного на фильм времени очень жалко.
Три икса: Мировое господство (xXx: Return of Xander Cage, 2017). Либо это кино для детей младшего школьного возраста, либо я так и не понял, что это, блин, такое было.
Живое (Life, 2017). Снято красиво, но муть редкая. Постоянно задаешь себе вопрос: что за херню нам показывают?
Обитель зла: Последняя глава (Resident Evil: The Final Chapter, 2017). Посмотрел только для того, чтобы увидеть, до какого маразма дошли создатели этой серии фильмов. Лучше бы не смотрел.

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

[prog.thoughts] Блеск и нищета C++

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

Серьезно, если кто-то еще не читал эту небольшую PDF-у, в которой показываются трюки вроде:

template <typename N, template <typename...> class... CRTPs>
class Number : public CRTPs<Number<N, CRTPs...>>... {
public:
   using S = decay_t<underlying_arithmetic_type_t<N>>;
   constexpr Number() // note: intentionally uninitialized
       {}
   constexpr Number(S value)
       : value_(value) {}
   constexpr S value() const
       { return value_; }
   constexpr void set_value(S a)
       { value_ = a; }
private:
   N value_;
};

template <typename T>
class Stream_i {
   friend std::ostream &operator <<(std::ostream &a, T b)
      { return a << b.value(); }
};

template <typename T>
class Shift_i {
   friend T operator <<(T a, T b)
      { return T(a.value() << b.value()); }
   friend T operator >>(T a, T b)
      { return T(a.value() >> b.value()); }
};

template <typename T>
class Eq_i {
   friend constexpr bool operator ==(T a, T b)
      { return a.value() == b.value(); }
   friend constexpr bool operator !=(T a, T b)
      { return a.value() != b.value(); }
};
...

using restricted_int = Number<int, Eq_i, Rel_i, Add_i, Stream_i>;
   // Supports only ==, !=, <, >, <=, >=, +, +=, <<(ostream).

то очень рекомендую. От нового взгляда на возможности современного C++ глаза распахиваются еще шире :)

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

И на этом фоне реальный топик с LOR-а, в котором человек приводит свой код и просит подсказать, в чем проблема.

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

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

[prog.c++] Библиотека timertt обновилась до версии 1.1.3

Вышла обновленная версия библиотеки timertt для работы с таймерами в C++ -- 1.1.3. В этой версии в публичный интерфейс timer_manager и timer_thread добавлена функция empty(), которая проверяет, пуст ли список таймеров или нет.

Признаюсь, это глупый косяк, который был допущен пару лет назад. В потрохах библиотеки empty() был реализован для всех timer_engine, но вот наружу я его тупо забыл вытащить (объект timer_engine инкапсулирован внутри timer_manager/timer_thread и просто так его методы недоступны).

Библиотека разрабатывалась для замены ACE в проекте SObjectizer, поэтому все, что связано с timertt, находится на SourceForge:

  • архивы с исходными текстами доступны в секции Files. Архив timertt-1.1.3-headeronly.7z содержит только основной заголовочный файл со всей функциональностью timertt. Архив timertt-1.1.3-full.7z содержит так же тесты, примеры и сгенерированный посредством Doxygen API Reference Manual;
  • основная документация для проекта собрана в Wiki;
  • исходники лежат в Subversion-репозитории на SourceForge. Релизные версии в tags/timertt, находящиеся в разработке версии в branches/timertt.

понедельник, 27 марта 2017 г.

[prog.flame] Rust-оманы зря пытаются продавать Rust С++никам, им бы поменять целевую аудиторию :)

Данный пост возник под впечатлением от двух недавних больших срачей на reddit-е на тему о том, почему Rust лучше C++: Have you used Rust? Do you prefer it over Modern C++? и Things I love about Rust while being a C++ programmer. А так же интересным ссылкам, которые проскочили в этих обсуждениях, например: вот (про некоторые проблемы Rust) или вот (специально для тех, кто верит, что безопасность Rust-а не имеет платы в run-time). Кроме шуток, срачи интересные, помимо обычного булшита (например, в очередной раз всплыл аргумент о том, как классно иметь возможность во время компиляции подключиться к СУБД, выкачать оттуда описание схемы данных и сгенерировать ORM) встречаются и прикольные примеры C++ граблей на ровном месте. Вот, скажем:

четверг, 23 марта 2017 г.

[prog] А кому нужны типизированные агенты?

В комментариях ко вчерашней статье на Habr-е очень активно обсуждается тема типизированных акторов. Мол, проблема акторов в том, что они "нетипизированны", ты отсылаешь актору сообщение A, но не знаешь, может ли этот актор обрабатывать сообщения типа A или же он ждет сообщения типа B. А вот если бы акторы были типизированными, то мы бы имели не просто actor_reference, а actor_reference<B> и во время компиляции бы получили по рукам за попытку отослать актору сообщение типа A.

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

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

Посему вопрос: а кому хотелось бы иметь акторов с типизированными интерфейсами в фреймворках вроде Akka, CAF, SObjectizer, QP/C++ и пр.?

Под катом маленький пример того, как это может выглядеть в SObjectizer...

среда, 22 марта 2017 г.

[prog.c++.fantasy] Дополнительные атрибуты implies и expects в дополнение к noexcept

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

Итак, сперва поговорим о том, почему мне хочется иметь что-то в дополнение к noexcept.

понедельник, 20 марта 2017 г.

[prog.thoughts] Не хватает мне в C++ noexcept-блоков с compile-time проверками

Написал давеча вот такой простой код на C++, с прицелом на обеспечение сильной гарантии exception safety:

void
stats_controller_t::turn_on()
   {
      std::lock_guard< std::mutex > lock{ m_lock };

      if( status_t::off == m_status )
         {
            const auto run_id = m_run_id + 1;

            send_next_message( very_small_timeout(), run_id );

// (1)
            m_status = status_t::on;
            m_run_id = run_id;
         }
   }

Тут в действиях до точки (1) может возникнуть исключение. Но это не страшно, т.к. никаких изменений в объект stats_controller_t внесено не было. А если мы нормально дошли до точки (1), то новое состояние объекта нужно зафиксировать. Что и происходит посредством двух простых операций присваивания.

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

void
stats_controller_t::turn_on()
   {
      std::lock_guard< std::mutex > lock{ m_lock };

      if( status_t::off == m_status )
         {
            const auto run_id = m_run_id + 1;

            send_next_message( very_small_timeout(), run_id );
// (1)
            noexcept
               {
                  m_status = status_t::on;
                  m_run_id = run_id;
               }
         }
   }

И чтобы компилятор дал бы мне по рукам, если бы в noexcept-блоке я бы написал какую-нибудь операцию, которая не помечена как noexcept. Зачем мне это нужно?

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

noexcept
   {
      m_status = status_t::on;
      store_status_change_timepoint();
      m_run_id = run_id;
   }

А это новое действие ба-бах! и начнет выбрасывать исключения. Тем самым послав изначальную сильную гарантию в /dev/null.

Но еще хуже то, что типы объектов могут меняться со временем. Так, сейчас у меня, допустим, m_run_id имеет тип int. А со временем он может быть заменен на какой-то "тяжелый" тип с бросающим исключения конструктором копирования. Т.е. внешне код в stats_controller_t::turn_on() остается таким же самым, но на практике сильная гарантия опять же отправится в /dev/null.

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


Интересно: только я задумывался на тему таких noexcept-блоков в C++? Или же это еще кому-нибудь интересно? Спрашиваю потому, что есть C++ RG21 и, в принципе, данную идею можно запулить туда. Если она хоть кому-нибудь представляется стоящей.

PS. Старый блог-пост на связанную тему. Тогда я еще не имел представления о том, что именно будет означать noexcept в С++.

воскресенье, 19 марта 2017 г.

[prog.thougts] В очередной раз о нотации (в применении к C++)

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

Дело в том, что в C++ нет общепринятого и стандартизированного соглашения о стиле оформления кода. На мой взгляд, это есть хорошо, но это мое личное мнение. Важнее то, что в C++ сообществе спокойно сосуществуют и активно используются совершенно разные стили именования. В STL и Boost-е, как мне кажется, традиционный C/C++ стиль. В Qt, wxWidgets и в POCO -- более привычный для Pascal/Delphi/VisualBasic/Java/C#. В библиотеке ACE вообще свой собственный, неповторимый стиль, заимствующий хорошие элементы как из snake_case, так и из CamelCase.

Мы же уже очень давно используем snake_case стиль, но с некоторыми очень важными дополнениями. В частности, у нас для имен типов используются суффикс _t. Например, у нас тип агента называется agent_t, а не agent. А тип сообщения называется message_t, а не message.

К суффиксу _t в мире C++, как мне думается, отношение довольно своеобразное. Давным-давно от суффикса _t стремились отказываться, т.к. это выглядело темным наследием plain old C. В C-шном коде суффикс _t давали, как правило, именам typedef-ов. Например, писали что-то вроде typedef struct my_type {...} my_type_t;.

Но в последние годы, после выхода C++11 и, особенно, после выхода C++14, суффикс _t в C++ опять возвращается, но уже в специфической роли. Например, начиная с C++14 в стандарт языка добавляются сокращенные определения, вроде enable_if_t<C,T> вместо enable_if<C,T>::type. Так что теперь в C++ для суффикса _t появляется вполне определенная нише. И использование данного суффикса для других целей способно запутать стороннего разработчика (разорвать шаблон, так сказать).

Чтобы быть "ближе к народу", мы у себя попробовали провести небольшой натурный эксперимент. И для одной своей новой разработки попробовали отказаться от _t в пользу традиционного для STL/Boost стиля именования сущностей.

Результат нам не понравился. И если при написании кода отсутствие суффикса _t хоть и мешает, но приспособиться можно, то вот при чтении кода имена типов без привычного уже суффикса _t крайне тяжело выделять из кода. Так что читать чужой код написанный в стиле STL/Boost значительно тяжелее, чем код в нашей привычной нотации. Посему эксперимент был признан неудачным, код мы вернули к старому оформлению. Причем решение вернуться назад мы приняли намного легче, чем решение провести этот самый эксперимент :)

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

PS. Если бы мне сейчас предстояло выбирать нотацию для C++ного кода, я бы взял уже привычную нотацию со snake_case, с использованием префиксов m_ для полей структур/классов и g_ для глобальных переменных. А вот для пространств имен и имен типов сделал бы небольшое изменение: первая буква в таких именах должна была бы быть заглавной. Получилось бы что-то вроде So_5::Impl::Simple_mtsafe_st_env_infrastructure_details::Actual_elapsed_timers_collector вместо текущего so_5::impl::simple_mtsafe_st_env_infrastructure_details::actual_elapsed_timers_collector_t (имена, кстати говоря, реальные).

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

[prog.c++] Библиотека timertt обновилась до версии 1.1.2

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

// Класс для управления таймерами в прикладной программе.
// Может работать с разными типами таймерных нитей или менеджеров.
templatetypename TIMER_CONTROLLER >
class timer_client {
   TIMER_CONTROLLER & controller_;

public :
   // Определяем тип идентификатора с учетом того, какой thread_safety
   // используется у менеджера таймеров.
   using timer_holder = timertt::timer_holder_object< typename TIMER_CONTROLLER::thread_safety >;

   // Создать новый таймер, при срабатывании которого нужно что-то выполнить.
   templatetypename DURATION, typename ACT >
   auto schedule_action( DURATION timeout, ACT && action ) {
      timer_holder id = controller_.allocate();
      controller_.activate( id, timeout, [act = std::move(action)] {
            act();
         } );
      return id;
   }

   // Отменить действие, которое было запланировано.
   void cancel_action( timer_holder id ) {
      controller_.deactivate( id );
   }
   ...
};

using mtsafe_wheel_manager = timertt::timer_wheel_manager< timertt::thread_safety::safe >;

timer_client< mtsafe_wheel_manager > client1(...);
auto id1 = client1.schedule_action( 250ms, []{ ... } );
...
client1.cancel_action( id1 );

using mtunsafe_wheel_manager = timertt::timer_wheel_manager< timertt::thread_safety::unsafe >;

timer_client< mtunsafe_wheel_manager > client2(...);
auto id2 = client2.schedule_action( 500ms, []{ ... } );
...
client2.cancel_action( id2 );

Без этого маленького дополнения класс timer_client пришлось бы делать зависящим от двух параметров шаблонов: от самого таймерного механизма и от признака thread_safety. Начиная с версии 1.1.2 достаточно всего одного шаблонного параметра.

Если вдруг кто-то не в курсе, что такое timertt, то в нескольких словах это:

Header-only библиотека без внешних зависимостей, базирующаяся на возможностях стандартной библиотеки C++11. Реализует таймеры на основе тайм-аутов, т.е. таймеры, которые должны сработать через сколько-то миллисекунд (секунд, минут и т.д.) после момента активации таймера. wallclock-таймеры не поддерживаются.

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

Библиотека поддерживает три таймерных механизма: timer_wheel, timer_heap и timer_list, у каждого из которых есть свои преимущества и недостатки. Может поддерживаться большое количество таймеров (десятки и сотни миллионов) и обеспечивается высокая скорость обработки таймеров (до нескольких миллионов в секунду).

Кросс-платформенная, проверялась посредством MSVS2013, 2015, 2017 (Windows), GCC 4.9-6.3 (Windows, Linux), Clang 3.5-3.9 (Linux, FreeBSD).

Распространяется под 3-х секционной BSD-лицензией, может свободно использоваться как в открытых, так и в закрытых коммерческих проектах.

Мы сделали timertt где-то 2.5 года назад, с тех пор она верой и правдой служит нам в SObjectizer-е. Последние правки вносились почти два года назад, когда вышла версия 1.1.1. За все время каких-то проблем с timertt не замечено.

Библиотека разрабатывалась для замены ACE в проекте SObjectizer, поэтому все, что связано с timertt, находится на SourceForge:

  • архивы с исходными текстами доступны в секции Files. Архив timertt-1.1.2-headeronly.7z содержит только основной заголовочный файл со всей функциональностью timertt. Архив timertt-1.1.2-full.7z содержит так же тесты, примеры и сгенерированный посредством Doxygen API Reference Manual;
  • основная документация для проекта собрана в Wiki;
  • исходники лежат в Subversion-репозитории на SourceForge. Релизные версии в tags/timertt, находящиеся в разработке версии в branches/timertt.

среда, 15 марта 2017 г.

[prog.flame] На тему тяжести выбора хороших имен идентификаторов

Как известно, одной из фундаментальнейших проблем в программировании является выбор хороших имен для индентификаторов в программе. Только что признать свое поражение в попытках решить эту проблему в одном частном случае и сделать сделать пространство имен с именем simple_mtsafe_st_env_infrastructure_details и класс с именем simple_mtsafe_st_env_infrastructure_t. Расшифровывается основная часть этого странный набор символов как simple multi-thread safe single-threaded environment infrastructure (т.е. простая реализация однопоточной инфраструктуры для окружения, в которой обеспечивается защита от многопоточного доступа).

Заодно этот пример показывает, почему после многих лет использования CamelCase я в итоге пришел к snake_case. Имхо, идентификатор SimpleMtSafeStEnvInfrastructureDetails был бы ну совсем уж зубодробительным неудобным (из категории прощай зрение).

воскресенье, 12 марта 2017 г.

[life.business] Впечатления от посещенного Startup-Forum-а

Вчера в Минске в EventSpace.by прошел Startup Forum, который мы посетили почти что полным составом своей небольшой компании. Впечатление своеобразные, попробую поделиться.

Прежде всего огромная благодарность организаторам: как всегда в EventSpace все было на отличном уровне.

Главное впечатление же от самого мероприятие таково: посетить нужно было обязательно. Но не столько ради того, чтобы научиться чему-то, сколько для того, чтобы в очередной раз вспомнить, что для успешного продвижения своего дела нужно быть предпринимателем, нужно думать как бизнесмен. Когда практически 95% времени ты связан с технологическим развитием своих продуктов об этом, к сожалению, забываешь. А тут был хороший повод вспомнить об этом.

Было два очень интересных выступления. Первое от Максима Каменкова, второе от Кирилла Волошина (того самого, одного из основателей tut.by). Выступление Кирилла Волошина, как мне показалось, было просто на голову выше всех остальных. Чувствуется просто колоссальный опыт выступления на публике, умение доносить свои мысли до слушателей, держать контакт с аудиторией и оперативно реагировать на реплики из зала.

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

Чего мне не хватило в выступлениях от опытных стартаперов, так это отдельного акцента на том, что для успеха нужна серьезная увлеченность своей идеей. Я бы даже сказал фанатичная увлеченность тем, что ты делаешь. Намеки на это звучали в ряде выступлений, но скорее под соусом того, что нельзя сдаваться, нужно находить в себе силы и желание продолжать. Однако, прямо не было сказано, что от основателя требуется готовность жить своим делом в режиме 24/7.

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

Мне представляется, что лет 30 назад (может раньше, может позже) на Западе пришло понимание, что для успешного выращивания стартапов нужно переходить к квадратно-гнездовому методу массовому их разведению. Полагаю, это было неизбежно. Вряд ли есть какие-то хорошие методы оценки перспективных новых начинаний для того, чтобы проводить хороший отсев жизнеспособных идей от нежизнеспособных. Чтобы из 100000 стартапов отобрать 100, из которых более-менее успешными окажутся 50. Проще и перспективнее дать возможность стартовать 50000 стартапов, из которых умрут 49000, оставшаяся 1000 выживет, а из этой тысячи штук сто окажутся очень успешными.

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

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

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

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

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

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

PS. Перед тем, как начать писать данную заметку, наткнулся на замечательную статейку в FB. Как по мне, так она просто из категории must read.

воскресенье, 5 марта 2017 г.

[life.book] Дочитал книгу "Стив Джобс. Уроки лидерства"

Дочитал книгу Уильяма Саймона и Джея Эллиота "Стив Джобс. Уроки лидерства". Интересно. Но я бы рекомендовал ее как дополнение к другой книге, "Стив Джобс" Уолтера Айзексона.

Книга Айзексона говорил о разных сторонах Джобса: и как о человеке, и как о бизнесмене. А вот книга Эллиота больше рассказывает о том, какие решения Джобс принимал и какие шаги предпринимал как предприниматель и как лидер и вдохновитель знаковых проектов компании Apple (а так же компаний Pixar и NeXT). В результате обе книги очень хорошо дополняют друг друга.

По-моему, я нашел хорошее описание того, чем же "брал" Джобс. Вот характерный фрагмент, который, имхо, отлично раскрывает самые сильные стороны Джобса. Речь идет о моменте истории Apple в середине 90-х, когда Apple искала для своих компьютеров новую операционную систему. В результате отбора осталось два претендента: NeXT от Стива Джобса и BeOS от Жана-Луи Гассе. И вот как описывается в книге финальное сражение между Джобсом и Гассе:

«Перестрелку в О.К. Коррал» назначили на 10 декабря 1996 года. Стива и Жана-Луи пригласили сделать презентацию своих продуктов на решающем совещании, которое должно было состояться в Пало-Альто, в отеле Garden Court (это место выбрали специально для того, чтобы сбить со следа журналистов).

Стив взял с собой своего гения операционных систем Ави Теваньяна. Столы в зале были расставлены буквой «П», и Стив вместе с Ави разместился в центре, а Джил и Эллен — в конце стола. Эксперт Apple по программному обеспечению Уэйн Мерецки сидел примерно посредине боковой линии столов. Он так описывает эту сцену: «Презентация Стива полностью сосредоточилась на Джиле, будто, кроме него, в зале никого не было. Стив, как и следовало ожидать, проявил абсолютное спокойствие, когда расхваливал преимущества своей операционной системы». Он изложил суть основных характеристик NeXTStep, делавших ее подходящей для Apple, а затем показал на ноутбуке, как эта операционная система может проигрывать два кинофильма одновременно… после чего запустил еще три фильма. Пять фильмов демонстрировались бок о бок на одном компьютере. Все присутствующие прекрасно поняли, насколько ценным для Apple было программное обеспечение, которое могло поддерживать такие вычислительные возможности.

Уэйн продолжает: «Стив использовал все возможные средства, и его презентация, которую он проводил при непосредственном участии Ави, в очередной раз подтвердила, что он по меньшей мере лучший торговый агент и лучший оратор в сфере технологий. Гассе пришел на эту встречу сам, без заранее подготовленного выступления, и только отвечал на вопросы». Он просчитался, полагая, что у Apple нет другого выбора, помимо операционной системы BeOS. Он не выдвинул никаких весомых аргументов, которые объясняли бы, почему BeOS и только BeOS необходима Apple.

Уэйн Мерецки сказал по этому поводу следующее: «Решение в пользу NeXT, а не Be Inc., стало очевидным».

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

Однако, книга "Стив Джобс. Уроки лидерства" оказалась для меня интересна не только поисками ответа на вопрос "чем же так велик Стив Джобс?" Она интересна еще и тем, что практически на всем ее протяжении Джей Эллиот, работавший рядом с Джобсом, рассказывает о решениях, которые принимались и претворялись в жизнь Джобсом. Это заставляет задумываться о том, а как бы ты сам поступал, на что ты готов пойти, что для тебя самое важное, ради чего ты сам занимаешься тем, чем занимаешься, хочешь ли ты этим заниматься и т.д., и т.п. В этом смысле мне даже показалось, что заключительная треть книги даже интереснее чем первые две трети.

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

[prog.flame] Вся сущность Хабра в одной ссылке

Интересная площадка, этот самый Хабр. Со временем лучше становится понятно, почему бывалые RSDN-еры и LOR-овцы отзываются о Хабре негативно. Квинтэссенцией на данный момент для меня стала вот эта статья на Хабре и ее обсуждение: "О чём молчат авторы «Hello, World!»-ов".

Сперва автор исходя из лучших побуждений, полагаю, написал откровенно слабую статью, без нормального введения, развития, кульминации и отчетливого вывода. Потом в комментариях начался треш и угар от публики, которая, очевидно, ни сном, ни духом о том, в каких условиях и как создавался язык Ada, и какую роль он играл в свое время в американском ВПК, да не только там, но и в разработке ПО для авионики во всем мире (может быть за исключением СССР и СНГ). Не удивлюсь, что все отметившиеся там комментарии (включая меня самого) и в кошмарном сне не смогут представить себе, что значит разработка ПО для проекта стоимостью в полмиллиадра долларов (вроде бы столько стоил взорвавшийся на старте Ариан 5, ПО для которого было написано как раз на Ada). Посему и вопросы в камментах из категории: а есть ли в Ada map/filter на лямбдах?

Тем, кто хоть чуть-чуть интересуется историей развития языков программирования очень рекомендую почитать про историю Ada. Ведь язык появился в результате попытки министерства обороны США упорядочить ситуацию с разработкой ПО для нужд армии. До появления Ada там царил хаос и анархия: каждый подрядчик использовал свои языки и технологии, никого не волновало, как именно будут сопрягаться разрозненные части одной и той же системы, созданные разными исполнителями в разных концах США. Создание Ada и ее насаждение в проектах для армии США, как по мне, сродни введению системы калибров и унификации артиллерийских систем в армиях самых продвинутых европейских стран в XVII-XVIII веков.

Язык Ada, действительно, является продуктом "разработки коммитетом", поэтому он выглядит достаточно страшно. Многословен, непрост в изучении, требует внимания при разработке. У современных хипстеров, эстетическое восприятие которых воспитано девайсами от Apple, может вызвать неудержимый рвотный рефлекс.

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

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

Ну, некоторые умельцы умудряются и на Java делать системы реального времени. Правда, превращая Java в какое-то убогое подобие недосишки/недоплюсов, выбрасывая GC и вручную колупаясь с байтами, не имея при этом нормальных средств для того же обобщенного программирования. Причем началось все это где-то лет через 20 после того, как Ada появился и начал успешно использоваться. Подозреваю, что на технике из середины 80-х годов, Java оказалась бы неприспособленной к массовому использованию чуть меньше, чем полностью.

А вот Ada, не смотря на "разработку коммитетом", оказался вполне себе успешным экспериментом по созданию языка для массовой промышленной разработке софта для систем с высокими требованиями к качеству, надежности и ресурсоемкости. Нужен ли этот язык сейчас? И если нужен где-то, то многими ли он будет востребован? Это уже совсем другие вопросы. Но подходить к оценке Ada с точки зрения наличия в нем лямбда-функций и алгоритмов map/filter... Ну это как рассматривать возможность использования карьерных самосвалов в гонках Formula-1. И это если оставаться в рамках цензурной лексики ;)

четверг, 2 марта 2017 г.

[life] Странные ощущения по ходу чтения книги "Стив Джобс. Уроки лидерства"

Читаю книгу Джея Эллиота "Стив Джобс. Уроки лидерства". Прочел уже одну треть. Не могу отделаться от нескольких очень странных ощущений.

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

Странность лично для меня здесь вот в чем: я не застал того переворота, который совершили Apple I, Apple II, Lisa и Macintosh. В середине 90-х Apple была сдувающейся компанией, со славным прошлым, унылым настоящим и непонятным будущим. А то, что стало появляться после возвращения Джобса в Apple (iMac, MacBook, iPod, iPhone, iPad) лично мне чем-то выдающимся не казалось. Уж не знаю почему. Может быть потому, что любые компьютерные устройства воспринимались и воспринимаются мной просто как инструменты. Ну в точности как молотки и стамески для столяра. Понятное дело, что какой-то молоток лежит в руке лучше, какой-то хуже. Какой-то удобнее, какой-то долговечнее. Но, в любом случае это расходный материал. И вряд ли кому-то придет в голову сравнивать молоток с произведением искусства, революционным прорывом и переворотом.

И вот когда не считаешь продукцию Apple чем-то выдающимся, то при чтении хвалебных од в адрес Джобса возникает невольное недоумение: а откуда весь пафос?

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

среда, 1 марта 2017 г.

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

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


Основатель (The Founder, 2016). Редко бывает, что фильм на какую-то профессиональную тему оказывается интересным и цепляющим. Этот оказался. Что мне особенно понравилось, так это показанные в фильме необходимые условия для создания успешного бизнеса: увлеченность на грани фанатизма, счастливое стечение обстоятельств (неоднократное) и люди, которые с тобой "на одной волне".


Врач (2016). Как по мне, так отличный российский фильм. Но очень грустный.


Пазманский дьявол (Bleed for This, 2016). На удивление добротный фильм на тему спорта вообще и бокса в частности. Но вряд ли будет интересен большинству зрителей. Отдельное спасибо авторам за то, что вместе с титрами пустили нарезку интервью с реальными героями этой истории.


Союзники (Allied, 2016). Ждал большего. Конечно же, актеры, съемки, даже сюжет, вроде как на высоте, а в целом не цепляет.


Другой мир: войны крови (Underworld: Blood Wars, 2016). Как обычно: если нравится Кейт Бекинсейл в облегающем латексе, то смотреть стоит. Если не нравится, то можно и пропустить. Хотя мне не понять, как это может не нравится ;)


Доктор Стрэндж (Doctor Strange, 2016). Очень красочно сделанное фэнтези для семейного просмотра. Правда, мне показалось, что Камбербэтч в этом фильме был более Шерлоком Холмсом, чем в финальном сезоне сериала "Шерлок".


Афера по-английски (Trespass Against Us, 2016). Просто удивительно, как так вышло: вроде как криминальный фильм, вроде как с хорошими актерами, вроде как все стараются, вроде как и диалоги в фильме нормальные. Но не цепляет. Остаешься равнодушным ко всем героям фильма.


Обитель зла: Последняя глава (Resident Evil: The Final Chapter, 2016). Смысла и сюжета, насколько я помню, в этой серии фильмов не стало очень и очень давно. Может быть даже самая первая часть не была в этом исключением. Смотреть очередные "Обители зла" можно было только ради сцен крутого мочилова и рубилова. В последней части лично мне этого самого мочилова и рубилова не хватило. Ну а смысла и сюжета, как и ожидалось, не было изначально.

Кредо убийцы (Assassin's Creed, 2016). Что-то непонятное. Все события, которые происходят в средневековье -- красочные и увлекательные. Эдакий боевик-рубилово с элементами средневекового паркура. Но зачем эти динамичные фрагменты было разбавлять унылой галиматьей, происходящей в наши дни, осталось загадкой.