От MVP к техническому банкротству
Ведущий замечает, что к системному дизайну относятся как к священной корове, хотя дизайн приложения MVP-уровня все представляют прекрасно. Александр отвечает эффектом, который настигает технарей ровно в момент бизнес-успеха: приложение делали быстро, а не надёжно и не с расчётом на масштабирование, ведь преждевременная оптимизация — грех, а грешить никто не любит. Приходит трафик, бизнес просит ещё фич — и наступает паралич. Андрей предлагает метафору отложенного кредита, который копит проценты; именно так, подтверждает Александр, технари объясняют бизнесу появление пласта задач, которых раньше не было. Если долг не отдавать вовремя, команда доходит до технического банкротства — заявления, что версию 1.0 надо выкинуть и написать 2.0. Пример — Netscape, «по-моему, 90-х»: пока кодовую базу год-два переписывали, конкуренты не ждали, и место на рынке пришлось уступить.
Контрпример Александр разбирал перед Новым годом — манифест Amazon про распределённые вычисления, анонсированный на последнем AWS re:Invent; заодно он раскопал историю компании в 2000-х. Маржинальность не сходилась: слишком много уходило на инфраструктуру, на серверы Sun, на обслуживание собственного магазина и логистики. Компания заморозила бизнесовые фичи на год, если не больше, и потратила его на переезд с Sun на Linux, которому тогда было лет пять-шесть. В середине переезда случился крах доткомов, сановские серверы стало можно забирать по дешёвке, но коммит уже был дан; один из топ-менеджеров вспоминал, что денег оставалось на пару кварталов. Операционные косты упали на 80%, к 2001 году компания умела жить с Linux, поймала волну виртуализации x86 — её сделали возможной инженеры VMware, научившиеся подменять инструкции в исполняемом коде, — и превратила бывшие косты в AWS.
Принципы, понятность и паттерны роста
Легаси, напоминает Андрей, — это не про неподдерживаемый код, а про нехватку знаний о нём: кода много, он чужой, команда большая. Парадокс в том, что маленькой системе надёжность не нужна — есть прототип и демо, — но выкидывать его никто не хочет, и в ту же кодовую базу доливают и функциональность, и отказоустойчивость. «Повезло» — плохая бизнес-стратегия, и разговор уходит на шаг назад, к принципам. В гугловой книге Building Secure and Reliable Systems, по словам Александра, треть, если не больше, посвящена компромиссам и весу нефункциональных требований. Первый принцип — борьба со сложностью, design for understandability: если система для тебя чёрный ящик, ответ «накину ресурсов, подниму пять инстансов» остаётся паллиативом — можно отмасштабировать глючащий stateless-компонент и уронить его совсем. Отсюда претензия к переодетым администраторам в роли SRE: в компании добиваются, чтобы они знали поддерживаемые системы. Второй принцип — готовность к меняющемуся ландшафту: железо, виртуализация, контейнеры, оркестратор нагрузок.
Сложность Александр называет главной проблемой создателей софта и советует очень тонкую книгу «Философия софтового дизайна» от создателя алгоритма консенсуса Raft: она выросла из стэнфордских курсов, где автор проверял, можно ли научить студентов хорошему дизайну. Он давал итеративный проект, делал ревью и показывал, где нарушение базовых принципов бьёт по гибкости; ценен именно микс высокоуровневых концепций с конкретными граблями. У того же автора он берёт метафору глубоких и мелких модулей: модуль должен прятать сложную логику за простым интерфейсом, а getter и setter в Java — модуль мелкий, вызов длиннее самого действия. На вопрос, где поучиться паттернам, Александр вспоминает доклад с конференции Яндекса: на примере простого сервиса «Яндекс.Вода» там показывали, как с ростом нагрузки и числа интеграций появляются балансировщик, репликация, шардирование, заглушка с запасной логикой (правильного названия паттерна он не помнит), ретраи и circuit breaker, трассировка и мониторинг, а затем и self-healing, когда число воркеров подстраивается под глубину очереди; все ли из них были в докладе, он не уверен.
Долги, пайплайн и фитнес-функции
Сходу сложную работающую систему не сделать, а простую, которая постепенно усложняется, — можно. Метафору роста Александр разбирает через книгу одного из менеджеров Amazon середины 2000-х — имя он называет с оговоркой, — где в оригинале стояло growing, а издательство «Питер» перевело буквально: «выращивание». Сначала это казалось странным: картошку выращивают на даче; но метафора живого организма оказалась точной — без заранее расставленных флажков система вырастает в хаос. Дальше про баланс: бизнесу кажется, что больше фич автоматически даёт больше денег, а задача технарей — не дать команде упереться в тупик, где ни фичи не едут с нужной скоростью, ни надёжность не держится в согласованном интервале; здесь помогает гугловый бюджет ошибок. Долги считают не только в коде: есть тестовый, есть дизайнерский, когда команды не успевают за развитием дизайн-кита, и есть аналитический — когда кросс-компонент тянется через пять-шесть экранов, а целиком его поведение не описано нигде. Первый шаг — понять, кому и сколько вы должны.
Как вложить накопленный опыт в голову соседу, когда команда растёт? Ответ Александра — встроить решения в пайплайн: тесты дают зелёное или красное, безопасность из режима «дали или не дали добро» превращается в DevSecOps со сканированием базовых образов и зависимостей, инфраструктура — тоже код, и её так же можно проверять. Тем же путём идут архитектурные характеристики: в «Эволюционной архитектуре» Нила Форда, Ребекки Парсонс и Патрика Куа (второе издание вышло в ноябре 2022 года, обложка из серой стала зелёной) это фитнес-функции. Базовое — проверка зависимостей и циклов, хотя у самого Google сервисы вроде Chubby, Bigtable, Colossus и Spanner развёрнуты друг поверх друга, и с нуля такую систему не забутстрапить. Из «Чистой архитектуры» он берёт анализ абстрактности: модуль без интерфейса, о реализации которого знают все, — это коммунальная квартира, где своей комнаты нет и ты живёшь на кухне; такое нашли при рефакторинге мобильного банка.
Что стоит унести с собой
- 01Just-in-time design по аналогии с JIT-компиляцией: вкладываться в надёжность в тот момент, когда проблема уже видна впереди; по формуле Андрея, позже так же плохо, как и раньше, — прототипу надёжность может и не понадобиться.
- 02Момент подсказывают сабдомены DDD: generic берут с рынка, supporting живёт по рабочим часам, а core требует и скорости изменений, и качества, потому что за косяки спросят снаружи; внутренний мессенджер может стать core за один поворот бизнеса.
- 03Массовое повышение технического уровня проще согласовать и приятнее делать выделенной командой и автоматически: Александр ссылается на два white paper из книги An Elegant Puzzle, включая гугловое переписывание C++-кода надстройкой над компилятором; заставлять бизнес-команды переписывать чужой код — выжигать мотивацию.
- 04Full-cycle-инженер из статьи Netflix 2018 года возможен только при готовом инструментарии: понятный фреймворк проектирования, as-a-service кубики с известными гарантиями, нормальный мониторинг — иначе он воюет с привнесённой сложностью, а ландшафт CNCF целиком в голову не помещается.