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

О блоге

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

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

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

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

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

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

среда, 11 ноября 2026 г.

[prog.c++.thoughts] Тип bool временами не так полезен, как кажется

Заголовок поста может звучать провокационно, но когда я задумываюсь о местах, в которых bool уместен, так их оказывается всего ничего:

  • тип возвращаемого значения для методов empty в контейнерах;
  • тип возвращаемого значения для метода has_value в optional;
  • оператор приведения к bool в умных указателях, чтобы можно было писать if(my_ptr) (+ сюда же аналогичный оператор в optional);
  • иногда результаты проверок с бинарным результатом "да"/"нет", которые (результаты в смысле) нужно зачем-то сохранить.

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

Если bool используется в качестве типов параметров для функций, то в коде получаются ужасы вроде:

remove_relations(obsolete_relations, false, false, &errors);
delete_nodes(obsolete_nodes, false, &errors);
add_nodes(new_nodes, true, false, &errors);
add_nodes(changed_nodes, false, false, &errors);
add_relations(new_relations, false, true, &errors);

Что здесь означает каждый true и false, почему они именно такие -- хз, удачи в разборах.

Если bool используется в качестве возвращаемого значения, то получается не менее удручающе:

auto item_processor = [&](item_id id, bool pos_already_provided = false){
    auto res = calculate_one_value(
            id, weights, weights_params, global_pos,
            pos_already_provided);

    if (res.m_should_obtain_pos) {
        need_deep_search = true;

        sum = 0;
        return false;
    }

    if (!res.m_continuation_operator_found) {
        value = res.m_value;
        return false;
    }

    if (res.m_value)
        sum += data_extractor::get_number(res.m_value);
           
    return true;
};

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

Поэтому для себя сделал вывод:

  • bool в качестве типа аргумента функции/метода -- ни в коем случае. Лучше такого вообще не делать, вместо bool должен использоваться enum class;
  • bool в качестве возвращаемого значения -- если для случаев empty/has_value, то OK, в остальных случаях лучше enum class. Во многом уместность bool определяется именем и назначением функции/метода. Если это getter с именами вроде has_something или is_something, или can_do_something, или must_do_something (т.е. в названии сформулирован вопрос, ответом на который может быть только "да" или "нет"), то норм. Но если если метод мутирующий или функция имеет побочные эффекты, а возвращается bool, то тут могут (и скорее всего будут) возникать вопросы при чтении кода с использованием таких методов/функций;
  • bool в качестве локальной переменной -- сомнительно, но OK, особенно если это константа. Если не константа, то таки лучше подумать в сторону enum class;
  • bool в качестве члена класса -- сомнительно, но в некоторых случаях может быть OK. Например, если это флаг has_value в optional (или что-то вроде этого).

Вполне себе подходящий случай для bool в качестве члена класса -- это статическая константа value в метафункции, вроде:

struct some_trait {
  static constexpr bool value = ...;
};

Если же говорить в целом, то сам по себе тип bool должен быть в языке. И еще лучше, если он никак не смешивается с другими типами и не может приводиться в другие типы (или автоматически выводиться из других типов). Потому что если bool нет и начинаются извращения с int-ами и вручную написанными константами TRUE и FALSE, то это еще хуже (сам через это проходил 30 лет назад). Но таки мест, где bool был бы предпочтительнее специально написанного enum class-а, на сегодня, не так много, как кажется.

PS. Самым же бесполезным типом в C++, наверное, является тип short.

понедельник, 9 ноября 2026 г.

[prog.c++] Герб Саттер написал про ситуацию с C++26

На Reddit-е увидел ссылку на текст от Герба Саттера по поводу проблем с C++26: When a language’s creator and its owners strongly disagree: C++26 post-DIS, historical experience, and paths forward

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

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

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

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

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

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

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

