Выпуск 3 · подкаст «Тысяча фичей»

#3: Пакетный менеджер: Homebrew, self-review

12:42
↓ скачать mp3

Александр Пахомов делится практикой селф-ревью: как отстраниться от собственного кода и отревьюить свой pull request так, будто его прислал незнакомый человек. А затем разбирает Homebrew: почему в macOS нет родного пакетного менеджера, что такое формулы, кеги и краны, как написать собственную формулу — на примере базы данных Ignite 3 — и отправить её в homebrew-core.

Главное

  • Селф-ревью: прежде чем просить ревью у коллег, отревьюй свой pull request сам — глазами человека со стороны, который не писал ни строчки этого кода.
  • Отстраниться помогает пауза: отправить PR драфтом вечером и отревьюить утром со свежей головой — или закоммитить до обеда и посмотреть после.
  • Homebrew — «недостающий пакетный менеджер macOS»: из коробки его нет, потому что Apple продвигает App Store.
  • Терминология Homebrew — из пивоварения: формула (рецепт пакета на Ruby), кега, Cellar (/usr/local/Cellar), tap (git-репозиторий с формулами), bottle (предсобранный пакет), cask (GUI-приложения).
  • Homebrew — это программа на Ruby поверх git: формулы лежат в репозитории homebrew-core, а brew update — по сути git pull, поэтому его важно выполнять перед каждой установкой.
  • Своя формула: brew search — проверить имя, brew create <url> — создать Ruby-файл, описать метод install на DSL и отправить pull request в homebrew-core; open-source с адекватной лицензией обычно принимают.
  • Доставка обновления — это просто pull request с новой ссылкой на дистрибутив и обновлённой чек-суммой.
  • Если в основной репозиторий нельзя — создайте собственный tap: пользователи подключат его командой brew tap.
Расшифровка

[00:21] Меня зовут Саша Пахомов, и я инженер, который любит своё дело. Это третий выпуск подкаста «Тысяча фичей» — в нём я делюсь с вами интересными концепциями, подходами и мыслями, а иногда пытаюсь разобраться, как устроены сложные штуки. Сегодня мы попробуем понять, как работает самый популярный пакетный менеджер в macOS — Homebrew: насколько сложно самому написать формулу и как выглядит процесс добавления пакета в основной репозиторий. Но вначале поделюсь практикой, которую я использую почти каждый день. Называется она по-русски «сделай ревью себе сам», или просто селф-ревью. Поехали!

[01:09] Бывало ли у вас такое: открываете pull-реквест, пытаетесь сделать ревью — и совершенно не понимаете, о чём этот реквест и какую проблему он решает? У меня такое случается периодически. А бывало, что приходилось просить исправить совсем странные ошибки — забытые переносы строк в конце файла или коммит-месседж с опечатками? Кстати, если вы не слушали предыдущий выпуск про коммит-месседжи — обязательно послушайте. Возникал ли у вас во время ревью вопрос: «Чувак, а ты свой пиар сам-то смотрел, прежде чем мне отправлять?» Это отличный вопрос, который я задаю себе каждый раз, когда отправляю свой pull request кому-то на ревью.

[01:50] Идея понятна: поревьюй свой код сам, прежде чем запрашивать ревью со стороны. Но она не так проста, как кажется. Когда код только написан и у автора ещё свежи причинно-следственные связи, ревью выглядит примерно так: «Ага, ну тут понятно, тут мы закешировали, тут проитерировались, вот тут рефакторинг давно напрашивался — хорошо, что сделал». Такое ревью особой ценности не несёт. Основной челлендж селф-ревью — отстраниться от кода как автор и стать человеком со стороны, который ни строчки этого кода не написал. Задача человека со стороны — понять, что происходит и зачем, и оставить комментарии там, где есть место для улучшения. Звучит просто, но на деле это сложно — нормальное ментальное упражнение, которое может не получиться с первого раза.

