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

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

Выбор коммита для добавления изменений в git

Одна из устоявшихся практик добавления изменений — rebase + fast-forward. Часто со схлопыванием всех коммитов в один жирный. История конечно получается красивая и это просто, но сваливать в одну кучу бизнес-изменения и рефакторинг — так себе затея, атомарные коммиты все-таки не зря придумали.

Но тогда после очередного rebase на основную ветку может возникнуть проблема, когда ваши красивые коммиты перестают компилироваться (например, кто-то тоже порефакторил от души). И после этого делать коммит fix after rebase или лепить все исправления в последний коммит через --amend как-то уныло. В этом случае поможет --fixup:

git add someChangedFiles
git commit --fixup=OLD_COMMIT_HASH
git rebase --interactive --autosquash OLD_COMMIT_HASH^

который позволяет добавлять изменения в существующий коммит, даже если он не последний.

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

Порядок просмотра файлов при код-ревью

Довольно интересное исследование показало:

  1. Большинство разработчиков ревьюят изменения тупо по порядку следования файлов (и обычно это алфавитный).
  2. Тесты комментируют реже, их качество обычно меньше волнует разрабов.
  3. Если тесты ревьюить после основного кода (как это обычно происходит, потому что t — в конце алфавита), то в них реже находят баги (для основного кода существенной разницы нет).
  4. Больше всего комментариев оставляют к первым файлам в списке, и баги в них обнаруживают с большей вероятностью.

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

Добавлю, что еще в далекие года ведущие эксперты™ писали в своем супер-мануале про порядок просмотра при ревью: тикет, тесты, код, тесты. Потому что на ревью важнее выявлять фундаментальные проблемы: неправильные требования, сделано не то, работает не как надо и т.п. И уже во вторую очередь идут ошибки в реализации. А для всякого форматирования и прочей мелочевки должен быть линтер, а не человек.

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

Ковариантность и контравариантность

У меня всегда были трудности с запоминанием умных терминов, хотя суть вариантности довольно проста. Если иерархия типов сохраняется в том же порядке для производных типов (которые используют искомый тип как параметр), то это (ко)вариатность. Если идет в обратном порядке — (контра)вариантность. Если нет иерархии — (ин)вариантность.

Если термины из теории категорий — “сложна”, то можно мыслить в терминах потребитель/производитель, в Kotlin и C# параметры так пишут — in и out вместо всяких плюс-минусов, и это гораздо читаемее.

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

Вариации сна для компьютера

  1. Бездействие (aka S1, idle) — CPU остановлен, система потребляет чуть меньше энергии: почти все устройства переключены в режим низкого энергопотребления или выключаются (ЖД, подсветка экрана).
  2. Сон (aka S2) — как S1, только CPU отключен от питания (разница с S1 минимальна, на некоторых материнских платах его даже не реализовывают).
  3. Ждущий режим (aka S3, sleep, suspend) — почти все устройства, кроме RAM отключены, состояние хранится в памяти. RAM обновляется медленнее. Жрет питание/батарею, но чуть-чуть.
  4. Гибернация (aka S4, hibernate) — состояние сохраняется на диск (например, в swap), питание полностью отключается. Однако не все оборудование корректно может восстановить свое состояние, поэтому этот режим обычно отключен по умолчанию.
  5. Мягкое выключение (aka S5, soft off) — все выключено, но некоторые порты/контроллеры включены (чтобы включить комп по LAN или по нажатию кнопки на клавиатуре, например).
  6. Гибридная гибернация (aka hybrid suspend) — состояние сохраняется на диск, как в гибернации, а потом комп переводится в ждущий режим. Позволяет быстрее выходить из сна, но не терять состояние, если питание пропадет. Есть еще вариация, когда сначала выполняется suspend, а потом, по таймеру или по триггеру (например, низкий заряд батареи) кратенько просыпается и уходит в гибернацию.
  7. Modern Standby (aka S0 low power idle, S0ix) и PowerNap — маркетинговые названия для S0 (полностью работающий комп), просто часть функций системы не работают и часть периферии отключена. Но при этом выполняются фоновые задачи и остается подключение к сети (“как у смартфона”). Питание потребляет много, и ноутбук в таком режиме в сумку класть не стоит — может перегреться.
СсылкаКомментировать

Псевдонимы для типов и value-классы

Почти бесплатно повысить читаемость кода можно за счет псевдонимов типов (type aliases). Например, можно заменить в бизнес-логике безликий UUID на UserId. Есть это почти во всех языках: typedef или даже #define в С, using в C++ и C#, type alias в Kotlin, type в Scala/Haskell и даже в питоне, но не в Java. Можно еще использовать локально: импортировать тип с другим именем. Но у псевдонимов есть банальный недостаток: ничто не помешает в UserId запихать другой UUID, например ObjectId.

