Проектирование: почему нельзя просто сразу начать писать код
В предыдущей статье — Требования и аналитика — мы дошли до момента, когда в трекере лежит задача с внятными критериями приёмки. Соблазн очевиден: открыть IDE и начать. Иногда это правильный ход. Гораздо чаще между «понял задачу» и «пишу код» есть фаза, которую в учебниках называют проектированием, а в жизни — «сходил поговорил», «накидал схему», «написал RFC», «посидел полчаса с блокнотом».
Эта статья — про то, что физически происходит в эти полчаса (или две недели), почему пропуск этой фазы стоит дороже, чем кажется, и как не свалиться в противоположную крайность — рисование красивых диаграмм вместо работы.
Сразу дисклеймер про границы. Здесь мы говорим о проектировании как о фазе процесса: кто, когда, в каком виде, с кем согласовывает. Содержательная часть — как именно устроены слои, микросервисы, событийные шины и CAP-теорема — живёт в отдельном треке Архитектурные паттерны, а принципы декомпозиции — в Принципах разработки. Дублировать их не будем.
Что ломается, когда проектирования не было
Начнём не с определения, а с типичной истории. Она повторяется в разных компаниях почти дословно.
Джуну дают задачу: «сделать возможность сменить тариф в личном кабинете». Критерии приёмки написаны, макеты есть. Джун делает ровно то, что написано: форма, кнопка, запрос на бэкенд, апдейт поля plan_id в таблице accounts. Проходит ревью, проходит тестирование, уезжает в прод. Работает.
Через три недели приходит бухгалтерия: не сходится выручка. Выясняется:
- Никто не сохранял историю смен тарифа, а она нужна для актов и для аналитики оттока. Поле перезаписывалось. История за три недели потеряна безвозвратно.
- Смена тарифа в середине оплаченного периода не пересчитывала деньги — критерий приёмки об этом молчал, а спросить было некого, потому что аналитик считал это очевидным.
- Если пользователь нажимал кнопку дважды подряд (а он нажимал — ответ шёл 4 секунды), создавалось два события в биллинге. Идемпотентности не было, потому что о ней не подумали.
- Партнёрская интеграция читала
accounts.plan_idнапрямую из реплики базы и сломалась, когда добавили статус «смена запланирована».
Ни одна из этих проблем не является багом в коде. Код делает то, что написано. Все четыре — пропущенные решения: их никто не принял осознанно, поэтому они приняли себя сами, по умолчанию, в момент написания первой строчки.
Вот это и есть определение, которое стоит запомнить.
Проектирование — это не рисование диаграмм. Это выявление решений, которые всё равно будут приняты, и принятие их до того, как они станут дорогими.
Два разных занятия, которые называют одним словом
Слово «проектирование» покрывает как минимум два разных вида работы, и путаница между ними — источник половины конфликтов на эту тему.
Архитектурное проектирование (system design) — решения уровня системы: на что делится приложение, как компоненты общаются, где лежат данные, как система выдерживает нагрузку и отказы. Горизонт — годы. Владелец — архитектор, техлид, senior-разработчики. Это то, что спрашивают на System Design Interview, подробно разобрано в System design.
Детальное проектирование фичи (feature design, иногда «техдизайн») — решения уровня одной задачи или эпика: какие таблицы, какие эндпоинты, какие состояния, что делать при ошибке, как выкатывать. Горизонт — недели. Владелец — разработчик, который будет это делать. Именно этим вы будете заниматься каждую неделю, начиная примерно с уверенного джуна.
Джуниору говорят «проектирование — это не твоё, этим архитектор занимается», и он честно ждёт, пока ему принесут готовую схему. Не принесут. Архитектор в лучшем случае определит, что фича живёт в сервисе биллинга и ходит в существующую шину. Всё остальное — ваша работа.
Сколько проектирования нужно: дозировка
Главный вопрос не «проектировать или нет», а «сколько». Ответ зависит от одного свойства решения — обратимости.
Джефф Безос в письме акционерам 2016 года описал это как «двери одностороннего и двустороннего действия» (см. письмо акционерам 2016): решения второго типа можно откатить, поэтому их принимают быстро и на низком уровне; решения первого типа откатить нельзя, поэтому их обсуждают. Для разработчика шкала выглядит так:
Практическое правило: объём проектирования определяется не размером задачи, а самым необратимым решением внутри неё. Задача на «добавить одно поле в API» может быть на два часа кода и на два дня обсуждений, если это публичный API, которым пользуются внешние клиенты. И наоборот: рефакторинг на три тысячи строк внутри одного модуля может не требовать вообще никакого дизайн-документа, потому что всё обратимо и покрыто тестами.
Второй фактор — цена ошибки. Сложите с обратимостью — получите матрицу, по которой удобно принимать решение «а надо ли мне тут документ».
Мартин Фаулер описал ровно эту динамику в Design Stamina Hypothesis: без дизайна вы быстрее в начале и медленнее потом, с дизайном — наоборот, и есть точка пересечения. Спор идёт только о том, где она находится для конкретного проекта. Для лендинга к рекламной кампании, который живёт три недели, она может не наступить вообще, и это нормальный инженерный выбор, а не разгильдяйство.
Из чего состоит детальное проектирование фичи
Разберём по пунктам. Это не формальный шаблон — это список вопросов, ответы на которые вы всё равно дадите, вопрос только когда.
1. Границы: где живёт изменение
Первое решение — в каком модуле/сервисе/слое появляется новый код. Обычно ответ навязан существующей архитектурой, и это хорошо. Плохо, когда ответ «а давайте новый сервис»: это самое дорогое решение из возможных, и у джуна нет данных, чтобы его принимать. Фаулер про это писал в MonolithFirst — почти все успешные микросервисные системы начинались как монолит, который научились резать по живым швам, а не по угаданным.
Полезный вопрос себе: «если бы этой фичи не было, какой модуль всё равно знал бы про эти данные?» Туда и класть.
2. Контракты: что видят снаружи
Контракт — это то, на что смогут завязаться другие. Как только кто-то завязался, менять больно. Поэтому контракты проектируются, а не «получаются».
# Фрагмент OpenAPI. Обратите внимание на три вещи, которые
# отличают продуманный контракт от случайного.
paths:
/v1/accounts/{account_id}/plan-changes:
post:
summary: Запланировать или применить смену тарифа
parameters:
- name: Idempotency-Key
in: header
required: true # 1. Идемпотентность заложена в контракт,
schema: { type: string } # а не «добавим потом, если задвоится»
requestBody:
content:
application/json:
schema:
type: object
required: [target_plan_id]
properties:
target_plan_id: { type: string }
effective_from: # 2. Смена может быть отложенной —
type: string # это следствие бизнес-правила,
format: date # а не техническая деталь
responses:
"202":
description: Смена принята; см. status для итогового состояния
content:
application/json:
schema:
type: object
properties:
change_id: { type: string }
status: # 3. Явная модель состояний наружу,
type: string # а не булев флаг success
enum: [applied, scheduled, rejected]
effective_from: { type: string, format: date }
"409":
description: Уже есть незавершённая смена тарифа
Три ошибки, которые видно на ревью чаще всего:
- Булев флаг вместо перечисления.
{"success": true}сегодня, а завтра появляется «принято, но применится первого числа», и вы либо ломаете клиентов, либо городите костыль. - Отсутствие идемпотентности в мутирующих операциях. Сеть не надёжна, ретраи будут, клиент нажмёт дважды. Идемпотентный ключ стоит один час на этапе дизайна и три дня расследования потом. См. паттерны устойчивости.
- Утечка внутреннего устройства наружу. Если в ответе есть
plan_idиз вашей таблицы — вы только что сделали свою схему БД публичным контрактом. Про стили API и их последствия — API styles, про версионирование хорошо написано у Stripe: api-versioning.
Отдельно про контракты событий. Событие в шине — это API, у которого вы не знаете потребителей. Это самый коварный вид контракта: сломать его можно молча, а узнать об этом — через неделю от чужой команды.
3. Модель данных и путь миграции
Схема БД переживает три поколения кода. Проектируется она отдельно и заранее.
-- Плохо: тариф как одно поле. Историю не восстановить,
-- отложенную смену не выразить, «кто менял» не ответить.
ALTER TABLE accounts ADD COLUMN plan_id text NOT NULL;
-- Лучше: событие смены как отдельная сущность.
-- accounts.current_plan_id остаётся как денормализованный кэш для чтения.
CREATE TABLE plan_changes (
id uuid PRIMARY KEY,
account_id uuid NOT NULL REFERENCES accounts(id),
from_plan_id text NOT NULL,
to_plan_id text NOT NULL,
status text NOT NULL, -- scheduled | applied | cancelled | failed
effective_from date NOT NULL,
idempotency_key text NOT NULL,
actor_id uuid, -- кто инициировал: пользователь или оператор
created_at timestamptz NOT NULL DEFAULT now(),
applied_at timestamptz
);
-- Именно этот индекс делает невозможным двойное списание при двойном клике.
CREATE UNIQUE INDEX plan_changes_idem
ON plan_changes (account_id, idempotency_key);
-- А этот — запрещает две параллельные незавершённые смены.
CREATE UNIQUE INDEX plan_changes_one_pending
ON plan_changes (account_id) WHERE status = 'scheduled';
Обратите внимание: два частичных уникальных индекса — это бизнес-правила, выраженные так, что их невозможно обойти из кода. Это типичное дизайн-решение, которое не видно в требованиях, но которое отличает работающую фичу от фичи, которая работает до первой гонки.
Второй обязательный вопрос — как выкатывать. Схема и код деплоятся не атомарно. Стандартный ответ — expand/contract: сначала добавили новое (совместимо со старым кодом), выкатили код, потом убрали старое отдельным релизом. Про механику — в треке DevOps и в Выбор и миграция БД. На этапе дизайна достаточно ответить: «сколько релизов нужно и что происходит, если между ними откатимся».
4. Состояния и переходы
Как только у сущности больше двух состояний, её жизненный цикл нужно нарисовать — буквально. Это занимает десять минут и вылавливает больше дыр, чем любое ревью кода.
Проверьте себя по такой диаграмме тремя вопросами: (1) есть ли состояние, из которого нет выхода; (2) что происходит, если процесс упал внутри перехода; (3) какие переходы инициирует не пользователь, а время или внешняя система. Третий вопрос почти всегда выявляет забытый крон или забытый вебхук.
Ровно та же техника применяется к жизненному циклу задачи в трекере и бага — про это в статьях Разработка и Тестирование.
5. Отказы и деградация
Вопрос, который джун почти никогда не задаёт сам: «что делать, если внешний вызов не ответил?» Вариантов ровно четыре, и выбрать нужно осознанно:
| Стратегия | Когда уместна | Что нужно предусмотреть |
|---|---|---|
| Упасть и вернуть ошибку | Операция синхронная, пользователь ждёт, повтор дешёв | Внятное сообщение, код ошибки, отсутствие частичных записей |
| Ретрай с backoff | Ошибка вероятно временная, операция идемпотентна | Лимит попыток, jitter, что делать после исчерпания |
| Поставить в очередь и ответить «принято» | Пользователю не нужен мгновенный результат | Способ узнать итог, обработка «завис навсегда» |
| Деградировать | Есть разумное поведение по умолчанию | Явная пометка в UI, метрика частоты деградаций |
Канон по теме — Michael Nygard, «Release It!» (Pragmatic Bookshelf); паттерны таймаута, circuit breaker и bulkhead разобраны в Resilience patterns.
6. Нефункциональные требования и наблюдаемость
Если про нагрузку, латентность и объём данных не спросили — их придумает продакшн. Полезный минимум на этапе дизайна:
- Сколько записей в этой таблице будет через год? Через три? (Ответ «немного» не принимается — попросите порядок величины.)
- Сколько запросов в секунду в пике? Пик — это когда?
- Что попадает в персональные данные и где это хранится? В российском контуре это ещё и вопрос 152-ФЗ и локализации, в европейском — GDPR. Это ограничение дизайна, а не «юристы потом посмотрят».
- Какие метрики и логи я добавлю, чтобы понять, что фича работает? Название метрики придумывается сейчас, а не во время инцидента. Про это — Наблюдаемость и дежурства и Релиз и эксплуатация.
Отдельным пунктом — безопасность. Минимальный дизайн-уровень: кто имеет право вызвать эту операцию, проверяется ли это на сервере, что будет, если подставить чужой account_id. Формальная техника — threat modelling по STRIDE, см. OWASP Threat Modeling. Даже в стартапе на десять человек 20 минут такого разговора окупаются.
Как это выглядит как процесс
Теперь соберём в поток. Вот честная картинка того, как проектирование живёт внутри спринта в команде, где процесс поставлен, но не бюрократизирован.
в требованиях?"} B -- да --> B1["Вернуться к аналитику/продакту
Это не слабость, это дешевле сейчас"] B1 --> B B -- нет --> C{"Есть необратимые
решения?"} C -- нет --> D["Набросок в комментарии к задаче
10-30 минут"] C -- да --> E["Техдизайн: 1-3 страницы
контракты, схема, состояния, отказы"] E --> F["Обсуждение с теми, кого затронет:
смежные команды, QA, безопасность, SRE"] F --> G{"Возражения по существу?"} G -- да --> E G -- нет --> H["Зафиксировать решение
ADR или запись в задаче"] D --> I["Уточнить оценку
теперь она осмысленная"] H --> I I --> J["Разбить на шаги, которые
можно мержить по отдельности"] J --> K["Писать код"] K --> L{"Дизайн столкнулся
с реальностью?"} L -- да --> M["Обновить документ, сообщить тем,
кто ревьюил. Не молчать."] M --> K L -- нет --> N["Разработка
и код-ревью"]
Три места, где эта схема ломается в реальности:
Ветка «вернуться к аналитику» не используется. Джун боится показаться глупым и додумывает требование сам. В 80% случаев угадывает, в 20% — переделка. Скажу прямо: вопрос «что должно произойти, если пользователь понижает тариф в последний день оплаченного периода» не делает вас глупым. Отсутствие этого вопроса в дизайне делает вас автором бага.
Обратная связь после столкновения с реальностью. Дизайн почти всегда оказывается частично неверным — это нормально, Парнас с Клементсом ещё в 1986 году честно написали статью «A Rational Design Process: How and Why to Fake It» о том, что идеального линейного проектирования не бывает и документ пишется задним числом как будто оно было. Проблема не в том, что дизайн изменился, а в том, что об этом никто не узнал.
«Разбить на шаги, которые можно мержить по отдельности» — самый недооценённый пункт. Хороший дизайн отвечает не только «как это устроено», но и «в каком порядке это появляется в main так, чтобы каждый шаг был безопасен». Об этом подробно в следующей статье.
Кто участвует и кто что решает
Проектирование редко бывает одиночным занятием. Вот как выглядит взаимодействие ролей на средней по размеру фиче.
в зависимости от компании
Ключевое наблюдение, которое стоит вынести: QA и безопасность подключаются до кода, а не после. Вопрос тестировщика «а как я воспроизведу состояние Failed?» на этапе дизайна стоит одну строчку в схеме. Тот же вопрос через две недели стоит переделки. Это и называется shift-left, про который много говорят и мало делают. Роли и зоны ответственности подробно разобраны в Кто есть кто в команде.
Артефакты: что реально пишут
Забудьте про толстые «технические задания» из методичек. В живых командах встречаются четыре формата, и все они короткие.
Комментарий в задаче на 10 строк. Самый частый артефакт. «Делаю так-то, поля такие-то, ручка такая, при отказе биллинга кладу в очередь ретраев». Занимает пять минут, ловит половину недоразумений на ревью.
Техдизайн / RFC на 1–3 страницы. Формат, который де-факто стал стандартом в продуктовых компаниях: постановка проблемы, варианты решения, выбранный вариант, последствия, открытые вопросы. Отлично описан в разборе практики Uber и других — Scaling Engineering Teams via RFCs; открытый пример живого процесса — RFD у Oxide Computer.
ADR (Architecture Decision Record). Короткая запись именно решения и его контекста, живёт в репозитории рядом с кодом. Придумал Michael Nygard, Documenting Architecture Decisions; коллекция шаблонов — adr.github.io.
# ADR-014: Смена тарифа как отдельная сущность, а не поле в accounts
## Статус
Принято, 2026-03-04. Заменяет неявное решение из ADR-002.
## Контекст
Тариф хранится как accounts.plan_id. Требуется отложенная смена,
история для бухгалтерии и защита от двойного применения.
Партнёрская интеграция читает plan_id из реплики.
## Решение
Вводим таблицу plan_changes с явной моделью состояний.
accounts.current_plan_id сохраняем как денормализованный кэш
и обновляем в той же транзакции, что и переход в applied.
## Альтернативы
1. Поле + аудит-лог общего назначения — отклонено: лог не даёт
гарантий уникальности и не выражает «запланировано».
2. Event sourcing для аккаунта — отклонено: непропорционально
задаче, команда не имеет опыта эксплуатации.
## Последствия
+ История и отложенные смены доступны из коробки.
+ Двойное применение невозможно на уровне БД.
− Две точки правды; расхождение кэша нужно мониторить.
− Партнёрскую интеграцию придётся мигрировать в течение квартала.
Ценность ADR не в моменте написания, а через полтора года, когда новый человек спросит «почему тут так криво сделано». Ответ «потому что в 2026-м не было опыта эксплуатации event sourcing» — это нормальный ответ. Отсутствие ответа — это то, из чего рождаются легенды про «предыдущих идиотов».
Диаграмма. Одна, от руки или в текстовом виде рядом с кодом. Хорошая опора — C4 model Саймона Брауна: она даёт четыре уровня масштаба и снимает вечный спор «а насколько детально рисовать». Практика, которая экономит месяцы: держите диаграмму в текстовом формате (mermaid, PlantUML, Structurizr DSL) в том же репозитории, что и код. Картинка в PNG на корпоративном портале протухает за квартал и врёт.
Энтерпрайз и стартап: одна фаза, две вселенные
Это тот случай, когда разница между типами компаний максимальна. Обе крайности имеют смысл в своём контексте, и обе имеют цену. Подробно — в Энтерпрайз изнутри и Стартап изнутри.
| Крупная компания / энтерпрайз | Стартап /小 команда | |
|---|---|---|
| Кто принимает решение | Архитектурный комитет, TDA, владелец домена | Тот, кто делает; иногда СТО |
| Артефакт | Формальный шаблон, иногда 20+ страниц | Тред в Slack, ADR на полстраницы |
| Срок согласования | От недели до квартала | От часа до дня |
| Что реально проверяют | Соответствие стандартам, ИБ, лицензии, ПДн, влияние на смежные системы | «Мы точно не закопаемся на месяц?» |
| Главный риск | Решение устарело, пока согласовывалось | Решение приняли, не зная о трёх последствиях |
| Что хорошего | Ловятся системные и юридические косяки; есть кого спросить | Обратная связь от прода за дни; дизайн проверяется реальностью |
| Что плохого | Проектирование превращается в защиту документа | Через два года половина системы — необратимые решения, принятые за пять минут |
Честно про энтерпрайз: часть тяжести процесса — не глупость, а следствие цены ошибки. Когда система обслуживает миллионы людей и регулируется ЦБ, «просто попробуем и откатим» не работает: откат может быть невозможен юридически. Часть — действительно ритуал, унаследованный от времён, когда релиз был раз в полгода.
Честно про стартап: скорость реальна и это огромное преимущество для обучения. Но неоплаченный дизайн — это долг с процентами, который вы же и будете обслуживать. Разница между хорошим и плохим стартапом не в наличии документов, а в том, отличают ли там зелёную зону от красной.
Отдельная категория — аутсорс и госсектор, где формат проектной документации может быть прописан в договоре или ГОСТе (например, ГОСТ 34 и 19 серии в госзаказе). Там дизайн-документ — юридический артефакт, а не инструмент мышления, и путать эти два назначения нельзя. Подробнее — в Какие бывают проекты.
Проектирование и оценка
Просить оценку до проектирования — всё равно что просить смету до осмотра квартиры. Тем не менее просят, и с этим нужно уметь работать.
Рабочий подход, который не превращает вас в человека, который «всегда срывает сроки»:
- Разделяйте оценку на два акта. Первая — грубая, порядковая, до дизайна: «дни, недели или месяцы». Вторая — после дизайна, уже в терминах шагов. Явно говорите, какая из них озвучена.
- Называйте не число, а диапазон с причиной разброса. «3–8 дней; разброс из-за того, что не знаю, поддерживает ли биллинг отложенные операции — выясню за день». Это превращает оценку в понятный менеджеру риск, а не в обещание.
- Не забывайте про всё, что не код. Ревью, тесты, миграция, переключение флага, мониторинг, документация, ответы смежникам. У новичков систематическая недооценка именно здесь — кода-то на день.
- Проектирование — это тоже работа, у неё есть длительность. Заложите её в оценку явной строкой. «День на дизайн» — легитимная позиция.
Механика оценок, story points, покер планирования и почему всё это систематически врёт — в Оценка и планирование.
Типичные ошибки
Проектирование в вакууме. Документ написан, но не показан тем, кого он затрагивает. Дизайн, который не прошёл через чужие глаза, — это не дизайн, а ваши предположения в красивом оформлении. Минимальный ритуал: 20 минут созвона с одним человеком, который знает систему дольше вас.
Over-engineering под будущее, которого не будет. Абстрактная фабрика провайдеров платежей при одном провайдере. Плагинная архитектура для двух вариантов поведения. Kafka ради 40 событий в сутки. Проверочный вопрос: «какое конкретное известное мне требование я не смогу выполнить без этой абстракции?» Если ответа нет — это YAGNI, см. также DRY, KISS, YAGNI и Антипаттерны.
Обратная ошибка: «сделаем просто, потом отрефакторим». Работает для зелёной зоны и не работает для красной. «Потом перепишем формат события» — не бывает. Отличать эти два случая и есть профессиональный навык.
Дизайн как документ, а не как мышление. Признак: документ пишется после того, как код уже написан, ради галочки в чек-листе. Это чистые потери. Если процесс требует такого документа — пишите его честно и коротко, но не притворяйтесь, что это проектирование.
Молчаливое отклонение от дизайна. В коде оказалось иначе, ревьюер об этом не знает, документ не обновлён. Через полгода документ активно вредит, потому что ему верят.
Проектирование в одиночку в open space, где сидит человек, писавший этот модуль. Два часа чтения кода против пяти минут вопроса. Стеснительность — самая дорогая черта джуна.
Пропуск вопроса «а как мы это выключим». Любая заметная фича должна иметь способ быть отключённой без релиза: фича-флаг, конфиг, kill switch. Решается на дизайне одной строкой, спасает во время инцидента.
Что делает на этой фазе человек в зависимости от грейда
Полезно понимать, куда расти. Развёрнуто про грейды — в Грейды, здесь — только срез по проектированию.
- Джун. Проектирует внутри одной задачи и одного модуля. Главный навык — заметить, что решение выходит за пределы задачи, и спросить. Нормально не знать ответ; ненормально не заметить вопрос.
- Мидл. Проектирует фичу целиком, включая контракты, миграции и порядок выкатки. Умеет назвать два-три варианта и объяснить выбор. Учитывает эксплуатацию: логи, метрики, откат.
- Сеньор. Проектирует то, что затрагивает несколько команд. Основная работа — не схема, а согласование: выяснить, кого сломает, и договориться. Умеет сознательно выбрать плохое-но-быстрое решение и явно записать долг.
- Техлид/архитектор. Отвечает за то, чтобы решения были совместимы между собой во времени, и за то, чтобы процесс проектирования не превращался ни в анархию, ни в бюрократию.
Как этому научиться, если вы джун
Проектирование — навык, который прокачивается наблюдением и разбором, а не чтением.
- Читайте чужие дизайн-документы и ADR в своей компании. Это самый быстрый способ понять, как здесь принято думать. Обращайте внимание на раздел «альтернативы»: там видно ход мысли.
- Проводите обратное проектирование по легаси. Возьмите модуль, который вам непонятен, и восстановите: какие решения были приняты и какие ограничения их вызвали. Половина «идиотского кода» окажется разумным ответом на давно исчезнувшее ограничение.
- Пишите техдизайн даже там, где не просят. Десять строк в задаче. Через полгода перечитайте: увидите, чего систематически не учитываете именно вы.
- Ходите на дизайн-ревью чужих задач и молчите. Слушайте, какие вопросы задают опытные. Через десяток встреч вы начнёте задавать их себе сами — это и есть весь секрет.
- Тренируйтесь на System Design задачах, но помните: интервью — упрощённая модель. Реальное проектирование на 70% состоит из выяснения ограничений, которых на интервью просто нет. Заготовка — System design и Архитектурные решения.
- Освойте одну технику совместного моделирования. Например Event Storming — быстрый способ вытащить из бизнеса модель процесса: Event Storming.
Чек-лист перед первой строчкой кода
Короткий список, который реально помещается в голове. Если на все ответы есть — можно кодить.
- Я могу назвать бизнес-правило, а не только UI-поведение.
- Я знаю, какие данные появляются и переживают ли они три поколения кода.
- Контракт наружу зафиксирован; в нём перечисление, а не булев флаг.
- Мутирующая операция идемпотентна или объяснено, почему не нужно.
- Нарисован жизненный цикл сущности; тупиковых состояний нет.
- Известно, что делать при отказе каждой внешней зависимости.
- Понятно, как это выкатывается и как откатывается; есть способ выключить.
- Названы метрики/логи, по которым будет видно, что фича жива.
- Проверено, кого это ломает: смежные команды, интеграции, отчёты.
- Решение из красной зоны — записано и с кем-то обсуждено.
- Работа разбита на шаги, каждый из которых можно смержить отдельно.
Мини-итог
- Проектирование — это не диаграммы, а осознанное принятие решений, которые иначе примут себя сами и не в вашу пользу.
- Дозировка определяется обратимостью: зелёную зону просто кодят, красную — обсуждают и записывают.
- Минимальный набор вопросов: границы, контракты, данные и миграция, состояния, отказы, нефункциональные требования, наблюдаемость, способ выключить.
- Артефакты короткие: комментарий в задаче, RFC на страницу, ADR, одна диаграмма в репозитории.
- Энтерпрайз рискует утонуть в согласованиях, стартап — накопить необратимые решения; ни то ни другое не «правильно» само по себе.
- Дизайн будет неверен частично — это норма. Ненормально не сказать об этом тем, кто на него опирался.
Источники и что почитать
- John Ousterhout, A Philosophy of Software Design — лучшее короткое чтение про то, что такое сложность и как её уменьшать. Страница книги
- Michael Nygard, Release It!, 2nd ed. — про отказы, таймауты и то, что система живёт в проде.
- Mark Richards, Neal Ford, Fundamentals of Software Architecture — про архитектурные характеристики и компромиссы.
- Michael Keeling, Design It! — практикум по дизайн-мышлению для команд.
- David Parnas, Paul Clements, A Rational Design Process: How and Why to Fake It, 1986 — честная классика про то, почему линейного проектирования не бывает.
- David Parnas, On the Criteria To Be Used in Decomposing Systems into Modules, 1972 — откуда вообще взялась идея скрывать решения за границами модулей.
- Martin Fowler, Is Design Dead? и Design Stamina Hypothesis
- C4 model — как рисовать архитектуру на четырёх уровнях детализации.
- adr.github.io — шаблоны и инструменты для ADR.
- Google API Design Guide — здравые правила проектирования контрактов.
- OWASP Threat Modeling — минимальная дисциплина по безопасности на этапе дизайна.
Что дальше
Дизайн есть, чек-лист пройден — пора писать код. Следующая статья про то, как код попадает из вашей головы в main: ветки, коммиты, ревью, стандарты и главный вопрос «а когда задача считается готовой».
Разработка: ветки, код-ревью, стандарты и Definition of Done