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

О блоге

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

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

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

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

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

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

вторник, 3 декабря 2024 г.

[work] Формы рабочей коммуникации в удаленном формате: что, когда и для чего

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

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

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

Так что электронная почта отличный вариант, когда нужно обмениваться информацией объемом более 2-3 строк и нам не нужно получить ответ от собеседника в течении ближайших 5-10 минут.

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

При этом обсуждать какие-то более-менее объемные темы в мессенджерах, особенно в групповых чатах, как по мне, такое себе занятие. Мало кто умеет набирать текст быстро и более-менее грамотно, да еще соблюдая правила пунктуации. Поэтому получение 5-10, не говоря уже о 15-20 строчек от собеседника -- то еще удовольствие, тем более что в это время ты не можешь отвлечься на что-то другое, ведь от тебя же ждут быстрой реакции.

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

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

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

И вот когда приходит время вернуться к отложенному "на потом", то наличие следов первичных обсуждений в почте или Telegram очень сильно облегчает возвращение в контекст. Если же серьезное предварительное обсуждение велось в устном формате, то лично я через полгода уже точно ничего не вспомню. Могу даже забыть и про сам факт такого обсуждения :(

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

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

Тем не менее, живое общение голосом имеет пару-тройку критически важных преимуществ.

Во-первых, максимальная оперативность. Здесь и сейчас в прямом смысле этого слова.

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

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

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

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

В общем, резюмируя:

Почта -- когда много и не срочно.
Мессенджеры -- когда немного и оперативно.
Телефон и он-лайн созвоны -- когда срочно и/или нужно общение по-человечески.


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

Так что описанное выше -- это не отлитые в граните незыблемые правила, скорее просто выводы из моего личного опыта.

воскресенье, 1 декабря 2024 г.

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

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

Фильмы

Боец. Лучший из лучших (Life After Fighting, 2024). Кино для любителей единоборств. Сюжет и актерская игра практически отсутствуют, зато мордобой зачетный.

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

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

Хищные земли (Elevation, 2024). Простенько и предсказуемо, объяснение происходящего вообще для "малолетних дебилов" (с). Но снято красиво и чтобы скоротать вечер в отсутствии чего-то приличного (а приличного сейчас почти что и нет) вполне сойдет.

Дорога отчаяния (Desperation Road, 2023). Тому, кто обозначил этот фильм как триллер и боевик, нужно поотрывать все что можно. Это драма с некоторым элементом криминала. Драма довольно скучная и затянутая. Но здесь есть хотя бы вменяемый сюжет и нормальная игра актеров.

Кража (Stöld, 2024). Во-первых, это не триллер. От триллера там ничего нет, не ведитесь на описание. Во-вторых, это весьма скучно. Но картинка качественная, можно глянуть, если хочется посмотреть на жизнь саамов в Швеции.

Сериалы

Корни зла (Die Quellen des Bösen, первый сезон, 2023). Сильно двойственные чувства. С одной стороны, очень качественно снято, я вот прям получал удовольствие от картинки. Но, с другой, бездарный финал, который оставляет лишь вопрос "ну и что это все было?" В общем, смело можно не смотреть.

Трасса (первый сезон, 2024). Первые несколько серий было OK, авторы даже смогли сильно удивить. Но где-то с пятой серии все стало скатываться в какое-то унылое и сопливое говно. В итоге не понравилось, не рекомендую.

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

Триггер (третий сезон, 2024). Разочарован. Жаль потраченного времени. Если о первых двух сезонах у вас осталось хорошее впечатление, то лучше третий сезон не смотреть, чтобы это самое впечатление не испортить.

четверг, 28 ноября 2024 г.

[soft.dev.wtf] Мир сходит с ума... На примере маразма с "The Undefined Behaviour Question"

Просто зафиксирую эту историю здесь, т.к. мне она кажется показательной. Если кто не в курсе, то суть, как я ее понял, в том, что в комитет по стандартизации C++ было подано предложение под названием "P3403 The Undefined Behaviour Question". Кому-то из комитетчиков в названии увиделась аналогия с "еврейским вопросом" (Jewish Question) времен гитлеровской Германии. И автора предложения попросили поменять название. Он сперва раздумывал об этом, но потом решил оставить все как есть, т.к. придерживается мнения, что вопрос об undefined behaviour в языке программирования не имеет ничего общего с геноцидом по этническому признаку. После чего (как я понял) его предложение отказались пропускать через комитетскую бюрократию, а его самого подвергли обструкции.

Эта история всплыла на Reddit-е, в разделе /r/cpp, откуда была удалена, но осталась в другом разделе. А потом и сам автор предложения "The Undefined Behaviour Question" подробно изложил свою версию происходивших событий: First-hand Account of “The Undefined Behavior Question” Incident.

Ну что здесь остается сказать?

Сперва ветку master в git-е переименовали в main из-за того, что когда-то в США "master"-ом называли рабовладельцев, а сейчас git checkout master вызывает жуткие страдания у современных чернокожих программистов (ага, ага). Теперь вот это. Верной дорогой, товарищи. Прям как во времена СССР -- а нет ли в названии художественного произведения скрытой антисоветчины?

ИМХО, мир становится глобальным и чем больше это происходит, тем более диким выглядит то, как какая-то маленькая (в масштабах человечества) группа хер знает кого диктует всем остальным свои правила.

Это тем более дико на фоне того, что разработчикам из РБ и РФ обнуляют аккаунты на BitBucket-е, отказываются принимать от них pull request-ы, блокируют доступ к техническим ресурсам в Европе и США. Просто по географическому признаку: мол, если ты из РБ, то ты подлежишь обструкции. Просто потому что.

И если уж тут всплыла тема "еврейского вопроса", то нет ли здесь каких-то аналогий? Ну по типу навешивания "вины" просто по одному общему критерию -- раз из РБ, значит виноват в войне на Украине. Вроде бы где-то такое уже было? Что-то типа: ну, раз еврей, значит виноват в распятии Христа и пожирании невинных младенцев, и выпивании всей воды из крана.

В общем, чем дальше, тем больше начинает казаться, что дистанцирование от загнивающего Запада, не самая плохая штука в современных-то реалиях. Заимствовать оттуда нужно технологии, а не идеологию. А то докатимся до того, что отменим типы разъемов "папа" и "мама" из-за очевидного сексизма, мужского доминирования и объективизации женщин. Тьфу, срамота!

PS. Если данный пост позволил кому-то рассмотреть во мне замшелого ватника, застрявшего в СССР, то поздравляю, ваши розовые очки в очередной раз треснули от столкновения с реальностью.

вторник, 26 ноября 2024 г.

[prog.c++] Чего мне не хватило в boost::dynamic_bitset

Довелось немного попользоваться boost::dynamic_bitset. В принципе, отличная штука. И написана так, что можно заглянуть в потроха и понять что к чему. В общем, авторам решпект и уважуха.

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

Disclaimer: возможно, что-то из описанного ниже на самом деле в dynamic_bitset есть, просто я этого, несмотря на штудирование документации, не нашел 🙁 В таком случае прошу понять и простить... 😎

Во-первых, очень утомляет то, что для операций test и set нужно гарантировать, что индекс бита меньше текущего размера множества. Для меня это оказалось неудобно. Мне нужно фиксировать в bitset-е обработанные целочисленные индексы в диапазоне от нуля до N. Не всегда они идут последовательно, да и само N изначально неизвестно. Т.е. сперва мне нужно обработать, например, индекс 42, затем 24, затем 1, затем 100500.

Приходится перед вызовом set проверять, а есть ли i в bitset-е. Если нет, то сперва нужно сделать resize, а лишь затем вызывать set.

Аналогично, перед вызовом test нужно проверить, что i меньше size и только затем вызывать test.

В общем, неудобно. Было бы лучше, раз уж у нас dynamic_bitset, чтобы индексы больше или равные size обрабатывались должным образом без участия пользователя:

  • для set чтобы происходило автоматическое расширение множества;
  • для test чтобы возвращался false (ведь бита все равно нет, значит он точно не выставлен в единицу).

Во-вторых, операции AND и OR требуют, чтобы оба операнда были одинакового размера. Что неудобно, когда у меня оказываются два множества разного размера, а я хочу либо слить их в одно, либо вычесть одно из другого.

Из-за того, что операции AND/OR могут применяться только к множествам одного размера, приходится вручную разбираться с тем, какой кусок откуда вырезать, чтобы получить допустимые операнды.

Как по мне, было бы гораздо удобнее, если бы operator& сам бы определил результирующий размер итогового множества и выполнил AND только для фрагментов этого размера. Например, если мы делаем L & R, где L больше R, то имеет смысл выполнять AND только для первых R.size элементов из L.

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

В-третьих, идет в догонку к "во-вторых". Иногда нужно понять, а есть ли непустое пересечение между L и R. Т.е. мне не нужен точный результат пересечения, нужно просто понимать пусто ли такое пересечение или нет. Но если L и R имеют разные размер, то просто так я этого не узнаю. Мне сперва нужно получить два множества одинакового размера, потом уже для них делать intersect. Т.е. мне требуется создать новый dynamic_bitset, который нужен только для выполнения одного intersect-а и все.

Было бы круто, если бы был какой-то dynamic_bitset_view, похожий на std::string_view. Чтобы я мог в этот dynamic_bitset_view поместить только часть исходного dynamic_bitset-а. Причем чтобы при этом dynamic_bitset_view оставался бы легковесным объектом, который бы ничего никуда бы не копировал.

И тогда intersect вообще можно было бы делать не с исходными множествами L и R, а с их дешевыми фрагментами в виде dynamic_bitset_view.

вторник, 5 ноября 2024 г.

[prog.c++] Послесловие к релизу SO-5.8.3: будет ли SO-5.9 и если будет, то когда?

Осенью 2014-го года мы выпустили первую версию в ветке 5.5. Эта ветка затем развивалась пять лет без серьезных ломающих изменений. Я бы был не против и дальше обходится без заметных переделок, но, к сожалению, версия 5.5 набрала такой груз разнообразных фич, который стало уже тяжело нести. Накопился опыт, взгляды на какие-то вещи принципиально поменялись и было решено разгрести накопившийся наслоения не всегда хорошо сочетающейся функциональности. Так в 2019-ом появилась ветка 5.6.

Cчитаю, что в течении последних пяти лет именно эта ветка и развивается. Хотя, формально, мы сделали переход от 5.6 к 5.7, а затем и к 5.8, поскольку были пусть и небольшие, но ломающие совместимость изменения. Тем не менее, различия между 5.6 и 5.8 гораздо меньше, чем между 5.5 и 5.6. Так что для меня лично 5.6/5.7/5.8 -- это развитие одной и той же линии романа и изменение номера версии всего лишь дань формализму.

Сейчас заканчивается 2024-й год и получается, что семейство 5.6/5.7/5.8 поступательно развивается уже пять лет. Вроде бы повторяется история с пятилетним циклом жизни 5.5 и пора задумываться о том, что дальше.

На данный момент, в отличии от ситуации с 5.5, я не вижу каких-то фатальных недостатков в семействе 5.6/5.7/5.8. Необходимости разгрести авгиевы конюшни пока нет. ИМХО, у 5.8 еще есть запас прочности для продолжения в том же духе.

Поэтому какой-то насущной необходимости начинать ветку 5.9 нет.

Насущной нет, но есть вопрос с освоением новых стандартов C++. И в 2025-ом нужно будет всерьез задумываться над этим вопросом.

Пока что хватает и C++17. И для библиотеки хорошо, когда она отстает от самого-самого свежего стандарта -- тем самым больше проектов могут ее использовать. Но в какой-то момент возникает вопрос: а стоит ли это "хорошо для сторонних проектов" того, что мы отказываемся от плюшек современного C++?

В 2019-ом было решено, что невыгодно дальше держаться за C++11.

Полагаю, в ближайшие полтора-два года так же невыгодно станет держаться и за C++17. Вот тогда на горизонте и появится ветка 5.9.

Это один возможный сценарий развития событий.

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

Ведь сейчас в SObjectizer аллокации/деаллокации буквально на каждом шагу: за send-ом скрывается new, постановка заявки в очередь к агенту может вести к аллокациям, подписка или установка delivery filter требует аллокаций, даже смена состояния агента, если для состояния используется time_limit, требует аллокаций.

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

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

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

Прекрасно понимаю почему так, да и сам далеко не всегда готов платить за разработку дороже, если крах при bad_alloc-е вполне себе допустим.

Но что делать когда крах при bad_alloc-е ну такое себе? Вот тот же прокси-сервер с 200k одновременных подключений... Он рестартует, это OK. Вполне вероятно, что он рестартует за считанные секунды, а то и быстрее. Тогда как восстановление этих 200k соединений -- это же не быстрый процесс. Это неизбежно скажется на впечатлении пользователей от качества сервиса. Но, что хуже, у нас нет устойчивости против подобных падений в будущем. Допустим, мы принимаем 200k подключений и работаем нормально, но затем приходит одно специфическое подключение, при работе с которым мы вынуждены активно потреблять память и это ведет нас напрямую к очередному bad_alloc-у. И мы опять падаем роняя 200k соединений. А через какое-то время все повторяется вновь.

Если же поставить себе целью написать код, который может пережить bad_alloc, то придется придумать какую-то стратегию выживания. У нас должен быть набор действий по восстановлению (например, закрытие проблемного соединения и очистка связанных с ним ресурсов). И, что важно, мы должны быть уверены, что при выполнении данного набора действий у нас нет никаких динамических аллокаций (ведь каждая новая аллокация в таких условиях может вести к повторному bad_alloc-у).

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

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

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

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

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