суббота, 19 апреля 2025 г.

[prog.c++] Наткнулся на образчик кода из категории "Да не дай боже такое сопровождать!"

В очередной раз с трудом удерживаюсь, чтобы не ввязаться в публичное обсуждение на профильном ресурсе. В этот раз опять на RSDN ;)

Недавно там образовалась тема с самодельным аналогом std::format/fmt::format. Над происходящим в нёй я уже слегка поугорал в LinkedIn. Но т.к. автор сего велосипеда в излишне поучительном (на мой субъективный взгляд, конечно же) тоне выступает в другом треде, то решил краем глаза вглянуть на то, какой же код производит данный оратор. Ну по принципу talk is cheap, show me the code.

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

Как по мне, так подобное не что иное как говнокод. Говнокод как он есть. В чистом, дистиллированном виде.

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

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


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


Простите, дальше будет совсем грубо.

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

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

Но при этом этот работающий код оказывается откровенным говном. Как в примере выше.

Но работающим же.

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

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

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

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

среда, 16 апреля 2025 г.

[prog.thoughts] Реплика в блог: так ли плохо иметь в C++ отдельный класс для сетевого пакета?

Поскольку я зарекся вступать в публичные споры на LOR/RSDN/Habr, а в Интернете, как водится, кто-то неправ, то попробую разместить свою ремарку здесь, в уютненьком ;)

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

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

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

Представление данных -- это всего лишь конкретный механизм сериализации. Скажем, использование принципа TLV (Tag-Length-Value), как в ASN.1 BER. Или плотная побитовая упаковка как в ASN.1 PER. Или же тегированное текстовое представление, вроде JSON или XML (должны сдохнуть в муках оба, шутка).

Кусок кода, который привели в обсуждении на RSDN, он как раз про представление данных.

Тогда как есть еще одна важная часть, когда мы говорим о каких-то протоколах обмена данными -- это из каких сообщений (PDU -- protocol data unit) состоит сам обмен.

Типа того, что есть сообщение handshake и ответное сообщение handshake_ack. Есть сообщение subscribe и есть ответы sub_ack и sub_nack. Есть сообщение publish и есть ответные pub_ack и pub_nack, а также сопутствующее delivery_report. И т.д., и т.п.

Так вот, представление данных определяет то, как содержимое PDU сериализуется.

Но представление данных не есть удобный способ работать с самими PDU в коде.

Достаточно часто в наше время встречается ситуация, когда PDU представляется в виде JSON. Входящий пакет парсится, у нас в коде появляется что-то вроде nlohman::json или RapidJson::Value. И дальше программисты любятся с этими JSON-объектами как умеют. А умеют практически никак 😣 Например, если в PDU есть поле priority, то из JSON-объекта запрашивают это поле вручную по строковому имени. Если это поле нуждается в какой-то валидации (хоть при извлечении, хоть при сохранении), то это тоже делают вручную. Если делают.

Мне же думается, что работать с PDU в программе гораздо удобнее, когда PDU представляется в виде конкретного C++ного класса с нужными методами getter-/setter-ами. И когда в эти самые методы вставлена валидация значений. Более того, такие классы могут (и должны, когда есть возможность) проверять корректность значений при сериализации/десериализации. Например, если поле A в PDU имеет вот такое значение, то поле B не может быть пустым, а поле C, напротив, должно быть пустым.

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

Однажды в прошлом с чем-то таким столкнулся. Даже рассказывал об этом на RSDN и упоминал в блоге. То решение на Ruby оказалось удобным. Если доведется еще раз с подобной задачей, то буду смотреть в ту же сторону (не важно, Ruby будет использоваться для кодогенерации, Python или еще что-то). Хотя современный C++ в области шаблонной магии далеко ушел от C++03, но все равно не думаю, что подобная задача будет хорошо решаться в рамках C++20 или C++23.


PS. Еще раз по поводу кода, который показали на RSDN. Как раз тот случай, когда смотришь в код, внутренний голос спрашивает "а что так навороченно то, нельзя ли пропроще?", но без вдумчивого изучения ответа на этот вопрос нет. А вдумчиво изучать нет желания ;)


PPS. Мораль всего поста: не беритесь судить без глубокого погружения.

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

[prog] Похоже, у меня уже не получается писать код без комментариев

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

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

Изредка приходится делать маленькие (или не очень маленькие) программки "на выброс". Буквально на один-два проверочных запуска, после чего все написанное отправляется в корзину. Вот там, как правило, вообще никаких комментариев нет. Точнее не бывало. До недавних пор.

Как раз давеча пришлось такими маленькими программками заниматься.

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

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

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

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

PS. Неприятным побочным эффектом от привычки писать комментарии становится все возрастающая нетерпимость к коду без комментариев.

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

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

PPPPS. Есть у меня ощущение, что в последние 15 лет программистов-то и программировать уже не учат. Что уж тут говорить про обучение написанию комментариев 🥺 ИМХО, это один из китов, на которых покоится миф о самодокументирующемся коде.