Programming Languages
Это первое, что я говорю людям, переходящим из классической эксплуатации в SRE: придётся писать код. Не «помогать команде разработки», не «чинить деплои» — писать сервис, который пойдёт в прод. И не «по чуть-чуть пять языков», а один-два до уровня поддерживаемого сервиса плюс уверенность в shell для скриптовой автоматизации. Здесь — про сам подход и модель навыков; конкретный выбор языка — в материалах.
Что должен уметь
Заголовок раздела «Что должен уметь»Главный навык на уровне L3 — писать скрипты, которые не падают молча. set -euo pipefail, явная обработка ошибок, ревью для всего, что живёт дольше недели. Я регулярно встречаю команды, где сервисы на Go тщательно тестируются, а скрипт в crontab живёт три года без единого теста и роняет прод с молчаливой ошибкой. Несимметричное отношение к качеству — типичная ловушка перехода в SRE.
L3
- Уверенно пишет скрипты на bash с обработкой ошибок (
set -euo pipefail), конвейерами, циклами и базовой работой сawk,sedиjq. - Читает и правит существующий код команды на основном языке (чаще всего Go или Python); понимает базовые идиомы.
L4
- Пишет небольшие сервисы на основном языке: обработчик HTTP, отдача метрик через клиент Prometheus, структурированные логи, работа с конфигурацией, аккуратное завершение.
- Пишет тесты: модульные, табличные в Go или через
pytestв Python; знает про фаззинг для критичных разборщиков форматов. - Профилирует код: запускает
pprofв Go,cProfileилиpy-spyв Python и читает flame graph или дерево вызовов, а не оптимизирует на глазок.
L5
- Поддерживает сервис в проде: разбирает паники, исключения и гонки; осознанно выбирает модель конкурентности; читает трассировки прямо в инциденте.
- Проектирует API сервиса: идемпотентность на повторах, версионирование, RED-метрики из коробки, аккуратное завершение с дренированием соединений, обработка сигналов.
L6+
- Принимает решения о языке и стеке для команды; обосновывает выбор ограничениями: производительность, экосистема, наём, стоимость эксплуатации.
- Развивает культуру ревью: это обучение и распространение знания, а не пропускной пункт. Заводит стандарты команды — линтер, форматтер, ожидания по тестам, соглашение о коммитах.
Материалы
Заголовок раздела «Материалы»- Alan A. A. Donovan, Brian W. Kernighan — The Go Programming Language (Addison-Wesley, 2015). База для основного языка отрасли. Первые главы тяжёлые, дальше идёт легче. Если выбираете один источник по Go — этот.
- Luciano Ramalho — Fluent Python, 2-е изд. (O’Reilly, 2022). По моим наблюдениям, многие команды берут эту книгу после первых боевых багов с asyncio или системой типов — там подробно разобрано то, что в туториалах опускают.
- Jim Blandy, Jason Orendorff, Leonora F. S. Tindall — Programming Rust, 2-е изд. (O’Reilly, 2021). Для мест, где важна производительность: обвязка вокруг eBPF, инструментирование, безопасный системный код. Rust в SRE пока редок; если у вас eBPF — это вход.
- Brian W. Kernighan, Rob Pike — The Practice of Programming (Addison-Wesley, 1999). Классика про дисциплину: отладка, тестирование, производительность, переносимость. Устарела по примерам, но не по принципам.
Статьи и доклады
Заголовок раздела «Статьи и доклады»- Go team — Effective Go. Официальное руководство по идиомам. Обязательное чтение перед первым боевым сервисом на Go.
- Steve Klabnik, Carol Nichols et al. — The Rust Programming Language (бесплатно онлайн). Канонический учебник.
- Adam Wiggins et al. — The Twelve-Factor App. Методология сервисов для прода: конфигурация, процессы, логи, одноразовость. Задаёт модель кода, готового к бою, независимо от языка.
- Mike Bland — Goto Fail, Heartbleed, and Unit Testing Culture (martinfowler.com). Почему модульные тесты без культуры их писать бесполезны. Хороший аргумент на ревью конвейера без тестов.
- Основы алгоритмизации и программирования — компактный компендиум по базе: алгоритмические конструкции, языки (Python, Go), процедуры и рекурсия, ООП, работа с файлами, HTTP, регулярными выражениями и базами, отладка и модульные тесты. Полезен переходящим из чистой эксплуатации в SRE и тем, кто хочет подтянуть фундамент без академического бэкграунда.
- Алгоритмы и структуры данных — лабораторный практикум на Python: массивы и стек, связные списки, очереди и деревья поиска, сортировки со счётчиком обменов, линейный и бинарный поиск, хеш-таблицы с разрешением коллизий. Реализации с нуля, без стандартных контейнеров — полезно, чтобы понимать цену структур, которые в проде обычно берёшь готовыми: словарь против среза, сложность поиска на горячем пути.
Инструменты
Заголовок раздела «Инструменты»- Профилирование —
pprof(Go, прямо в стандартной библиотеке),cProfileиpy-spy(Python),cargo benchсcriterion(Rust). Профиль перед оптимизацией обязателен. По моим наблюдениям, ежедневно в командах живут первые два набора, а инструменты Rust встречаются реже — обычно там, где рядом eBPF. - Линтеры и форматтеры —
golangci-lint(Go),ruffиblack(Python),clippyиrustfmt(Rust),shellcheck(bash). Минимум вкусовщины в стиле, максимум внимания — проектированию. - Тестирование — встроенный
go testвместе сtestifyилиgomock;pytestсpytest-cov;cargo testсcriterion;batsдля bash. Тесты на критичные сетевые пути и работу с диском — не опция. - Отладчики —
delve(Go),pdbиpdbpp(Python),gdbилиlldb(Rust и C). В большинстве инцидентов логи и профиль выигрывают у отладчика, но для воспроизводимого бага он незаменим.
Best practices
Заголовок раздела «Best practices»Если посмотреть, на чём написана инфраструктура вокруг нас — Kubernetes, Prometheus, Docker, Terraform, etcd, стек HashiCorp, — всё это Go. Инструменты для работы с данными, своя автоматизация, обвязка вокруг моделей — Python. Эти два языка, по моим наблюдениям, закрывают почти весь боевой код в командах SRE. Rust появляется нишево: обвязка eBPF, инфраструктурные утилиты. Совет «выучи пять языков для универсальности» хорош для собеседования и не отражает реальной работы.
Отсюда три правила, которые я считаю базовыми. Первый язык доводится до уровня «умею писать сервис», и только потом добавляется второй: поверхностное знание трёх языков означает, что на всех трёх человек пишет в стиле первого освоенного, без идиом и без инструментов. Профилирование идёт до оптимизации всегда — «здесь медленно, я знаю» стабильно приводит к неделе, потраченной на место, которое не было узким. И аккуратное завершение вместе с идемпотентностью обязательны для любого долгоживущего сервиса: без первого теряются запросы в полёте и клиент получает разрыв на ровном месте, без второго повторы спокойно дублируют побочные эффекты.
Код SRE — это код в проде, а не «временный скрипт». Чаще всего правило ломается вокруг shell. Типичная история, которую я наблюдаю: трёхлетний скрипт в crontab падает молча, отдаёт NaN в одну из метрик планирования мощностей, и об этом узнают через две недели, когда ломается дашборд. Тестов нет, в CI не запускается, владельца тоже нет — потому что «временный». Если код регулярно запускается на проде, он живёт по правилам продуктовой команды: репозиторий, тесты, ревью, версионирование и наблюдаемость собственного инструментария.
Уверенность в shell — отдельное вложение, а не приложение к Go. Хороший Go не заменяет умения написать for f in $(...); do ...; done, прочитать kubectl logs ... | jq | grep и разобрать вывод чужой утилиты. На дежурстве это пишется ежедневно, и слабый bash съедает больше времени, чем слабый Go в коде сервиса. Соседний лист — Shell & CLI Craft.
Чтение чужого кода — главный навык. SRE поддерживает чужие сервисы, и читать приходится больше, чем писать. Сильных и слабых инженеров я различаю ровно здесь: первые открывают код, разбираются и приходят к автору с конкретным вопросом; вторые дёргают автора на каждое непонятное поведение, не открыв ни файла. Тренируется это скучно — ревью соседних сервисов, разбор унаследованного кода вместе с техлидами и привычка понять раньше, чем менять.
И про границу. Всё сказанное — про SRE, который отвечает за сервисы и инструменты. Если работа устроена иначе — вы держите чужую платформу, а разработка идёт целиком в других командах, — требование «пиши сервис на Go» превращается в ритуал: язык учится, а применять его негде, и через полгода навык рассыпается. Тогда честнее вкладываться в shell, в чтение чужого кода и в один язык на уровне уверенных правок. Обратная сторона тоже реальна: инженер, который дорос до сервисов, но остался с одним bash, упирается в потолок ровно в тот момент, когда задача перестаёт помещаться в скрипт.
Связанные листья
Заголовок раздела «Связанные листья»- Networking — повторы, размыкатели цепи и таймауты реализуются в коде; знание сетевых библиотек своего языка — половина практики устойчивости.
- SLI-based Alerting — метрики и трассировка (клиент Prometheus, SDK OpenTelemetry) пишутся в коде; качество SLI упирается в идиомы языка.
- SLO Engineering — аккуратное завершение, идемпотентность и повторы — кодовая основа того, что потом измеряется целями.
- Runbooks — скрипты внутри runbook (разовые починки, диагностические выгрузки) — отдельный класс кода; bash здесь часто выигрывает у Go простотой обновления.
- Incident Response — чтение трассировок, стека исключения и профиля прямо в инциденте — главное живое применение языка.
- Shell & CLI Craft — соседний лист про сборку команд из готовых утилит; shell — не приложение к Go, а отдельная мышца.
- Performance & Profiling — профили, flame graph и бюджеты задержки — соседний лист про дисциплину «сначала измерь»; работает поверх среды исполнения языка.
- Operating Systems — среда исполнения стоит на системе; паузы сборщика мусора, поведение планировщика и характер системных вызовов — общая зона.
Открытые вопросы
Заголовок раздела «Открытые вопросы»- Модели конкурентности по языкам — структурированное сравнение горутин в Go, asyncio в Python, асинхронного Rust и виртуальных потоков в Java. Возможно, отдельный лист под
Programming / Scripting. - Я не уверен, где правильно проходит граница между листом про язык и листом про среду исполнения и систему. Часть тем (настройка сборщика мусора, взаимодействие с планировщиком) сейчас распределена между этим листом, Performance & Profiling и Operating Systems — пересечение намеренное, но, возможно, требует более чёткой границы.