[02:43] Вот как это делаю я. Если сроки не горят, я отправляю pull request, допустим, вечером и помечаю его как драфт — в GitHub такая возможность есть. Затем иду заниматься своими вечерними делами и ложусь спать — одним словом, пытаюсь забыть свой код. Утром со свежей головой я сажусь и наряду с другими pull-реквестами ревьюлю свой — так, будто мне его прислал человек, которого я вижу впервые. И тут столько интересного можно о себе узнать! Можно удивиться, почему pull request без описания. Почему он такой большой — его же сложно ревьюить. А где тесты? А где документация? Автор-то норм вообще? Ну, вы поняли. Все эти вопросы и пометки я собираю в туду-список и фикшу — либо завожу тикеты, добавляю ссылки на них в код, оформляю как технический долг, дописываю тесты. В общем, прохожу нулевой раунд ревью. И только после этого можно убрать статус драфт и попросить коллег или комьюнити сделать ревью. Всё это можно сделать и сразу, не на следующий день, — но мне так проще. А если задачу нужно было залить ещё вчера и времени на «забывание» кода меньше — я делаю коммит перед обедом, а после обеда его ревьюлю. Тоже рабочая схема. Вот такой лайфхак: если им будет пользоваться больше людей, код станет чище, а ревьюить его будет приятнее.

[04:14] Ну а теперь, как и обещал, давайте разберёмся, как устроен Homebrew. Для начала — зачем вообще пакетный менеджер? Ведь на маке есть App Store, да и если приложения там нет, всегда можно скачать пакет через браузер и установить. Но пакетный менеджер — это, во-первых, удобно: вы знаете, что и где установлено, как это обновлять и как удалять. У всех Unix-систем пакетные менеджеры есть: APT у Debian, YUM или DNF у CentOS и Fedora. Homebrew, кстати, позиционирует себя как «тот самый недостающий пакетный менеджер для macOS»: из коробки в macOS его нет, потому что Apple продвигает App Store, и развитие пакетного менеджера ей неинтересно.

[05:01] Теперь немного терминологии. Homebrew — по-русски «домашняя пивоварня» — это система управления пакетами для macOS и Linux с открытым исходным кодом. Формула — «рецепт» — описание пакета, написанное на Ruby; основная сущность Homebrew. Keg — «кега», бочонок — префикс пути файловой системы, связанный с формулой: по дефолту это /usr/local/Cellar/<имя пакета>. Cellar — «подвал» — путь, куда устанавливаются все кеги: в нашем случае /usr/local/Cellar. Tap — «кран» — git-репозиторий с формулами; большинство лежит в репозитории homebrew-core. Bottle — собранная версия кеги: пакет не нужно собирать из сорцов, можно взять предсобранный. Cask — «бочка» — расширение Homebrew для установки нативных GUI-приложений на macOS. Думаю, вы заметили, что вся терминология — из пивоварения: рецепт, кега, подвал, кран. И наверняка интересно, почему в таком популярном продукте выбрана пивная тема. Так вот — автор не закладывал особого смысла в название и не думал, что продукт станет настолько популярным. Хотя в Википедии есть смысловое объяснение: каждый пользователь может приготовить собственный пакет на свой вкус — так же, как пивовар может сварить пиво для себя. Звучит логично.

[06:29] С терминологией познакомились — посмотрим, как выглядит установка обычного пакета. Чтобы установить софт, доступный в Homebrew, достаточно выполнить две команды: brew update и brew install. Вот, собственно, и всё. Технически Homebrew — это программа на Ruby, которая использует git для хранения информации: все данные о пакетах лежат в git-репозитории самого Homebrew под названием homebrew-core. Авторы пакетов — или, в терминологии Homebrew, формул — отправляют код формул в центральный репозиторий, и как только он оказывается в мастер-ветке, формула становится доступна всем пользователям. А так как для хранения используется git, для получения последней версии данных нужно выполнить git pull — именно это и делает команда brew update. Поэтому её так важно выполнять до установки или обновления любого пакета — иначе локальное состояние репозитория будет отличаться от актуального.

