Показаны сообщения с ярлыком Поток сознания. Показать все сообщения
Показаны сообщения с ярлыком Поток сознания. Показать все сообщения

пятница, 31 июля 2026 г.

[prog.thoughts] Так как же ИИ может изменить профессию "программист"?

Попробую подвести итог начатых ранее размышлений.

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

Во-первых, это экономическая и политическая обстановка в мире. Если не будет какого-то катаклизма, сравнимого с Первой или Второй Мировыми войнами, если мировая экономика выберется из кризиса и вернется экономический рост, то у программистов в целом все будет ОК. Будет работа, которая, наверняка, сильно изменится. Но эта самая работа хотя бы будет. А вот если мир скатится во что-то вроде Великой Депрессии в США 1930-х годов, или периода Веймарской республики начала 1920-х годов, то увы. Всем будет очень и очень не очень. В том числе и программистам. А может быть программистам как раз в первую очередь.

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

Еще, конечно же, интересный вопрос в том, до какого уровня качества этот самый ИИ в итоге дойдет. Пока все говорят (говорят!), что ИИ с каждой новой версией становится все лучше и лучше. Хотя внешней публике и не видно во что (по деньгам инвесторов) эти улучшения обходятся.

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

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

Думаю, что тогда наша профессия изменится. Быстро и бесповоротно.

Но не исчезнет.

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

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

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

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

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

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

четверг, 30 июля 2026 г.

[prog.thoughts] Надобность в "инфраструктурниках" из-за того, что людям приходилось писать код самим

Продолжу то, что начал ранее.

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

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

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

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

Получается, что чем более сложную задачу нам нужно решить, тем большим количеством более мощных абстракций мы должны располагать. Будь то языковые конструкции (вроде классов или шаблонов/дженериков) или библиотеки готовых "компонентов". А воплощение в жизнь подобных абстракций -- это именно что работа инфраструктурных программистов. Кто-то из инфраструктурщиков развивает языки программирования для того, чтобы поднять уровень и дать возможность выражать в коде все более и более сложные вещи, при этом обеспечивая и надежность, и удобство (если не брать в рассмотрение C++, конечно же). Кто-то пишет библиотеки и фреймворки. Кто-то создает вспомогательные инструменты вроде flex/bison или ANTLR.

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

Или может быть лучше сказать "получали"?

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

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

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

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

Это люди могли набить шишки на return -1, прийти к выводу, что исключения надежнее, потом собрать кучу граблей с исключениями, прийти к выводу, что нужен симбиоз, изобрести синтаксис `?` в Rust и try в Swift...

Чтобы в итоге этих самых людей заменил ИИ, который будет генерить простыни Go-шного кода с примитивнейшим `if err != nil` ничуть не страдая от того, что это и многословно, и отвлекает внимание, и не обеспечивает достаточной надежности.


Продолжение.

среда, 29 июля 2026 г.

[prog.thoughts] Мое деление программистов на "прикладных" и "инфраструктурных"

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

Прикладные программисты делают то, что нужно пользователю. Причем не важно, о каком именно продукте идет речь -- это может быть какая-то сделанная на коленке под заказ система складского учета для провинциальной конторы "Рога и Копыта", пакет Microsoft Office или же сервер реляционной СУБД. Суть в том, что есть продукт, есть требования к нему, есть список фич, которые нужно выкатить, есть сроки, есть бюджеты, есть обязательства и т.д., и т.п. И появляется конкретный продукт для конкретного пользователя именно благодаря труду прикладных программистов.

Инфраструктурные программисты делают инструменты, которые используют прикладные программисты в своей работе. Самыми яркими примерами таких инструментов являются фреймворки и библиотеки. Как общего назначения (вроде Qt, JDK или .NET Framework), так и какие-то специализированные, заточенные под конкретный проект.

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

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

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

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

Яркий пример, демонстрирующий разность в подходах, довелось увидеть буквально пару дней назад в докладе «Опыт перехода проекта „Авито.Доставка“ с Java на Go» / Илья Лапин, Сергей Поляков (Avito), который мне YouTube зачем-то подсунул в рекомендациях (но оказалось довольно любопытно, благо доклад короткий и толковый):

Суть в том, что на момент доклада (2018-й год) в стандартной библиотеке Go (как и в самом языке) не было такого понятия как "множество" (оно же Set). Понятие "словарь" встроенное в сам язык было (в виде штатного типа map), а вот "множества" -- нет.

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

