Перейти к содержимому

В 2023 я начал gchGo CLI Helper, монолитную утилиту со всем, что мне регулярно нужно: генератор паролей, генератор лицензии, сокращатель ссылок, поиск дубликатов JPG и PNG в каталоге, заготовка для разбора инцидента. За это время туда наросли команды вокруг SRE-артефактов — постмортемы, RFC, runbook’и, SLO-документы, отчёты по дежурству, — и gch начал распухать: разные команды путали друг друга. В 2026 я выделил генераторы в отдельный srekit, оставив gch для повседневной мелочи. Это типичный путь личного набора инструментов: один монолит, потом специализация, потом разделение. Этот лист — про самый дешёвый уровень автоматизации: алиасы, функции в shell и маленькие утилиты, которые один человек собирает под себя за годы. Цена входа околонулевая, отдача мгновенная, но у набора есть жизненный цикл: он копит технический долг, требует чистки и переезжает между машинами через dotfiles. Сосед Toil Automation — про то же на уровне команды; здесь — на уровне одного человека. Граница неточная (хороший личный инструмент становится командным и наоборот), но фокус разный.

Главный навык на уровне L4 — понять, что алиаса уже мало и пора писать утилиту. Алиас или функция выгодны для одной-двух простых команд с фиксированными аргументами; отдельная утилита оправдана, когда появляются подкоманды, разбор флагов, автодополнение и документация. Я регулярно вижу две крайности: инженер держит двухсотстрочную функцию на bash с ветвлениями и вложенными условиями (это уже пора переписать на Go или Python) — или пишет полноценную утилиту на cobra ради однострочника, что тоже перебор. Правило простое: как только у функции появились подкоманды, флаги и коды возврата, она стала программой, и оформлять её надо как программу.

L3

  • Ведёт свои dotfiles в git (.zshrc, .bashrc, .config/nvim, .config/tmux и прочее); разворачивает своё окружение на новой машине одной командой.
  • Знает базовый набор: fzf, ripgrep, fd, jq, yq; умеет собирать их в цепочки через конвейер.
  • Использует Taskfile или Makefile в своих проектах, чтобы команды сборки не приходилось вспоминать.

L4

  • Пишет небольшие утилиты на Go, Python или Rust под повторяющиеся задачи, которых нет в готовых инструментах; понимает, где алиаса уже мало, а полноценная утилита ещё избыточна — промежуточный уровень — функция в shell, лежащая в dotfiles.
  • Распространяет свои инструменты (свой tap в Homebrew, go install, релизы на GitHub), чтобы они синхронизировались между машинами и доезжали до коллег.
  • Соблюдает соглашения по интерфейсу: стандартные флаги (--help, --version, --dry-run, --json), осмысленные коды возврата, ошибки в stderr, полезный вывод в stdout (clig.dev и 12-Factor CLI).