[07:44] С установкой разобрались, но было бы странно делать подкаст про две команды — поэтому давайте поймём, как выглядит процесс добавления собственной формулы. Допустим, я разработчик, который хочет распространять свою программу через Homebrew. Для этого мне нужен макбук — по-хорошему, конечно, но и виртуальная машина подойдёт — с установленным brew. Первое, что я выполняю, — brew search <имя пакета>: команда покажет, существует ли уже пакет с таким именем (тогда стоит выбрать другое). Если такого пакета нет, идём дальше. Если речь про Java-приложение, у меня, скорее всего, уже есть дистрибутив в виде zip-архива — поэтому я выполняю brew create <url до архива>. Команда создаёт локальный Ruby-файл — формулу. В ней я пишу инструкции по установке. Стандартная формула содержит описание пакета, url домашней страницы, url на zip- или tar-архив, SHA-256 чек-сумму, лицензию, метод install и метод test. Самый важный, естественно, install: в нём на Ruby DSL, который предоставляет родительский класс формулы, нужно описать, какие файлы в какие директории мы устанавливаем. Установка софта бывает сложной, но большинство формул выглядят тривиально: исполняемые файлы кладутся в bin-директорию кеги; если это Java — JAR-ники в lib, конфигурация в etc.

[09:10] На словах просто, но на деле бывает и не так. Я вот сейчас пишу формулы для базы данных Ignite 3 — что, собственно, и сподвигло меня на этот выпуск. Там пришлось немного поплясать с бубном, чтобы всё работало как надо: возникли вопросы, куда писать логи и как их настроить, где хранить файлы данных, что с bash-комплишенами для CLI и так далее. Но примеров в homebrew-core более чем достаточно, так что, будучи полным нулём в Ruby, написать скрипт установки оказалось несложно.

[09:39] Итак, формула готова: мы её написали, локально протестировали, brew install работает. Что дальше? А дальше всё просто: делаем fork репозитория homebrew-core и отправляем туда pull request с формулой. Как правило, если ваш продукт open-source и у него адекватная, не проприетарная лицензия, request примут — и формула станет доступна для скачивания. Как доставляются обновления? Чтобы доставить пользователю новую версию, нужно, во-первых, чтобы она была доступна для скачивания, а во-вторых — сделать pull request с новой ссылкой на дистрибутив и обновлённой чек-суммой. Всё, пользователи могут обновляться.

[10:21] И напоследок пара интересных дополнений. Первое: система собирает данные пользователей через Google-аналитику. От этого можно отказаться и даже посмотреть, что конкретно собирают, — в основном количество скачиваний. Особой проблемы я в этом не вижу: им же нужно понимать, какие формулы популярнее и какие pull-реквесты вливать быстрее. Второе: если по каким-то причинам вы не можете отправить формулу в homebrew-core, спокойно создавайте собственный репозиторий и подключайте его командой brew tap — вашим пользователям перед установкой нужно будет выполнить ту же команду brew tap <имя репозитория>.

[11:06] На этом знакомство с Homebrew закончено — спасибо, что дослушали. В конце у меня подготовлен небольшой мотивейшн-спич. Огромное количество людей сейчас оказались не дома, и я в том числе. Единственное, что у нас есть, — это наши навыки и знания: лишь они помогают адаптироваться в сложной ситуации и помогать адаптироваться другим. Не забывайте прокачивать себя каждый день, чтобы сохранить кукуху в норме. Меня спасают подкаст и книги, одной из которых хочу поделиться — та самая книга с кабанчиком. Если вдруг ещё не прочитали — крайне советую. А чтобы не быть банальным (её советовали все, кто мог), вот вам бонус: плейлист на YouTube от автора книги, называется Distributed Systems. По сути, это дублирование книги в видеоформате — отлично подойдёт и тем, кто читал, для освежения памяти, и тем, кто не читал, как дополнение: прочитал главу — посмотрел видосик. Кстати, если вам интересна тема распределённых систем — пишите в комментариях к выпуску в Telegram или Apple Podcasts. И не забывайте оставлять отзывы — они помогают делать подкаст лучше. Ну а на этом всё. Услышимся!