Тогда как инфраструктурный программист от подобного впадает в ступор. Типа: "а почему этот самый Set нельзя было взять и сделать?" 😉

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


Продолжение.

вторник, 28 июля 2026 г.

[prog.thoughts] И еще одна мысль про влияние ИИ на программирование

Навеяно вот этой статьей: Английский вместо кода

Когда я приходил в профессию на программиста возлагались следующие задачи:

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

Плюсом сюда же могло попасть (и зачастую попадало) участие во внедрении сделанного. А потом и сопровождение, включая оперативное реагирование на инциденты с внезапной побудкой в полтретьего ночи или срочным выездом на объект заказчика.

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

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

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

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

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

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

Как по мне, так это уже и не программирование вовсе.

понедельник, 27 июля 2026 г.

[prog.thoughts] Подумалось тут про ИИ и будущее программирования...

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

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

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

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

понедельник, 29 июня 2026 г.

[prog.thoughts] Начинаю думать, что бесстековые короутины в C++ следовало делать чуть иначе

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

Изначально я планировать только позволить пользователю описывать event-handler-ы, в которых можно было бы делать co_await. Но по мере продумывания способов реализации столкнулся с тем, что не имею на руках никаких механизмов запуска внешних по отношению к SO-5 короутин. А это нужно, чтобы проверить, что из event-handler-а можно дернуть, скажем, короутину из Asio, и когда она завершится, управление должным образом вернется event-handler-у.

И тогда появилась мысль сделать сперва возможность асинхронной работы с mchain-ами. Сейчас в SO-5 есть синхронные версии receive и select, а что, если предоставить их асинхронные версии? Тогда в event-handler-е можно было бы написать что-то вроде:

so_5::event_handler_task_t
some_agent::evt_some_handler( mhood_t<some_msg> cmd )
{
  auto result = co_await so_5::async_receive( so_5::from( test_chain ), ... );
  ...
}

Тогда отправляя (или не отправляя) сообщения в тестовый канал я бы мог тестировать поведение event-handler-ов.

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

А выкристаллизовалось понимание чего же именно не хватает в процессе знакомства с библиотекой Capy (которую сейчас пытаются запихнуть в Boost). Как раз авторы данной библиотеки четко выделили проблему, которую не удавалось нащупать мне. И попробовали ее решение прикрутить сбоку синей изолентой.

Суть в том, что в интерфейсе короутин нет способов явно указать на каком рабочем контексте короутина должна быть продолжено. Лично мне не очевидно кто и где будет вызывать resume для coroutine_handle когда короутина окажется готова к возобновлению.

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

В Capy ее предлагают решать за счет введения специальной сущности -- Executor-а и за счет изменения интерфейса сущности Awaiter-а: метод await_suspend для Awaiter-а вместо одного аргумента получает два:

std::coroutine_handle<> await_suspend(std::coroutine_handle<> h, io_env const* env);

И во втором параметре передаются вещи, которые могут потребоваться короутине (и ее дочерним короутинам): executor, stop_token, allocator.

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

Это как раз то, чего мне не хватало для реализации асинхронных версий receive/select. Я уже сам пришел к мысли о том, что в асинхронный receive нужно передавать какой-то coro_scheduler, который будет отвечать за то, чтобы возобновить приостановленный receive/select именно там, где это разрешено. Например, если receive вызывается из event-handler-а, то это могло бы выглядеть так:

auto result = co_await so_5::receive(
  so_5::from( test_ch ).resume_by( this->so_coro_scheduler_for_this_agent() )...,
  ... );

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

so_5::cpp_coro::this_thread_scheduler_t coro_scheduler;
coro_scheduler.sync_wait(
  [&coro_scheduler, &ch]() -> so_5::cpp_coro::async_receive_task_t {
    co_await so_5::receive(
      so_5::from( ch ).resume_by( coro_scheduler )..., ...);
  } );

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

Но, повторюсь, и подход Capy, и мои попытки придумать некий условный coro_scheduler для SObjectizer-а -- это попытки прикрутить решение сбоку посредством синей изоленты.

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

Например, чтобы обращение к co_await можно было параметризовать. Скажем, передавать executor/scheduler непосредственно в co_await:

co_await(executor) some_task();

И чтобы этот executor передавался бы параметром в await_resume. Может быть в виде ссылки на некоторый специальный объект environment, как это делается в Capy.

Есть у меня подозрение, что с такой явной передачей executor-ов в co_await, код с короутинами и писать, и читать было бы гораздо проще.

