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

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

Статическая типизация — не панацея

Что выведет этот кусочек кода на Kotlin?

fun main() {
    data class SomeClass(val someValue: Int)
    val someNull = null

    println(someNull + SomeClass(12))
}
Ответ

Выведет nullSomeClass(someValue=12). Почти как в JS:)

Все благодаря выводу типов: компилятор находит расширение operator fun String?.plus(other: Any?), вызывает у обоих аргументов toString() и склеивает их.

Хорошо хоть, узнал это не из продакшен-кода, а из познавательного видео, в котором мужик рассказывает про “переопределение” оператора сложения для nullable типов.

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

Экономьте газ

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

Однако есть ниша, в которой экономить элементарные операции все еще актуально — смарт-контракты. Каждое вычисление чего-то стоит. Например, в Etherium каждая операция смарт-контракта тратит немного “газа”, не уложился в лимит — транзакция откатывается. В периоды большой нагрузки на сеть газ стоит дороже, в периоды низкой, соответственно, дешевле. Если алгоритм оптимизирован, то на его выполнение будет потрачено меньше газа и, как следствие, меньше криптовалюты.

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

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

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

Буфер обмена с консольной виртуалкой

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

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

Оптимизация хэш-таблицы

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

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

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

Отладка Jenkins пайплайна

Чтобы быстрее отладить/доработать скрипт пайплана в jenkins, можно использовать:

  • Генератор кода http://${jenkinsHost}/pipeline-syntax, в котором можно накликать один из шагов из плагинов.
  • REPL http://${jenkinsHost}/script, чтобы проверить небольшие кусочки или какие-то моменты из Groovy. Недостаток — контекст немного отличается от пайплайна (запускается без песочницы), и код из REPL не всегда будет работать в пайплайне.
  • Список глобальных переменных и методов http://${jenkinsHost}/pipeline-syntax/globals, чтобы посмотреть, что доступно.
  • Скрипт для одобрения методов за пределами песочницы (если пришлось залезть в кишки), чтобы одобрять методы не по одному.
  • Replay билда + отключение шагов, которые можно пропустить, для более быстрой проверки работоспособности.
СсылкаКомментировать

Запуск нескольких целей в 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 — и тесты перестают работать.

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

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