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

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

DTO в python

Еще в древнем 2.6 были namedtuple:

from collections import namedtuple

Person = namedtuple("Person", "name age")
p = Person("Jeshua", 33)
print(p.name)

Они позволяли обращаться к полям по имени и были иммутабельными. Однако создание было не очень красивым.

Потом в 3.5 появились типы:

from typing import NamedTuple

class Person(NamedTuple):
  name: str
  age: int
p = Person("Jeshua", 33)
print(p.name)

Все то же самое, только запись поадекватнее, но это как-то пролетело мимо меня.

Наконец, в 3.7 появились dataclasses:

from dataclasses import dataclass

@dataclass(frozen = True)
class Person:
  name: str
  age: int

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

Ссылка

Хранение нескольких версий продукта в git

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

Однако доклад все равно полезный — в нем и кратенько про git и github flow рассказано, и проблема более-менее четко обозначена, и показаны варианты решения с плюсами и минусами.

Ссылка

Hello world на kotlin native

  1. Скачиваем релиз, распаковываем.
  2. Запускаем kotlinc-native -help:
Error occurred during initialization of VM
Could not reserve enough space for 3145728KB object heap
  1. Офигеваем от того, что этой штуке нужно 3 гига, запускаем с ограничением:
_JAVA_OPTIONS="-Xmx256M" kotlinc-native -help
  1. Делаем 1.kt с чем-то похожим на котлиновский код:
fun main() {
  println("https://t.me/minutkaprosvescheniya/120")
}
  1. Пробуем скомпилировать:
_JAVA_OPTIONS="-Xmx256M" kotlinc-native 1.kt -o 1
  1. Офигеваем от того, что надо скачать “немного” зависимостей — 600 мегабайт (в 2000-х за такое расстреляли бы).
  2. Офигеваем от того, что виртуалка у нас немного старая, i386, и kotlin-native поддерживается для arm32, win x86, watchOs x86, wasm32, MIPS, умных часов, но не для linux 32-bit, мол никому не надо — тебе надо, ты и делай.
  3. Повторяем шаги 1-6 для компа поновее.
  4. Офигеваем от того, что нельзя никак убрать расширение .kexe, потому что “это хороший способ идентифицировать файлы”.
  5. Запускаем ./1.kexe, получаем результат.
  6. Продолжаем офигевать от зрелости технологии.
Ссылка

Состояния процесса в linux

Когда-то давно я думал, что root всемогущ и может убить любой процесс. Однако если процесс находится в состоянии Uninterruptible Sleep (оно же D), то он может так конкретно повиснуть, что поможет только перезагрузка, о чем даже в отделе травили страшилки на вечер пятницы:) А происходит это из-за того, что процесс ждет I/O и на сигналы не реагирует. И если что-то пошло не так, то так он и будет висеть до следующей перезагрузки, несмотря ни на что (такое было на проде).

В новом дивном мире ты просто редеплоишь докер-контейнер в кубере, но на нем свет клином не сошелся.

Подробнее про состояние процессов можно почитать в статье.

Ссылка

Как тестировать работу с реляционной БД

Самые банальные варианты включают в себя:

  1. Тестирование на тестовом стенде (для особых извращенцев — на общем стенде, для супер-извращенцев — резервирование ресурса путем устных переговоров с коллегами, ну а у темных властелинов тестовый стенд — это прод).
  2. Тестирование с БД, которая разворачивается локально (возможно даже сама, возможно в докер-контейнере).
  3. Тестирование с in-memory аналогом.

С первым пунктом все понятно, а вот между другими двумя надо думать.

С одной стороны, завязываться на реализацию БД как-то странно, особенно с учетом того, что вряд ли к базе идет обращение напрямую, а не через ORM и/или DSL, и может еще и через liquibase. С другой — эти абстракции дырявые, и тот же liquibase поле с типом TEXT создаст как TEXT (он же VARCHAR) в Postgresql, но как CLOB в H2. Вдобавок, у различных СУБД есть свои “особенности”, от которых не всегда получится абстрагироваться — помню как года 4 назад во времена импортозамещения у меня пригорело от того, что Oracle не различает пустую строку и null. Вдобавок всякие статьи говорят о том, что не-не, нельзя делать unit-тесты c in-memory H2, если у вас на проде Postgresql, у вас прод сгорит и вообще мы все умрем.

