Читать в телеге. Когда-то там были посты не только от меня.
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
- Скачиваем релиз, распаковываем.
- Запускаем
kotlinc-native -help
:
Error occurred during initialization of VM
Could not reserve enough space for 3145728KB object heap
- Офигеваем от того, что этой штуке нужно 3 гига, запускаем с ограничением:
_JAVA_OPTIONS="-Xmx256M" kotlinc-native -help
- Делаем 1.kt с чем-то похожим на котлиновский код:
fun main() {
println("https://t.me/minutkaprosvescheniya/120")
}
- Пробуем скомпилировать:
_JAVA_OPTIONS="-Xmx256M" kotlinc-native 1.kt -o 1
- Офигеваем от того, что надо скачать “немного” зависимостей — 600 мегабайт (в 2000-х за такое расстреляли бы).
- Офигеваем от того, что виртуалка у нас немного старая, i386, и kotlin-native поддерживается для arm32, win x86, watchOs x86, wasm32, MIPS, умных часов, но не для linux 32-bit, мол никому не надо — тебе надо, ты и делай.
- Повторяем шаги 1-6 для компа поновее.
- Офигеваем от того, что нельзя никак убрать расширение
.kexe
, потому что “это хороший способ идентифицировать файлы”. - Запускаем
./1.kexe
, получаем результат. - Продолжаем офигевать от зрелости технологии.
Состояния процесса в linux
Когда-то давно я думал, что root
всемогущ и может убить любой процесс. Однако если процесс находится в состоянии Uninterruptible Sleep (оно же D), то он может так конкретно повиснуть, что поможет только перезагрузка, о чем даже в отделе травили страшилки на вечер пятницы:) А происходит это из-за того, что процесс ждет I/O и на сигналы не реагирует. И если что-то пошло не так, то так он и будет висеть до следующей перезагрузки, несмотря ни на что (такое было на проде).
В новом дивном мире ты просто редеплоишь докер-контейнер в кубере, но на нем свет клином не сошелся.
Подробнее про состояние процессов можно почитать в статье.
Как тестировать работу с реляционной БД
Самые банальные варианты включают в себя:
- Тестирование на тестовом стенде (для особых извращенцев — на общем стенде, для супер-извращенцев — резервирование ресурса путем устных переговоров с коллегами, ну а у темных властелинов тестовый стенд — это прод).
- Тестирование с БД, которая разворачивается локально (возможно даже сама, возможно в докер-контейнере).
- Тестирование с 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, и вкорячить туда нужное, чем возиться с настройкой чего-то посложнее.
Пагинация в SQL
Годная статья про пагинацию в SQL, где рассказано про варианты ее реализации. С алгоритмической сложностью!
Покрытие тестами схем 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
Вы все еще любите глобальные настройки? Тогда мы идем к вам:)