Читать в телеге. Когда-то там были посты не только от меня.
Старейшая тудушка в коде
Ну уж в этом-то году точно все легаси уберем, да?
Чтобы найти старые TODO в репозитории (и, скорее всего, ужаснуться), можно использовать вот эту колбасу
git grep -i -nE 'TODO|FIXME|FIMXE' | while IFS=: read -r file lineno line; do commit_date=$(git blame -L "$lineno,$lineno" --porcelain "$file" | awk '/^author-time/ {print $2}' | { read epoch; date -u -d @$epoch "+%Y-%m-%d %H:%M:%S" 2>/dev/null || date -u -r $epoch "+%Y-%m-%d %H:%M:%S"; }); echo "$commit_date $file:$lineno: $line"; done | tee >(sort > todos.txt)
(результат будет в todos.txt)
P.S. Особым мазохизмом было получение кроссплатформенного варианта этой команды и выдрать нормальную дату из гита, потому что по умолчанию blame
выдавал не очень машиночитаемый формат.
"Кроссплатформенность" bash
Годами сидя на линуксе, особо не задумываешься об версиях баша и стандартных утилит: по умолчанию ожидаешь, что cp
и в Африке cp
, и думать тут много не надо.
Но как только надо написать какой-нибудь не очень тривиальный однострочник, чтобы добавить его в документацию и/или репозиторий, чтобы “работало” везде, сразу возникают проблемы. Например, у какого-нибудь sed
есть как минимум две версии: BSD (во фряхе и маках) и GNU (в большинстве линуксов), и они серьезно отличаются.
Казалось бы, есть POSIX-команды, можно врубить какой-нибудь режим совместимости и все будет пусть и безобразно, но единообразно, да? *падме.жпг* Реальность, разумеется, полна разочарований: так с большинством команд сделать не получится.
Например, GNU date -Is -ud @249499969321
— это BSD date -Iseconds -ur 249499969321
, и если seconds
тоже можно использовать в первом случае, то остальное уже не поменять.
Другой пример: в BSD sed
“на месте” должен быть явным, -i ""
, а в GNU должно быть именно -i
, без явной пустой строки. Обо всяких \b
тоже можно забыть.
Наконец, некоторые вещи можно обнаружить только методом проб и ошибок, например, strftime
в awk
.
Вишенка на торте: по умолчанию на маках стоит баш версии 3.2 аж от 2007 года (пусть даже ее постоянно патчат, функционально она застыла во времени).
В качестве обходного решения на маке можно… тупо поставить GNU-версии через brew
. В среднем по больнице они все равно лучше. Но если это невозможно, то очевидный вариант — обмазать скрипт if/else
с проверками на систему или переписать на питон. Еще один обходной путь: вызывать два варианта команды через ||
с учетом того, что неподходящий вариант отвалится с ошибкой.
Карта исторических границ
Сабж. Для важных переговоров™.
Дублирование ссылки в Markdown
Понадобилось в во внутренней доке вынести часть ссылок в начало документа, чтобы не искать их в тексте. Оказывается, у Markdown есть механизм для ссылки на ссылку! В любом месте документа (например в конце) добавляем название
[link_name]: https://ov7a.narod.ru/index-1.html
И потом используем в квадратных скобках сколько угодно:
Это [ссылка][link_name]. И [это][link_name] та же самая ссылка.
Версионирование
Де-факто стандарт для версионирования всяких библиотек и продуктов — семантическое версионирование. Идеи довольно простые, хотя и полный документ содержит немного душноты.
Браузеры со своими версиями за 300 и внутренние релизы некоторых компаний а-ля 0.192, годами крутящиеся на проде, передают пламенный привет:)
Оказывается, у этого подхода есть куча критиков: 1, 2, 3. Недостатки сводятся к следующему:
- Демагогия по поводу того, “а что такое ломающее изменение”, “а если это влияет только на 1% пользователей”, “а мелкое ли это изменение?”, “это не баг, а фича” и т.п.
- Не все следуют SemVer (sic!) (например, у них 0.x в проде).
- О ужас, SemVer не всем подходит!
- Одно число не может передать всей глубины изменений. На него нельзя полагаться при обновлениях, все равно надо читать список изменений.
- Если ваш продукт последний в цепочке (например, фронтенд-морда) — о боже мой, всем насрать какой он там версии. Это все очень сложно, простоиспользуйте одно число, как например браузеры.
- Частые обновления библиотек могут отпугнуть пользователей.
- Настоящим инженерам вообще версии не нужны — посмотрите на ранние UNIX-программы, они совершенны! Версионирование — это отмазка, чтобы ломать API.
- В большом дереве зависимостей изменение одной версии может привести к каскадному
резонансуизменению заметного числа зависимостей. - Инженеры боятся обновлять мажорную версию своей библиотеки, и откладывают внедрение фич. Иногда во имя маркетинга.
- Ради обратной совместимости приходится делать костыли.
На часть этих замечаний неплохо отвечает создатель спецификации (один из создателей GitHub кстати): не надо бояться увеличивать мажорную версию, не надо мешать маркетинг с техническими деталями, надо любить своих пользователей, предоставляя им средства для автоматических миграций, а ломающие изменения выдавать по чуть-чуть, а не огромными пачками.
В java-мире сейчас обсуждают подход Tip & Tail, который может сгладить некоторые моменты (при этом не противореча идее SemVer). По сути предлагается иметь два релиза: tip, с новейшими фичами и всем таким, и tail, в котором все будет максимально стабильно и меняться очень редко и только когда прям совсем надо (по сути, LTS).
Валидация HTML в консоли
На одной из страничек в легаси проекте всплыл косяк, что есть лишний закрывающий div
. Вроде очевидное решение — его надо убрать, но может можно как-то найти и предотвратить это в будущем? Конечно, для этого можно использовать какой-нибудь JS-фреймворк (какой там сейчас популярный?), но у меня же тупо страничка с шаблоном (или SSR, как сейчас (или уже раньше) было модно говорить). Нашел консольную утилиту — HTML tidy, вы только зацените кислотность сайта! Привлекло, что можно ее можно использовать в формате curl url | tidy
.
P.S. думал еще какой-нибудь плагин/расширение для браузера найти, но это тяжело в пайплайн встроить, и быстро ничего приличного не нашел (если кто шарит, поделитесь опытом).
Применимость AI в разработке
Годная статья про текущий уровень, где автор неплохо и довольно трезво оценил, как лучше сейчас использовать всяких “ассистентов” (демки/MVP, автодополнение, генерация черновых вариантов), какие есть проблемы (код надо проверять, уметь дебажить и думать о крайних случаях оказывается, ну и архитектура с безопасностью в помойке) и попытался посмотреть в будущее (автоматизация рутины, помощь в поиске идей, проактивные предложения ну, и, разумеется, “вкалывают роботы, а не человек!”).
Описанное в статье в целом соответствует моим впечатлениями (см. 1 и 2)
Работа с ошибками в Roc
Очередной доклад про работу с эффектами (на самом деле с обработкой ошибок). Не могу сказать что он супер или что в нем какая-то невероятно новая идея, но тут хорошо поставлена и разжевана проблема: почему напряжно обрабатывать ошибки разных видов.
Сама идея тегов, которые отслеживает и обрабатывает компилятор, занятная, но не думаю что она выстрелит. В скале более общий и фундаментальный поход, я рассказывал об этом ранее. Да и итоговое решение не сильно семантически отличается от первоначального подхода на Rust.
Другая идея, реализация конечного автомата для асинхронных вычислений, тоже не нова, и сильно напоминает котлиновские корутины. Реализована в функциональном стиле, но сюрпризов особо нет, и проблема “двухцветности” особо не решена, и вся машинерия торчит в коде.
Впрочем, автор и сам признает некоторые недостатки и часть идей на момент доклада не была реализована. Однако, если ни с одной идеей не знакомы, доклад довольно простой и доступный, и его можно посмотреть. Видос от создателя Roc и соавтора Elm, и прошлое автора чувствуется — торчат уши языков из этого семейства и сопутствующих идей. Но он неплохой докладчик — у меня в бложеке нашлась еще пара ссылок на его видео (1, 2).
Пик сложности
Давным-давно, когда я глотал фантастические книжки стопками, в одной из них была такая идея об уровнях развития цивилизации:
- Простые технологии/механизмы для решения простых задач (палка стукать).
- Сложные технологии/механизмы для решения сложных задач (двигатель внутреннего сгорания, атомная станция).
- Простые технологии/механизмы для решения сложных задач (это у более развитых цивилизаций, чем наша).
Было это в контексте того, что кто-то посмотрел на двигатель высокотехнологичного транспорта, а там внутри все просто и понятно, и элементарно починить.
Увы, я уже совсем не помню никаких метаданных о книге, и ни поиск, ни чатгпт не помогли (если вы вдруг знаете, откуда это — напишите, пожалуйста). Но сама идея намертво застряла и я ее постоянно кому-то рассказываю, потому что она очень хорошо подходит для разработки.
Похожие идеи про простоту всплывают повсеместно, взять хотя бы тот же KISS и его вариации). Но конкретно в этой интерпретации важен аспект эволюции и сравнения, как может быть по-другому. Увы, встречаются кодовые базы, когда используется 4 вариант, дополняющий остальные три: сложные технологии/механизмы для решения простых задач. Я не помню точно, но вряд ли фантаст мог помыслить об энтерпрайзном fizzbuzz, а я с таким работаю.
В тему эволюции подходов к решению задач есть неплохой доклад от архитекторов языка Java, основная идея которого заключается в том, что когда вы наконец рассмотрели задачу со всех сторон и учли все нюансы, надо потратить еще время, чтобы упростить решение. Автор предостерегает от того, чтобы развертывать первое решение, приводя в пример сериализацию в Java (которая очень сложная и имеет кучу проблем). Тут есть нюанс контекста: он рассуждает в контексте платформенного решения, на основе которого строятся другие, а свое уэб-приложение можно и перезалить. Но еще важный момент — отношение: “раз работает, то все, задача выполнена, да и бизнес давит” — так и рождается техдолг и/или переусложенное решение.
Недостатки закона Постела
Сам принцип звучит примерно так:
Будьте либеральны в том, что вы принимаете, и консервативны в том, что вы отправляете.
На поверхности звучит логично, и, пожалуй, он неплохо применим к пользовательскому вводу, однако в долгосрочной перспективе этот принцип скорее вредит. Даже в самой википедии есть критика, но подробнее и с примерами можно почитать в этой заметке, размещенной на сайте интернет-стандартов, в контексте которых и зародился принцип. А еще недавно появилась статья с еще одним наглядным примером про куки: сочная дичь, которая получилась как раз из-за недостаточной строгости.
Если вкратце обобщить источники выше:
- Если что-то “почти правильное” принималось без проблем, то оно может стать де-факто стандартом. Потом будут сюрпризы при использовании альтернативных реализаций, особенно если у них разный уровень толерантности к вводу. Похожая фигня случилась с URI/URL. Из-за этого возможно придется делать совместимость на уровне багов.
- Нечеткая интерпретация спецификации может привести к уязвимостям и другим проблемам безопасности.
- Толератность приводит к усложнению реализации: будут разные модели для ввода и вывода, ну и в целом надо будет поддерживать дополнительный код для исправления неточностей, количество которого потенциально может расти со временем для обеспечения взаимодействия с новыми реализациями.
- Многие упускают аспект, что этот принцип нужен для исправления недостатков спецификации, но часто есть возможность улучшить саму спецификацию.
- Если не глотать ошибки/недочеты, то их будет проще обнаружить, и будет обратная связь для протокола/спецификации.
- Работать обычно проще с меньшей вариативностью, KISS и все такое.