Ну, например, приняли в C++20 модули. Кому-то же они понравились, раз приняли. А всем остальным приходится теперь ждать пока это "изобретение" наконец-то полноценно поддержат везде. Чтобы затем изучать очередную странную и не очевидную херню, добавленную зачем-то в уже работающий язык, ломающую старые самодельные системы сборок и разделяющую сообщество на "до и после".

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

Теперь вот очень и очень странные контракты. Которые, как по мне, без поддержки контрактов для виртуальных методов не должны были добавляться в язык в принципе. А с текущей процедурой работы над стандартом вообще получается маразм: скоуп C++26 закрывается в 2026-ом году с контрактами без поддержки виртуальных методов, и тут же, в же 2026-ом году в C++29 включается пропозал, который эту самую поддержку виртуальных методов в контракты добавляет.

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

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

  • модулями, которые не могут реализовать на протяжении многих лет;
  • недоделанными короутинами;
  • deducing this, который не совместим с экспортом классов из DLL (ведь стандарт вообще ни сном ни духом про существование DLL и SO);
  • рефлексией с таким синтаксисом, после которого язык C++ начинает уверенно побеждать всех конкурентов в борьбе за звание языка с самыми уродскими синтаксическими конструкциями...

И вроде бы все было хорошо, комитет заседает, стандарты выходят. Но тут БАХ! И кто-то эту замечательную отлаженную схему по строительству воздушных замков взял и обломал.

Вот жеж уроды.

воскресенье, 1 ноября 2026 г.

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

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

Фильмы

Фальшивомонетчик (L’affaire Bojarski, 2025). Мне понравилось. Вроде бы и история не самая сложная, но рассказана интересно, плюс воссозданная атмосфера тех лет. Посмотрел с удовольствием.

Надежда (Hopeu, 2026). Очень бодренько. Ну и я смотрел с пиратским матерным переводом, так что было бодренько вдвойне.

Поймать Эль-Чапо (La Captura, 2026). Неожиданно неплохое кино из Мексики. Да, ощущается бюджетность. Да, не хватает экшОна. Но насколько хорошо создателям удалось передать ужас обычных полицейских, оказавшихся в такой ситуации, просто мое почтение.

Тенцинг (Tenzing, 2026). Было бы лучше, если бы хронометраж сократили минут на 20, убрали бы сопли из воспоминаний о тяжелом прошлом главного героя и больше сконцентрировались на том, какими же фантастически тяжелыми были условия первых восхождений на Эверест.

Мятеж (Mutiny, 2026). Классический фильм со Стетхемом в главной роли: очень бодро, очень предсказуемо.

Бегущая (The Runner, 2026). Довольно бодренько и развязка хорошая. Но, во-первых, меня дико бесила операторская работа. Во-вторых, было в фильме несколько ну очень уж фантастических моментов, в которых спасение главной героини выглядело совсем уж сказочным. Что, в сумме, сильно портит впечатление от просмотра.

На краю Оук-стрит (The End of Oak Street, 2026). Глянуть можно, но очень уж по детски и очень уж дешевые спецэффекты.

Любой ценой (By Any Means, 2026). Очень скучное кино. Не смотря на какой-то экшОн и жестокость, рассказанная история не цепляет.

Мотор Сити (Motor City, 2025). Ну очень нудно и затянуто. Немного спасает ситуацию саунд-трек, но только немного. В развязке фильма одного из героев загримировали так убого, что окончательно убили все то хорошее, что в фильме еще было.

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

Флорист (The Florist, 2026). Очень посредственно даже не смотря на участие хороших в прошлом актеров. Да еще и очень бюджетно.

Мексикали (Mexicaly, 2026). Дешевый боевик с закосом под олдскульность. Сцены рукопашных боев сделаны отлично, все остальное снималось "на сдачу", в особенности перестрелки.

Сериалы