Чтобы компилятор проверял подобные несоответствия, можно использовать value-типы (они же Single case discriminated union). Обычно это класс-обертка над целевым типом, который имеет единственное поле и при возможности заменяется после компиляции на целевой тип. Например, в Kotlin это будет

@JvmInline
value class UserId(val value: UUID)

В некоторых языках еще можно добавить логику (например, проверку в init блоке или добавить методы-геттеры). Если value-типов нет, можно достичь примерно того же, используя data-классы с одним полем (а где-то может и вообще разницы не будет).

Очевидная проблема оберток в том, что к содержимому всегда придется обращаться через поле или паттерн-матчинг, а не напрямую (и какой-нибудь делегацией это, увы, не решается). А из-за потенциального оборачивания страдают библиотеки, использующие рефлексию, например, сериализация в JSON. В Scala это решили с помощью opaque-типов: рядом с объявлением класса он работает прозрачно, как type alias, а снаружи — непрозрачно, и доступа к целевому типу нет. При этом там есть и “обычные” value-классы, которые почти такие же, как в Kotlin.

А еще и в Scala и в Kotlin ждут Project Valhalla, чтобы можно было создавать пользовательские типы, доступ к которым осуществляется по значению, а не по ссылке. В комбинации с inline это позволит решить часть проблем с оборачиванием value-типов.

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

Help me, step-container, I'm stuck!

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

docker commit %container_id% %some_name%

и стартовать его с командной строкой:

docker run -it %some_name% /bin/sh

А потом уже дебажить, что там внутри не так.

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

Из-за чего команда профессионалов может работать фигово

В продолжение заметки про продуктивность — а почему в команде из кучи замотивированных сеньоров все равно может получиться что-то не то?

Причин может может быть масса [1, 2, 3]:

  1. Они делают не то, что важно (в т.ч. из-за того, что увлекаются чем-то интересным для себя), часто из-за отсутствия четких целей, отсутствует фокус или пытаются сделать все и сразу.
  2. Они ждут другую команду (из-за плохого разделения, из-за мутных процессов или из-за чрезмерной специализации, когда не можешь помочь другой команде).
  3. Нет четкого понимания, что нужно сделать, тратится время на выяснение этого (хорошо еще, если до разработки, плохо, если на миллионе встреч).
  4. Нет четких зон ответственности и ролей — непонятно, кто должен что сделать, чаще всего превращается в “не делает никто”. В том числе когда что-то можно было предотвратить малой кровью вместо героического расхлебывания последствий.
  5. Они не умеют говорить “нет”.
  6. Нет долговременного планирования, слишком большая сосредоточенность на скорости, а не качестве.
  7. Они плохо понимают предметную область и конечного потребителя.
  8. Нет признания результатов, чувства достижения, мотивация делать нормально падает, появляется куча новых проблем.
СсылкаКомментировать

Визуализация explain для SQL-запроса и рекомендации по индексам

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

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

Docker на Маке

brew install docker поставит только клиенты докера, без демона. docker-machine, который запускает докер в виртуалке (sic!), уже устарел и его хрен запустишь. Docker Desktop платный (ну, на честном слове платный, но все же) и требует GUI…

В итоге рабочий вариантом оказалась… установка кубера, а именно minikube. Можно еще туннелирование в локальную сеть настроить или поиграться с kubectl. Но после таких приколов хотя бы понимаешь, почему некоторые считают, что надо минимум 32 гига оперативки для разработки на маке :/

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

Даты изобретения сортировок и кроссбаузерность

После изучения всяких фронтенд штук захотелось сделать что-нибудь очень простое. Прям наговнякать. Решил сделать временную шкалу с датами изобретения алгоритмов сортировки на CSS, и собирать HTML на голом питоне.

Во-первых, я все еще офигеваю, как сложно сделать какие-то элементарные вещи. Во-вторых, что до сих пор в трех разных браузерах одно и то же форматируется по-разному, хотя я использую все из древних стандартов. Я честно пытался написать кросс-браузерно, но в итоге мне это надоело и я сделал браузеро-зависимый CSS на основе всяких трюков. Отправляйте пулл-реквест, если умеете верстать или хотите попытать силы :)

Наконец, самой тяжелой частью оказались собственно данные. Нашел статью, где вроде есть все, что нужно, но качество данных там просто впечатляющее. Например, в качестве авторов Stooge Sort указаны “Prof. Howard Fine and Howard”. А на самом деле она фигурирует в упражнении из Кормена: “Professors Howard, Fine, and Howard have proposed the following “elegant” sorting algorithm…” — и является отсылкой на комедийный коллектив. Изначально в планах было найти оригинальные источники для каждой сортировки, но это оказалось нетривиальной задачей, поэтому я отложил это до лучших времен.

Демка тут.

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