PS. Раз уж заговорил про попытку добавить поддержку короутин в SO-5, то слегка обозначу текущий статус. Пока до чего-то работающего еще далеко. Пытаюсь двигаться от простого к более сложному. Сперва хочу попробовать сделать асинхронную версию receive/select. Чтобы с ее помощью перейти к поддержке event-handler-ов в виде короутин. Затем, возможно, попробую погрузиться еще глубже, чтобы разрешить короутины в роли обработчиков входящих сообщений в receive/select (если это вообще возможно). Работы много, ресурсов мало, движется все очень медленно. Поэтому я сам в течении ближайших пару месяцев никаких значимых результатов не жду.

понедельник, 15 июня 2026 г.

[prog.c++.imho] Не согласен с постулатами пропозала P3097 (контракты для виртуальных методов)

Комитет по стандартизации C++ продолжает творить дичь. Сперва в C++26 были включены кастрированные контракты (нет ключевого слова old в постусловиях, нет контрактов для виртуальных методов, нет инвариантов для экземпляров классов и циклов). Для людей, знакомых с Eiffel, контракты из C++26 выглядят как "мы не осилили тему полностью, поэтому впихнули в стандарт какой-то эрзац с надеждой, что со временем допилим". Не хочу обсуждать зачем нужен эрзац вместо нормального продукта. Просто перейду к следующей дичи.

Далее в C++29 включили предложение P3097, которое описывает контракты для виртуальных методов классов. И авторы этого предложения, как по мне, покусились на святое: на сформулированное много-много лет назад для Design By Contract в Eiffel-е требование о том, что производный класс может только ослабить предусловния и ужесточить постусловия, но не наоборот.

И вот авторы пропозала почему-то пришли к выводу, что C++ настолько особенный, что в нем можно это требование послать в пешее эротическое.

На протяжении нескольких страниц пропозала эти люди пытаются приводить "аргументацию" своей точки зрения. Меня эта аргументация не убеждает от слова совсем. Скорее наводит на мысль о том, что люди толком не понимают тему, о которой пытаются рассуждать и, скорее всего, не имеют опыта разработки на языках с поддержкой Design By Contract (в первую очередь на Eiffel-е, на который в данной теме и следует равняться).

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


В разделе "3.2 Adoptability in legacy code" есть интересный заход:

среда, 15 апреля 2026 г.

[prog.sadness] Вскрик души в процессе копания в чужом коде

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

PascalCase -- отстой.

PascalCase в совокупности с длинными строками и экономией на пробелах и пустых строках -- отстой вдвойне.

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

Удачно выбранные имена классов рулят. Неинформативные имена или имена, отличающиеся всего одной буквой (например, resource_handler и resources_handler) доставляют (в худшем смысле этого слова) неимоверно.

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

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

Но главное впечатление, еще более субъективное, личное и неутешительное для меня самого: очень сложно работать с кодом, написанным по принципу "сейчас кое как слепим, а потом переделаем по нормальному". Пытаясь разобраться с результатом главная мысль в голове -- "Господь, жги, тут уж ничем не помочь". А жечь то как раз и нельзя 😡

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

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

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

[business] Практические выводы из того, что успешный результат в бизнесе не гарантирован

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

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


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

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

И так снова и снова.

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

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


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

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

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


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

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

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

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


Нужно как-то научиться спокойно относиться к потере собственных денег.

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

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

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

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


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

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

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

Отсюда еще один, если можно так сказать, совет: не стоит затягивать с попыткой начать свое дело. Если в 35 вы задумались о том, что пора открывать что-то свое, то лучше не откладывать это до 45. Можно попробовать в 36 и к 45 совершить несколько попыток. Либо что-то увенчается успехом, либо вы поймете, что в найме все-таки спокойнее и денежнее и будете тихо встречать неизбежно приближающуюся старость ;)

понедельник, 2 февраля 2026 г.

[business] О чем вам не раскажут бизнес-спикеры с YouTube

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

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

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

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

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

Можно посмотреть, скажем, на велогонщиков. В гранд-турах, вроде Вуэльты или Тур-де-Франц, участвуют порядка 200 спортсменов, но победы на этапах одерживает дай бог если пара десятков, а на общую победу даже в теории претендуют только единицы. Причем это все гонщики ТОП-ового мирового уровня, на которых приходятся тысячи тех, кто даже никогда до гранд-тура не доберется в принципе.