L5

  • Выращивает личный набор в командный: то, чем регулярно пользуюсь сам, выносится на ретро и либо становится общим, либо отвергается с обоснованием.
  • Управляет жизненным циклом набора: чистит устаревшие алиасы и скрипты (полгода без использования — на выход), обновляет зависимости, переезжает на современные замены — eza вместо ls, bat вместо cat, ripgrep вместо grep.
  • Знает границы: чего в личном наборе быть не должно — критичные для безопасности операции в проде, всё, что требует согласования нескольких людей, и бизнес-логика. Это уезжает в командную автоматизацию или в оператор внутри кластера.
  • David Thomas, Andrew Hunt — The Pragmatic Programmer (2-е изд., 2019), главы про заточку инструмента, автоматизацию и простой текст. Старая, но именно оттуда растёт мысль, что инженер вкладывается в собственный инструментарий.
  • Brian Ward — How Linux Works (3-е изд., 2021). Не про инструментарий напрямую, зато даёт понимание shell, модели процессов и файловой системы — фундамент, без которого автоматизация получается наугад.
  • clig.dev — Command Line Interface Guidelines (2020). Канонический свод соглашений: флаги, коды возврата, вывод, читаемость для человека. Пишете утилиту — обязательно пройдите по этому чеклисту, он ловит половину неудобств до того, как ими воспользуется кто-то ещё.
  • 12-Factor CLI Apps (Jeff Dickey, 2016). Перенос принципов Twelve-Factor на командную строку: конфигурация, переменные окружения, разделение потоков вывода.
  • Heroku CLI Style Guide — пример последовательного интерфейса промышленного уровня.
  • Homebrew Formula Cookbook — раздача под macOS и Linux. Свой tap — главный способ дать утилиту коллегам без возни со сборкой у каждого на машине.
  • GoReleaser — автоматизация релизов для проектов на Go: сборка под несколько платформ, релиз на GitHub, обновление формулы в tap, образ для Docker. Превращает релиз в одну команду.
  • mise / asdf / devbox — версии инструментов на каждый проект отдельно; альтернатива глобальной установке.
  • Базовый набор: fzf (нечёткий поиск), ripgrep (быстрый grep), fd (быстрый find), bat (cat с подсветкой), eza (современная замена ls), zoxide (умный cd), jq, yq. По моим наблюдениям, эта восьмёрка и есть фактический минимум в современных наборах на macOS и Linux.
  • Работа с GitHub: gh CLI — большинство походов в браузер закрывается одной командой. Я ещё написал repo-opener, чтобы открывать в браузере любой git-remote, в том числе там, где gh browse не работает.
  • Удобство облачных CLI: aws-cli с aws-vault, gcloud, yccli — мой набор алиасов к CLI Yandex Cloud. Приём переносится на любой длинный облачный CLI.
  • Шаблоны и генераторы: srekit (мой генератор SRE-артефактов: постмортем, RFC, runbook, SLO, план мощностей, changelog), cookiecutter, copier — для типовых заготовок проектов.
  • Личные секреты: pass (классика поверх GPG), jtsekret (мой CLI для личных секретов: пароли, токены OAuth, ключи API, токены ботов), а также CLI от 1Password и Bitwarden, если секреты уже там.
  • Запуск задач: Taskfile (мой выбор по умолчанию: YAML и task --list вместо чтения файла), GNU make (для старых проектов), just (современная замена make). Мой репозиторий taskfiles — набор переиспользуемых шаблонов.
  • Мультиплексор и редактор: tmux или zellij плюс neovim или helix. Конфигурация уезжает в dotfiles. Мой BearLazyVim собран поверх LazyVim.
  • Уведомления и склейка: notiflow (мой GitHub Action для уведомлений в Telegram по завершении задачи), terminal-notifier (родной для macOS), ntfy (свой сервер уведомлений).

Конкретный кейс — эволюция от gch к srekit. gch начинался в 2023 как монолитная утилита на Go со всем, что нужно ежедневно: сократить ссылку, сгенерировать пароль, сгенерировать лицензию, найти дубликаты картинок, узнать курс, набросать заготовку для разбора. Это работало несколько лет. Когда SRE-артефактов стало много, я вытащил их в srekit — отдельную утилиту со своим релизным циклом, своей документацией и своим набором пользователей, которым до генератора паролей нет никакого дела. Вывод простой. У личного набора есть свой технический долг, и рефакторить его приходится ровно как любую кодовую базу. Признаки, что момент настал, тоже узнаваемые: подкоманды одной утилиты обслуживают разные домены, разные пользователи хотят разного (мне — всё, коллегам — только генераторы), а объяснение нового флага занимает больше времени, чем его написание.

Dotfiles уезжают в git с первого дня. Без репозитория они не переживут ни переустановку системы, ни смену машины, ни новую работу — и это не гипотеза, а то, что я наблюдаю у каждого второго. Инженер с dotfiles в git разворачивается на новой машине за час. Без них теряет неделю на «вспомнить, что я там настраивал». Схема стандартная: ~/.dotfiles или ~/.config/dotfiles плюс симлинки в нужные точки через GNU stow или собственный install.sh.

Раздавать свои инструменты лучше через свой tap, а не через «скачай и положи». Свой tap делает установку одной командой brew install jtprogru/tap/srekit — на любой машине, своей или коллеги. Без него начинается копирование бинарников, чужая сборка и пляски с подписью на macOS. GoReleaser обновляет формулу на каждый релиз, так что цена поддержки этой схемы почти нулевая.

Чистка идёт по расписанию. Раз в полгода я прохожу по алиасам, функциям и установленным утилитам и выкидываю то, чем не пользовался. Мёртвые алиасы замедляют старт shell, путают поиск через which и засоряют изменения в dotfiles. Копить дешевле, чем чистить. Ровно поэтому чистку и приходится ставить в календарь.