Капкан для монстра (первый сезон, 2026). Неоднозначные впечатления. Главные злодеи угадываются практически сразу. Плюс случаются моменты, в которые хочется воскликнуть "ну что за фигня?!!!" Но, с другой стороны, играют хорошо, история затягивает, какой-то типичной сериальной затянутости не ощущается. В общем, не шедевр, но посмотреть вполне можно.

Число зверя (первый сезон, 2026). Начало было приличным, но затем стали накапливаться разные моментики (вроде проведения обыска с санкцией, но без понятых), которые сильно подпортили итоговое впечатление.

суббота, 31 октября 2026 г.

[prog.c++] Пара слов о stackless короутинах в C++20

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


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

task_t my_coro(int a, char * b) {...}

то у task_t::promise_type должен быть либо дефолтный конструктор, либо конструктор вида:

promise_type(int, char *)

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

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

Или вот мне захотелось уметь привязывать task_t к конкретному планировщику, а в прототипе my_coro нет никаких планировщиков -- только int и char*. И все, выдумывай что хочешь.

Что тут можно было бы придумать?

А вот пока не знаю. Для меня вообще stackless короутины -- это странный и непривычный зверь с очень ограниченной областью полезного применения. Пока еще не набил с ними достаточного количества шишек. Поэтому могу только фантазировать.

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

auto r = co_await co_create(allocator, scheduler) socket.connect(ip_address);

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

Может быть в co_create можно было бы предавать и признак того как именно короутина должна стартовать -- энергично или лениво:

auto c = co_create(std::lazy) socket.connect(ip_address);
...
auto r = co_await c;

Но на счет этого не уверен совершенно.


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

Метод await_suspend у Awaiter-а может иметь разные типы возвращаемых значений:

  • void. Приостанавливать текущую короутину нужно обязательно;
  • std::coroutine_handle. Нужно возобновить работу указанной короутины. В том числе это может быть и текущая короутина если приостанавливать ее не пришлось;
  • bool. Нужно или не нужно приостанавливать текущую короутину определяется возвращенным значением.

И вот с bool-ом лично у меня постоянные заминки. Ну не могу я запомнить что означает true: приостановить короутину или же нет.

И тут спрашивается: а что мешало вместо bool сделать специальный тип, вроде:

enum class await_suspend_result { suspend, resume };

Т.е. если await_suspend возвращает await_suspend_result::suspend, значит текущую короутину нужно таки заморозить. А если await_suspend_result::resume, то наоборот.

Ну ведь просто же и понятно. Так почему нет? Экономия на новых типах в стандартной библиотеке?

суббота, 10 октября 2026 г.

[work;life] СтифСтриму десять лет

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

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

Несколько лет назад пошутил:

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

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

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

Пока что на 100% эта цель не достигнута 😉
Тут еще есть над чем работать.

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

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

Во-первых, когда СтифСтрим создавался, мне было уже за 40. И я исходил из того, что это будет моя первая и последняя попытка начать собственное дело. Поэтому не рассматривал для себя опцию "быстро попробуем, если не пойдет, то закроемся и посмотрим в другую сторону". Хотя, наверное, следовало бы. Оглядываясь назад и присматриваясь к чужому опыту понимаю, что одним из важных качеств бизнесмена является умение признавать неудачи, быстро ликвидировать убыточные предприятия и пробовать новые направления. Мне этого умения не хватило. Возможно, компанию имело смысл закрыть где-то в 2019-ом или 2020-ом году, когда все наши первоначальные планы окончательно накрылись медным тазом. Возможно. Но история не знает сослагательного наклонения. Поэтому сегодня СтифСтим отмечает свое десятилетие.

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

В-третьих, я долго не мог понять кому же нужны наши услуги. Только в последние 3-4 года стало окончательно понятно, что это небольшие по размеру компании, в которых от 4-5 до 10-15 разработчиков.

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

Ну да все это дела минувшие. А вот заглядывать в будущее страшновато.

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

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

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

Как-то так: делай что должно и будь что будет. Ну а я был бы не против через 10 лет написать еще один такой пост.