В моем идеальном мире все СУБД и прослойки для общения с ними написаны нормально и такие проблемы не должны возникать. В чуть менее идеальном — эти отличия несущественные и легко проверяются интеграционными тестами, если надо поддерживать несколько СУБД, или влияют только на производительность, но не на интерфейсы/поведение.

Но этой заметки не было бы, если бы не потекшие абстракции: при обновлении H2 столкнулся с проблемой, что они решили кидать исключение про то, что не поддерживают индексы на CLOB поля (хотя раньше просто ничего не делали). И вот сошлись звезды в лице связки liquibase + H2, и несмотря на то, что никакие нестандартные вещи не использовались, все поломалось. Конкретно в этом кейсе удалось извернуться, но ситуация насторожила: получается, что SQL не такой уж и стандарт…

Ссылка

Полезные и не очень сайты для curl

Полезные:

  • https://httpbin.org/ — универсальная штука для отладки HTTP-клиента. Самый частый кейс у меня был curl https://httpbin.org/ip, но подойдет для кейсов, когда надо выяснить, что ваш клиент сует в данные кроме того, что сказали (например, какой user-agent).
  • https://restcountries.eu/ — выводит основные данные о стране: curl -s https://restcountries.eu/rest/v2/name/russia.

И среднего уровня бесполезности:

  • Погода: curl -s http://wttr.in
  • Зойдберг: curl zoidberg.live
  • Fuck off as a service, местами может заменить httpbin: curl 'https://www.foaas.com/zero' -H'Accept: application/json'
  • Ну и классика — Звездные Войны, можно сделать аналог самостоятельно: curl https://asciitv.fr
Ссылка

Mock и Wiremock

Сейчас довольно популярно тестирование с моками — объектами-заглушками, имитирующими реальное поведение чего-либо. Для любителей ФП звучит дико, конечно: зачем что-то имитировать для чистых функций?

К сожалению, не всегда все так радужно, и в ООП-шном коде с кучей DI, IoC и прочими SOLIDами для простого юнит-теста придется пол-графа зависимостей поднимать. Вот и получаются моки, которые по сути работают как перехватчики входов-выходов для нужного метода. А нормальные интеграционные тесты делать дорого и они существенно замедляют билд.

Добавьте сюда еще микросервисы и получится, что надо имитировать и проверять HTTP-вызовы. Появляется специальный web-сервер, вся задача которого — отдавать заранее заготовленный ответ на нужный вызов и записывать все обращения. В качестве примера можно привести WireMock. Хотя если такая штука нужна на 1 раз, то, имхо, гораздо проще взять первый попавшийся скрипт на питоне, поднимающий локальный HTTP, и вкорячить туда нужное, чем возиться с настройкой чего-то посложнее.

Ссылка

Покрытие тестами схем Camunda

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

Припудрю это своим нытьем про java.

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

Работа с коллекциями это вообще ад. Мало того, что все надо делать тупыми циклами, так еще и нет элементарных методов типа getOrDefault.

Конечно, если ОЧЕНЬ НАДО, то что-то написать можно. Но плакать и колоться так каждый день лично я не готов даже за большие деньги…

Ссылка

Нюансы sendmail

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

Работает это довольно просто — глобально настраивается почтовый сервер, а дальше отдаешь команду вроде

echo "hello" | sendmail general@kenobi.sw

И все, письмо ушло адресату. Звучит весьма клево, но внимательный читатель должен был триггернуться на “глобально”.

Недавно выяснилось, что сервер, где такое настроено, выжирает дневной лимит писем в 50к за сутки, хотя предполагаемая нагрузка — 10 писем в день. Виртуалка выключена админами, и в голове мечутся мысли: взломали? Но кому такое надо? Может, ПО, использующее sendmail, сошло с ума?

Однако после разбирательств выяснилось, что столько писем слал… cron. По умолчанию поведение системы такое, что любой stdout от него шлется пользователю на почту. Но на какую почту, ее же наверно надо задать? Разумеется, тут все предусмотрено: на почту user@host, и плевать, что она не существует. А как себя ведет себя с письмом на несуществующий адрес почтовый сервер? Правильно, пытается послать до посинения.

А надо было всего лишь отредактировать /etc/sysconfig/crond, чтобы отключить отправку на почту и включить редирект в syslog:

CRONDARGS=-s -m off

рестартнуть crond и почистить очередь:

exim -bp | exiqgrep -i | xargs exim -Mrm

Вы все еще любите глобальные настройки? Тогда мы идем к вам:)

Ссылка