Значит ли это, что абсолютно все те, кто не побеждает, просто недостаточно подготовлены? Что они просто мало тренируются или не соблюдают спортивный режим? Не следуют рекомендациям тренеров, спортивных врачей и других специалистов?

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

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

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

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

Ага. Как же.

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

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

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

понедельник, 26 января 2026 г.

[prog.thoughts] Как ИИ может отбирать хлеб у разработчиков библиотек

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


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

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

Грубо говоря, если 10 лет назад я рассчитывал на то, что вокруг OpenSource можно зарабатывать на трех вещах:

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

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


Чтобы затронуть еще один важный момент нужно ответить на вопрос, а зачем вообще нужны библиотеки?

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

Почему библиотеки возникли?

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

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

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

Возможно это приведет к тому, что библиотеки отживут свое как явление.

Действительно, зачем нужна удобная библиотека для парсинга JSON-а, если ИИ по спецификации может сгенерировать фрагмент, который будет разбирать входной поток байт прямо "по месту"? Кого вообще будет заботить, что ИИ сгенерировал "рукопашный" разбор вместо того, чтобы использовать готовую JSON-библиотеку? Особенно, если сгенерированный код справляется со своими задачами и покрыт тестами (сгенерированными тем же ИИ).

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

И чем лучше и удобнее были те самые библиотеки, тем проще было прикладным программистам.

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

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

вторник, 20 января 2026 г.

[prog.flame] Пробелы таки выигрывают у табуляции?

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

А вот когда узнал, году эдак в 1992-ом, то практически сразу же перешел с пробелов на табуляции, ибо:

  • исходные файлы с табуляцией занимали гораздо меньше места. Что было более чем критично во времена дискет на 1.2 MiB. Ведь тогда в наших палестинах самыми распространенными были 5.25" дисководы и дискеты на 360 KiB, 720 KiB и 1.2 MiB (хотя не везде диски на 1.2 MiB нормально читались и писались). Гораздо более надежные и практичные 3.5" дискеты на 1.44 MiB в нашей местности получили распространение спустя несколько лет. Архиваторы, вроде pkzip и arj уже были, но вроде бы исходники с пробелами все равно сжимались хуже;
  • текстовые редакторы для программистов тогда были гораздо более убогими, чем сейчас. Я не припомню редакторов, которые бы по клавише Tab и по сочетанию Shift+Tab двигали бы выделенный блок текста вправо или влево. Поэтому если тебе нужно было изменить выравнивание куска кода, то приходилось делать это вручную, и с табами было это гораздо быстрее и проще;
  • в те времена достаточно распространенной практикой была распечатка текстов программ. Сейчас это кажется диким, а 35 лет назад машинное время было дефицитом и ты не мог сидеть за компьютером часами на пролет в поиске какого-то заковыристого бага -- тебе этого просто не позволяли, а собственных персональных IBM PC-совместимых компьютеров в те времена практически ни у кого не было. В текстовом редакторе можно было выставить размер табуляции в 2 символа и видеть больше на тогдашних 14" EGA/VGA экранах с текстовым режимом 80x25 символов, а для печати использовать размер в 4 символа и получать более удобный для чтения формат. Тогда как с пробелами такой фокус уже не проходил.

В общем, в начале 1990-х для меня табы были намного практичнее пробелов. И таковыми они оставались в течении тридцати лет. Но сейчас ситуация в моих сценариях работы сильно изменилась.

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

Во-вторых, мне по работе периодически приходится вставлять куски кода в e-mail-ы или документы Google.Doc. Типа вот есть такой фрагмент, в нем вот здесь и вот здесь есть вот такие и такие проблемы, исправить их можно вот так и вот так, а еще лучше было бы переписать вот так или вот так. Но, к сожалению, со вставкой кусков кода с табуляцией внутри могут возникнуть проблемы. Так, если я пишу письмо прямо в Web-интерфейсе Google Mail, то при отправке письма все табы вырезаются и форматирование кода оказывается полностью сломано -- весь текст просто прижимается к левому краю 😡 Если фрагмент вставляется в Google.Doc, то форматирование более-менее сохраняется, но вносить в такой фрагмент правки -- это то еще приключение.

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

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

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

Преимуществ у табов, по факту, не осталось. Кроме привычки. Зато код с пробелами везде выглядит одинаково и забот с пробелами намного меньше.

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

А вот для новых проектов, похоже, имеет смысл выбирать именно пробелы.

среда, 6 августа 2025 г.

[prog.c++.thoughts] Design By Contract и приватные методы классов в C++

