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

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

Проверяемые исключения в Scala

В релизе 3.1.0 появилась интересная фича: проверяемые исключения. Да-да, как в java, но немного по-другому.

Во-первых, проверка не обязательная, а специально подключаемая в импортах. Оборачивать все в try-catch чисто ради удовлетворения компилятора не обязательно. Во-вторых, команда разработчиков попыталась хотя бы частично решить проблемы java-подхода.

Одна из основных проблем с непроверяемыми исключениями в том, что… их не проверяет компилятор, они вне системы типов. Поэтому некоторые упарываются и отказываются от исключений совсем, заворачивая все в монады. Это генерирует много новых проблем, например, вопрос композиции этих монад (куча паттернов типа Final Tagless или Free Monad и супермонады типа ZIO — это все варианты решения). Но код с исключениями легко писать и читать, да и “happy path” не несет накладных расходов.

В новой версии компилятор проверяет, что если в теле функции есть throw, то исключение прописано в сигнатуре. Внутри сахара — контекстные параметры, которые будут удалены после компиляции. Это как неявные параметры (implicit val) в scala 2. Т.е. если функция может кидать исключения, то она требует неявный параметр, который свидетельствует о том, что оно будет обработано. А генерится этот параметр уже в блоке try-catch.

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

UPD: Видос от Одерски по теме.

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

Плагины Camunda Modeler

Два самых полезных плагина, на мой взгляд — это отображение границ транзакций и линтер. Ставятся они тупо копированием в папку plugins в корне моделера.

Поскольку плагин — это код на javascript, то его можно легко изменить под свои нужны. Например, в плагине с транзакциями можно залезть в стили и сделать его поприятнее. А для линтера можно настроить правила или написать свои, даже заготовка для этого есть.

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

Линтер BPMN можно даже встроить как проверку в maven, но это то еще извращение.

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

Устранение шумов микрофона в Linux

Без понятия, почему это не включено по умолчанию, но хотя бы можно включить. В /etc/pulse/default.pa надо добавить

.ifexists module-echo-cancel.so
load-module module-echo-cancel aec_method=webrtc source_name=echocancel sink_name=echocancel1
set-default-source echocancel
set-default-sink echocancel1
.endif

И перезапустить PulseAudio (pulseaudio -k) или перезагрузиться. После этого в настройках звука появятся дополнительные входы/выходы с пометкой echo cancelled.

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

Судьба GIL в Python

Кажется, Python близок к тому, чтобы отказаться от GIL. Статью рекомендую к прочтению.

Одна из основных проблем GIL — сборщик мусора, а именно счетчики ссылок. Чтобы они работали корректно при конкурентном доступе, их можно заменить на атомарные, но это будет серьезным ударом по производительности — до 60%. Большинство программ на Python — однопоточные, и подобные расходы непозволительны.

Сэм Гросс, один из авторов PyTorch, предложил интересное решение этой проблемы на основе соответствующего исследования. У каждого объекта теперь два счетчика ссылок — локальный (для владельца) и глобальный (для остальных тредов). Первый счетчик — быстрый и неатомарный, потому что у владельца к нему эксклюзивный доступ, второй — атомарный, но к нему, скорее всего, будет гораздо меньше обращений, потому что большинство объектов локальные.

Локальный счетчик не совсем прост: два младших бита у него зарезервированы под флаги. Первый нужен для бессмертных объектов: True, False, None, -127..128 и т.п. — считать ссылки на них бесполезно, удалять их не нужно. Второй флаг используется для долгоживущих объектов вроде модулей и функций: они почти всегда попадают в globals или создают циклические ссылки. Проще пройтись сборщиком мусора и найти неиспользуемые.

Дополнительно Гросс оптимизировал кучу мелочей в интерпретаторе, и он стал быстрее на 10%. Похоже, что такими темпами можно будет увидеть Python4 :)

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

Поиск всех пулл-реквестов пользователя в GitHub

Чтобы посмотреть вклад в Open Source, можно зайти на https://github.com/pulls и убрать фильтр открытых:

is:pr author:ov7a

Однако может потребоваться фильтр по владельцу репозитория/организации, чтобы отсеять коммиты, за которые платят зарплату:

is:pr author:udalov -user:JetBrains -user:Kotlin
СсылкаКомментировать

Приостановка процесса

Чтобы приостановить работу какого-нибудь долгого процесса, можно отправить ему сигнал TSTP:

kill -TSTP [pid]

или, если он был проигнорирован — STOP:

kill -STOP [pid]

Продолжить процесс потом можно будет через сигнал CONT:

kill -CONT [pid]

Мне эти команды пригодились для временной остановки питонячего скрипта миграции данных, который “долго запрягает, но быстро едет”. Перезапуск потребовал бы ручной перенастройки (чтобы не повторять уже выполненные операции). Скрипт проигнорировал TSTP, а вот после STOP успешно приостановил свою работу.

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

Есть ли будущее у мутационного тестирования?

Интересная заметка про мутационное тестирование. Тезисно:

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

Большие запросы без пагинации и scroll'а в ElasticSearch

Параметр search_after позволяет выполнить последовательность запросов без использования пагинации (у которой есть ограничения на размер page*size, по умолчанию 10 000) и без использования scroll (который практически создает слепок индекса и жрет память). Идея довольно простая: использовать сортировку по какому-то полю, взять первые N результатов, а потом сделать запрос, в которого значение поля сортировки больше, чем у N-ного результата.

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

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

CQRS

CQRS (Command and Query Responsibility Segregation) — это очень простой принцип построения систем, который является продолжением CQS (сommand-query separation). Напомню, что CQS говорит о том, что всякий метод является либо командой, которая меняет данные, но ничего не возвращает, либо запросом, который возвращает данные, но не меняет их. А CQRS дополняет его, говоря о том, для обработки команд и обработки запросов используются разные сущности (например, сервисы).

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

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