Дальше про уровни: алиас, функция, утилита. Алиас — команда с фиксированными аргументами и без логики (alias k='kubectl', alias ll='ls -la'). Функция в shell — одна-три строки с переменными и минимальной логикой (gcp() { git checkout main && git pull && git checkout -b "$1"; }). Утилита начинается там, где появляются подкоманды, разбор аргументов, автодополнение и документация. Промежуточный антипаттерн узнаётся сразу. Пятидесятистрочная функция на bash с ветвлениями в dotfiles уже стала программой, но не оформлена как программа: ни тестов, ни справки, ни внятной обработки ошибок, и правит её только автор, да и то по памяти. Переросла десяток строк — выноси в отдельный скрипт. У меня личное правило: если код переехал из .zshrc в отдельный .sh, следующая остановка — утилита на Go или Python.

Taskfile или Makefile в каждом проекте — обязательная гигиена. Минимум dev, build, test, lint, release, clean. Помогает не столько команде, сколько мне самому через три месяца, когда вопрос «как я тут собирал» звучит абсолютно всерьёз. По моим наблюдениям, чем проще запускается цикл разработки, тем дольше проект остаётся живым. Я предпочитаю Taskfile: YAML вместо синтаксиса на табах, task --list вместо чтения файла, проще подключать чужие куски и раскладывать команды по группам. Make — тоже норма, если он уже прижился.

Возможность поделиться работает как фильтр качества. Утилита, которую захотели коллеги, почти всегда уже прошла проверку на дизайн: внятная справка, разумные значения по умолчанию, никаких зашитых путей вида /Users/jtprogru/.... Коллега поставил из tap и пользуется — значит, оформлено правильно. Если пользоваться могу только я, да и то после чтения исходников, это не инструмент, а код. Делиться обязаны не все утилиты, часть остаётся личной по замыслу, но сама возможность держит код в форме.

Личные секреты — отдельная категория с особыми требованиями. Личный набор почти всегда трогает чувствительное: ключи API, токены ботов, учётные данные OAuth, ключи SSH. Хранить их открытым текстом в dotfiles или в экспортах окружения — антипаттерн, см. Secrets Management. Для личного использования рабочий набор небольшой: pass поверх GPG, CLI от 1Password или Bitwarden, либо собственная минимальная обёртка. Я написал jtsekret ровно потому, что разнообразие сервисов перестало помещаться в одно хранилище с устоявшейся структурой. Принципы те же, что и в командном управлении секретами: шифрование на диске, никакого открытого текста в коммитах, дисциплина ротации.

  • Toil Tracking — личный набор убирает toil одного человека; учёт даёт основание решить, стоит ли писать свой инструмент.
  • Toil Automation — автоматизация на уровне команды; личный набор — её самый дешёвый уровень, и хорошая личная утилита нередко в него и вырастает.
  • Shell & CLI Craft — беглость в shell — фундамент для того, чтобы вообще писать инструменты.
  • Programming Languages — Go, Python и Rust — типичный выбор под утилиту; размен между скоростью написания и удобной раздачей готового бинарника.
  • Secrets Management — личные секреты — частный случай той же дисциплины: принципы те же, охват меньше.
  • Architecture Decision Records — даже для личных инструментов полезно записать короткое решение: почему этот язык, почему такая раздача.
  • ChatOps — боты в чате как командное продолжение личных скриптов.
  • Командная библиотека инструментов (TBD) — отдельная подобласть: как личная утилита становится командным стандартом. Граница с golden paths и платформенной инженерией.
  • Дисциплина выбора инструментов — по каким критериям брать один open-source инструмент вместо другого и когда привязка к нему становится проблемой. Пока в сообществе преобладает метод проб и ошибок, а не явные критерии.
  • Несколько платформ или одна — выбор зависит от парка машин. У меня сейчас macOS плюс Linux как запасной вариант, Windows игнорируется. Это решение рабочего окружения, а не принцип.
  • Я не уверен, сколько времени инженеру разумно тратить на свой набор — слышал оценки от часа в неделю до десятой части рабочего времени. Хорошей публичной модели не знаю; обычно решается по вкусу и зрелости инструментов. Если у вас есть явные замеры — был бы интересен опыт PR’ом.