Минутка просвещения

Читать в телеге. Когда-то там были посты не только от меня.

Запуск нескольких целей в Maven

С помощью defaultGoal и профиля можно запускать несколько фаз или целей:

<profile>
  <id>some-profile</id>
  <build>
    <defaultGoal>
      test
      a.group:an.artifact:some-plugin:goal@custom-goal-config
    </defaultGoal>
...

При такой настройке mvn -Psome-profile будет эквивалентен mvn test a.group:an.artifact:some-plugin:goal@custom-goal-config. Это удобно для разделения этапов в пайплайне (и когда есть конфигурации для целей). Мне пригодилось для получения агрегированного результата покрытия после параллельного выполнения тестов.

СсылкаКомментировать

Проектирование API

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

Интересно в этом докладе то, что докладчик — автор книги Effective Java, той самой, которую очень любили создатели Kotlin, и откуда пошли многие (в том числе спорные) решения в языке. Забавно, что некоторые API java и Гугла (где работал автор) советам, изложенным в докладе, явно не соответствуют.

СсылкаКомментировать

Конвертер видео

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

ffmpeg -i video.mp4 -ab 320k audio.mp3
СсылкаКомментировать

Хрупкие аннотации Spring

Одна из самых бесючих проблем в Spring — это то, что одной аннотацией можно неочевидно сломать работающий код.

Например, добавление @ComponentScan превратит в тыкву @WebMvcTest.

@Transactional может сломать любой сервис без интерфейса, причем в лучшем случае будет NoSuchBeanDefinitionException, а в худшем, а в худшем, если класс-потребитель не финальный, то будет тупо null вместо бина.

Поставил @TestExecutionListeners без mergeMode = MERGE_WITH_DEFAULTS — и тесты перестают работать.

И подобных примеров еще массу можно напридумывать:(

СсылкаКомментировать

Связи в проекте и Github Action

Очевидно, что связи между артефактами в проекте очень полезны. Код привязан к коммиту, коммит — к тикету и код-ревью/пулл-реквесту, тикет к ТЗ/эпику/истории и/или документации. Причем хорошо, когда эти связи еще и двусторонние: например, чтобы по коду можно посмотреть тикет и зачем он был написан, а по тикету — написанный код. Иначе при смене процесса придется искать эти связи вручную или не напрямую. Кажется, это одна из “продающих” фишек Gitlab или Space.

Мне не хватало связи пулл-реквеста GitHub с тикетом, существующие варианты action’ов показались унылыми, поэтому я написал свой, старался сделать его максимально универсальным.

К сожалению, для написания action’ов есть только два варианта: nodejs или docker-образ. Я по глупости выбрал первый вариант, потому что большинство action’ов были написаны на нем, да и библиотека для работы с GitHub была только для JS. В очередной раз вляпался в экосистему nodejs: обновление npm через него самого сделало его непригодным для использования. Куча пулл-реквестов от Dependabot — это мрак, группировки обновлений нет годами.

TypeScript вроде мощный и классный, можно выражения в шаблонах считать, но нет каких-то банальных вещей вроде безопасного enum или filterNotNull. Но мне понравились линтеры и форматтеры — благодаря им исправилась половина моих ошибок.

Сама библиотека для работы с GitHub сильно разочаровала. Хочешь получить текст коммита в пулл-реквесте? Запрашивай через API. Хочешь имя ветки? Используй окружение или костыли. Конфигурация в yaml, но параметры только строчные. Наконец, добила возможность гонок: все работы из action’ов запускаются параллельно, а контекст запуска статичный, поэтому пришлось менять получение тела из контекста на запрос к API.

СсылкаКомментировать

Что говорит наука о разработке?

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

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

В другом исследовании выяснили, что в говнокоде больше вероятность наличия багов, но при этом его переписывание не коррелирует со снижением числа багов. Еще было исследование исходников кучи проектов на GitHub с результатом, что программы на ФЯП имели меньше багов, чем программы на императивных языках, а на языках с автоматическим управлением памятью — меньше, чем на языках с ручным управлением и т.п. (что вроде очевидно). Однако последующее исследование показало ошибку в методике, а с ее учетом выяснилось, что ни у одного языка нет преимуществ относительно другого. Похожие проблемы были при исследовании TDD, систем типов, парного программирования.

Но есть и вещи, которые более-менее подтверждаются наукой. Эмпирически доказано, что устройство организации сильно влияет на устройство кода. Многие самые дорогие баги — это проблемы архитектуры или требований. Практика, которая работает — код-ревью, она позволяет ловить 60-80% багов. А еще одни из самых существенных факторов для качественной разработки (да и любой работы в целом) — это отсутствие стресса и хороший сон. Бессонная ночь = -50% к производительности. Кранчи делают итоговый продукт хуже по всем метрикам.

Ссылки на статьи из доклада можно найти тут.

СсылкаКомментировать

Насколько уникален UUID?

Напомню, что UUID — это идентификатор вида ac2c6d9a-68d0-4802-948b-da8cc594ac80, который содержит 16 байт или 128 бит. При этом в 4 версии из этих 128 бит только 122 случайны (и генерируются обычно хорошим генератором случайных чисел), остальные 6 — это 4 для номера версии и 2 зарезервированных бита.

Чтобы оценить вероятность совпадения, можно воспользоваться формулой для “парадокса” дней рождения, а именно ее приближением:

p(n, b) =  1 - e^(-n(n-1)/2^(b+1)))

где n — количество сгенерированных элементов, а b — количество случайных бит (2^b — количество вариантов).

Дальше надо прикинуть, сколько будет UUID в системе. Пусть нагрузка на систему — 1000 RPS, и при каждом запросе генерируется новый UUID. Тогда за 1000 лет будет сгенерировано всего 31,5 триллиона идентификаторов, а вероятность, что будет пара одинаковых — всего 9*10^-11, чем можно спокойно пренебречь.

СсылкаКомментировать

Круглые скобки в Scala

Иногда слышу в качестве одной из претензий к Scala “почему для получения элемента из ассоциативного массива используют круглые скобки?”. В одном из докладов услышал интересную гипотезу на эту тему.

Что такое “map”? Вообще это карта, и имеет происхождение от латинского “mappa mundi” — “лист мира”. Если заглянуть в словарь поглубже, то там будет упомянуто еще математическое значение — синоним “mapping”, отображения [из одного множества в другое], что большинстве случаев можно считать синонимом функции.

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

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

СсылкаКомментировать

Action для коммита в другой репозиторий

У меня на сайте сейчас два способа подключения чего-то стороннего: через git read-tree и через git submodule. Теперь появился еще один: через github action, который пушит коммит в другой репозиторий. Этот вариант оказался самым удобным, жаль, что я на него наткнулся недавно и случайно.

Пример настройки и сгенерированный коммит.

СсылкаКомментировать