В C++26 будут включены контракты. Т.е. можно будет сказать, что элементы Design By Contract наконец-то доберутся и до C++.

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

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

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


Технология Design By Contract (DbC) берет свое начало в языке Eiffel (вот еще одно описание от первоисточника). Если вы не знакомы с Eiffel хотя бы в части понимания DbC, то вы, к сожалению, многое упустили в своей профессиональной подготовке. Если же знакомы, то, надеюсь, понимать написанное ниже будет проще.

Ключевыми для нашего разговора будут три вещи (на самом деле в Eiffel есть еще и инварианты для циклов, и утверждения check, похожие на C-шный assert, но их мы спокойно можем игнорировать):

суббота, 28 июня 2025 г.

[prog.c++.dreams] В очередной раз выяснил, что в C++ using это не strong typedef :(

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

Но, к сожалению, using не может сделать совершенно новый тип. Поэтому если у вас есть что-то вроде:

using type_a = ...;
using type_b = ...;

void do_something(type_a v) {...}
void do_something(type_b v) {...}

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

Например, раньше было:

using small_data = std::map<some_key, some_value>;
using large_data = std::unordered_map<special_key, some_value>;

using type_a = small_data::iterator;
using type_b = large_data::iterator;

А в один прекрасный момент стало:

using special_key = some_key;

using small_data = std::map<some_key, some_value>;
using large_data = std::map<special_key, some_value>;

И все 🙁
Типы type_a и type_b оказались одинаковыми.

Недавно в очередной раз наступил на подобные грабли, но немного в другом контексте. Было что-то вроде:

namespace processing
{

class processor {...};

template<typename Data>
void
handle(const processor & how, const Data & what)
{
  // Должна быть найдена подходящая функция за счет ADL.
  apply(what, how);
}

// namespace processing

namespace data_type_a
{

struct data {...};

void apply(const data & what, const processing::processor & how) {...}

// namespace data_type_a

namespace data_type_b
{

struct data {...};

void apply(const data & what, const processing::processor & how) {...}

// namespace data_type_b

И т.д.

Т.е. смысл в том, что в конкретном пространстве имен data_type_X должна быть функция apply, который компилятор посредством ADL находит для вызова внутри processing::process.

Все шло хорошо до момента, пока не появились data_type_i и data_type_j, в которых тип data был определен через using:

namespace data_type_i
{

using data = std::map<...>;

void apply(const data & what, const processing::processor & how) {...}

// namespace data_type_i

namespace data_type_j
{

using data = std::vector<...>;

void apply(const data & what, const processing::processor & how) {...}

// namespace data_type_j

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

А дело в том, что если заменить псевдонимы, то получались функции вида:

void apply(const std::map<...> &, const processing::processor&);
void apply(const std::vector<...> &, const processing::processor&);

И естественно, что ADL не мог их найти ни в пространстве имен std, ни в processing.

Было больно, т.к. пришлось отказаться от очень красивого способа привязки специфических данных к их обработчику 😪

В очередной раз захотелось, чтобы using в С++ мог работать как strong typedef. Чтобы можно было написать что-то вроде:

namespace data_type_i
{

using(new) data = std::map<int, std::string>;

// namespace data_type_i

И чтобы компилятор начал считать, что data и std::map<int, std::string> теперь разные типы. И что тип data теперь принадлежит пространству имен data_type_i, а не std.

PS. В свете добавления в C++ рефлексии может оказаться, что наколхозить какой-то нестандартый strong_typedef_for, типа:

namespace data_type_i
{

using data = my::strong_typedef_for< std::map<int, std::string> >;

// namespace data_type_i

через рефлексию будет быстрее и проще, чем дождаться появления using(new) в стандарте. Обычная традиция C++: если что-то можно собрать своими руками дендро-фекальным методом, то включать в стандарт удобный и нормальный вариант никто не будет.

понедельник, 16 июня 2025 г.

[prog.thoughts.flame] Прочел давеча статью про вайб-кодинг с использованием LLM

На RSDN-е поделились ссылкой на статью "Вайб-кодинг: практика, о которой почему-то не говорят" в которой рассказывается про опыт разработки некого проектика на Go посредством "искусственного интеллекта" (Sonnet 3.7).

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

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

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

Первый грубый пример, который сходу вспоминается, -- это мода на всяческие Wizard-ы, которые начали появляться в IDE когда стало возникать само понятие IDE (середина-конец 1990-х). Помнится, в каком-нибудь условном Borland C++ 2.0 кучу кода нужно было написать вручную прежде чем у тебя появится примитивное приложение с одним окошком. А в каком-нибудь Borland C++ 4 или VisualStudio 98 ты кликнул на несколько кнопок в Wizard-е и получил готовый каркас приложения с тем самым одним окошком.

Еще один вспомнившийся пример: простые декларации модели данных средствами ActiveRecord в Ruby-On-Rails скрывают за собой кучу ORM-кода.

Более сложный пример, который, возможно, не все сочтут релевантным, -- это генераторы парсеров, вроде yacc/bison, coco/r, ragel или ANTLR. Ведь чтобы вручную написать разбор даже относительно несложной грамматики придется написать не одну сотню строк кода. Тогда как в случае с bison-ом ты описываешь лишь то, что тебе нужно, на специальном DSL, и получаешь здоровенную простыню автоматически сгенерированного кода.

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

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

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


Не могу не заострить внимание на нескольких фразах из статьи, касательно которых хочется сказать пару слов.

Рутинные задачи, написание бойлерплейта, стандартных функций — всё это автоматизируется. Время освобождается. Фокус смещается с написания строк кода на архитектуру, декомпозицию задач, правильную постановку технического задания, которое теперь превращается в промптинг.

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

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

И до недавнего времени задача разработчиков (по крайней мере той части разработчиков, которая занимались языками программирования и фреймворками) состояла именно в том, чтобы дать прикладным программистам те самые высокоуровневые, заточенные под задачу инструменты (в виде продвинутых ЯП, специализированных DSL или же фреймворков для ЯП общего назначения).

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

Т.е. высокоуровневыми инструментами становятся не ЯП/DSL/фреймворки, а генеративные модели, которые запросто выплевывают мегатонны кода на уже существующих языках общего назначения. А исходником становится текст промпта для AI.

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

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

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

А вот тут у меня возникают опасения.

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

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

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

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

Второй же момент возникает из того, что автор статьи пишет в других местах:

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

Что-то я весьма скептически отношусь к такой вещи, как "умение читать чужой код".

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

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

Насколько хорошо вы решаете такие задачи?

А если код не одна страничка текста, а 150-200-250 и более строк?

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

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

Но этого не происходит.

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


Если же все-таки попробовать подвести некий итог от прочитанного, то есть ощущение, что прикладное программирование с пришествием AI должно очень серьезно измениться. Под прикладным я понимаю решение задач, необходимых конечным пользователям программного обеспечения, типа "посмотреть историю движения остатков по складам за три последних квартала" или "сделать интеграцию с сервисом N для того, чтобы видеть последние M товаров, интересных пользователям пришедшим с площадки K".

Другой вопрос: а что будет с теми, кто занимается не рутиной, а какими-то уникальными велосипедами? Например, сможет ли AI в обозримое время заменить тех, кто сделал Roaring Bitmap?

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

В общем, не знаю чего ожидать. Есть ощущение, что ничего хорошего.

PS. Убежден в том, что развитие тех самых IDE из середины 1990-х с их Wizard-ами, автоматизированными рефакторингами, интеллектуальным автодополнением и мгновенной навигацией по коду сделало ситуацию в программизме только хуже: стало больше говнокодеров и, соответственно, говнокода. А производство кода посредством AI лишь усугубит дело -- это как самые продвинутые IDE на конских дозах стероидов + массовое непонимание того, что творится в сгенерированном коде. Так что да, есть ощущение, что ничего хорошего таких как я не ждет.

пятница, 4 апреля 2025 г.

[prog.c++] Нормально на C++ программируют лишь параноики?

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

Под кодом на "современном C++" понимается код, в котором активно используются шаблоны, лямбды, исключения, контейнеры, алгоритмы, перегрузка операторов и вот это вот все. Такой код может выглядеть как вполне себе высокоуровневый, почти как современная Java, C# или даже Scala.

Проблема, однако, в том, что C++ таким высокоуровневым языков не является.

Есть ряд моментов, которые, скажем так, портят всю малину.

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

Или, что часто происходит в моей практике, люди забывают (или не знают?) про exception safety. Как результат, если вылет исключения не приводит к немедленной катастрофе, то уж утечку ресурсов или нарушение инвариантов множества объектов вызывает точно. Далеко не все программисты, к сожалению, привыкли к повсеместному RAII. А обеспечение strong exception safety обходится не бесплатно в плане сроков написания кода (особенно если это дело еще и покрывать тестами).

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

Но вот молодежь, особенно которая приходит в C++ из безопасных, высокоуровневых и выразительных языков... Вот они, такое впечатление, бегают как непуганые по минному полю. И глядя на них думается, а не стал ли я с годами параноиком?


На самом деле проблема не в "современном C++", а именно в C++ безотносительно его версии.

Как по мне, так старый и недобрый "Си с классами" являлся еще большим рассадником багов и внимания к мельчайшим деталям при программировании на C++98 требовалось даже больше, чем сейчас.

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

Тогда как код на современном C++, с какими-нибудь ranges и coroutines может производить обманчивое впечатление того, что C++ таки вошел в одну когорту с Java, C#, Scala и, может быть, даже Python с JavaScript. Что есть опасное заблуждение.

Да, на C++ можно писать высокоуровневый код, особенно при наличии хороших прикладных библиотек. Только вот возможность нечаянно отстрелить себе ногу никуда не делась. Что принципиально отличает C++, даже в самых его свежих стандартах, от Java/C#/Python/JavaScript.

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

PS. Нахожусь при мнении, что при программировании на чистом Си параноить приходится гораздо меньше. Потому, что там нет исключений. И нет неявно вызываемых конструкторов (например, когда из строкового литерала внезапно возникает экземпляр std::string). Поэтому в мире чистого Си при использовании идиомы goto cleanup чувствуешь себя намного спокойнее.

PPS. Нормально программировать на C++ вполне себе возможно, сколько бы не пытались лаять хейтеры и ниасиляторы.

понедельник, 13 января 2025 г.

[prog.c++] Интересная постановка вопроса: если люди испытывают сложности с многопоточностью, то не забанить ли многопоточность совсем?

Этот вопрос всплыл на днях на r/cpp. Позволю себе процитировать значимую часть поста с reddit-а без перевода:

Hi all,

Had an interesting discussion today and would appreciate some advice.

Multithreaded code can be especially tricky for medium to junior level developers to write correctly. When a mistake is made, it can result in difficult to find bugs.

If the application you are working on needs to be very reliable (but isn't safety critical), what would you recommend for medium/low experience c++ teams?

Assume that the application will need to do 4 things at once and can't use state machines or coroutines. The various "threads" need to regularly exchange less than 10 KB of data a second.

Do you ban threads?

A few approaches come to mind.

#1 train the team to know the dangers and let them use threads with best practices. More experienced (and paranoid/diligent) developers carefully audit.

Any suggestions for books/resources for this team?

#2 and/or use a tool or technique to detect concurrency issues at compile time or during test? Thread sanitizer? cppcheck? ???

#3 ban threads and force concurrency to be implemented with multiple processes. 4 processes each with 1 thread. The processes will communicate with some form of IPC.

Т.е. смысл в том, что для разработчиков уровня middle/junior написание мультипоточного кода зачастую оказывается слишком сложным. И если приложение должно быть надежным, то возникает вопрос: как же быть? Может быть проще вообще запретить многопоточность в пользу многопроцессности? А если не запрещать, то что? Учить людей? Использовать какие-то инструменты для тестирования и анализа корректности кода?

Признаться, комментарии на reddit-е к этому посту я не читал, только просмотрел мельком и не увидел того, чего хотел 🙁

Поэтому выражу эмоции в этом блог-посте.

Хватить себя обманывать -- писать низкоуровневый многопоточный код сложно не только middle/junior-ам, но и senior-ам. Не устану повторять, что многопоточность на голых нитях, mutex-ах, condition_variable и, ниприведихоспади, atomic-ах -- это пот, боль и кровь.

Поэтому если у вас есть возможность не писать многопоточный код, то не пишите его.

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

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

Если нужно, значит наш путь лежит в многопоточность. Если не нужно, то выдыхаем и не паримся (до поры до времени).

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

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

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

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


Выбор между многопоточностью и многопроцессностью в современных условиях, имхо, должен лежать не плоскости простоты написания многопоточного или однопоточного кода. А, прежде всего, в плоскости дополнительных факторов. Например, таких как:

  • обеспечение надежности работы в условиях ненадежности используемых программных компонент. Например, мы вынуждены полагаться на стороннюю библиотеку, которая время от времени падает и роняет весь процесс, в котором ее используют. Библиотека не наша, мы не можем "довести ее до ума", можем только минимизировать причиняемый ею ущерб;
  • обеспечение надежности работы в условиях ненадежности внешнего оборудования и/или внешних сервисов. Например, к компьютеру подключено устройство, которое может зависнуть. И единственный способ вернуть его к жизни -- это убить процесс, который общался с устройством, переинициалировать устройство и начать работать с ним заново. Аналогично и со сторонними сервисами, с которыми мы можем общаться через HTTP(S) или еще какую-то форму IPC. Бывает, что такой сервис набирает от нас N запросов и перестает подавать признаки жизни до тех пор, пока все эти N запросов не будут принудительно прекращены;
  • возможность жесткого прерывания длительных операций. Например, какой-то математический расчет, который может занимать часы и который не так-то просто прервать "изнутри". Но вот если вынести этот расчет в отдельный процесс, то этот процесс легко "прибить" в случае необходимости;
  • простота и удобство реконфигурации "на лету". Иногда работающий в режиме 24/7 сервис нужно переконфигурировать без его останова, но из-за внутренней кухни и/или особенностей использованных в нем библиотек, сделать такую переконфигурацию затруднительно.

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

  • в Unix-ах нужно избегать возникновения зомби-процессов;
  • после принудительно убитого дочернего процесса могут оставаться различные следы жизнедеятельности (в виде .tmp-файлов, которые не были вовремя удалены), которые нужно подчищать;
  • если взаимодействие идет через shared-memory, то нужно как-то определить а доверяем ли мы текущему содержимому блока разделяемой памяти или же внезапно умерший дочерний процесс оставил там какой-то мусор...

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

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


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

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

[prog.thoughts] Программист: хороший, плохой, крутой. Что под этим вообще понимается?

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

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

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

Соответственно, с плохим программистом все просто: это противоположность "хорошего программиста".

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

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

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

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

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


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

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


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

среда, 11 декабря 2024 г.

[prog.flame] Комментарии в коде нужны. Без них тяжено, проверено на собственном опыте

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

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

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

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

  • почему это сделано именно так, а не иначе?
  • зачем вообще это было сделано?

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

Первоначально я хотел на этом и закончить, но встретил в статье про переиздание знаменитой книги "Мифический человеко-месяц" вот такой абзац:

Однако есть и другая точка зрения на этот вопрос. Например, Мартин (Роберт, а не Джордж), автор книги «Чистый код», утверждает, что комментарии — это зло. Даже будучи среди исходного кода они всё равно могут стать неактуальными. «Не трать время на написание комментариев», – говорит Мартин. Вместо этого он предлагает более тщательно подходить к процессу именования переменных, методов и классов. Если всё делается правильно, то и необходимость в комментариях отпадает.

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

Disclaimer. Приведенный код -- это черновик, который еще не компилировался и не тестировался.

Итак, вот фрагмент без комментариев:

template<typename T>
void
doAttemptToSwitchFromReadOnlyToReadWrite(T * objectToLock)
{
   auto & globalList = getGlobalListFor(objectToLock);
   std::unique_lock globalListLock{ globalList._lock };
   auto it = globalList._objects.find(objectToLock);
   if(it != globalList._objects.end())
   {
      auto & lockInfo = it->second;
      if(AccessMode::ReadOnly != lockInfo._currentMode)
         throw std::runtime_error{
               "doAttemptToSwitchFromReadOnlyToReadWrite: "
               "lockInfo._currentMode != AccessMode::ReadOnly "
               "in the global lock list"
            };

      if(1u == lockInfo._ownersCount)
      {
         lockInfo._currentMode = AccessMode::ReadWrite;
      }
      else if(isWaitingQueueEmpty(lockInfo))
      {
         OwnerCountForLockingUpgrateTrx ownerCounterTrx{ lockInfo };

         const auto requestResult = makeWaitingAccessorInfoThenWait(
               globalListLock,
               lockInfo,
               AccessMode::ReadWrite);
         if(AccessRequestResult::granted != requestResult)
            throw PossibleDeadlock{
                  "doAttemptToSwitchFromReadOnlyToReadWrite: "
                  "unable to upgrade ReadOnly lock to ReadWrite lock even "
                  "after waiting"
               };

         ownerCounterTrx.commit();
      }
      else
      {
         throw PossibleDeadlock{
               "doAttemptToSwitchFromReadOnlyToReadWrite: "
               "there is no possibility to upgrade ReadOnly lock "
               "to ReadWrite lock"
            };
      }
   }
   else
   {
      throw std::runtime_error{
            "doAttemptToSwitchFromReadOnlyToReadWrite: there is no "
            "information about objectToLock in the global lock list"
         };
   }
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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