Цели модуля
После модуля студент сможет:
- Писать Architecture Decision Records (ADR) по стандартному шаблону
- Вести decision records для важных технических решений
- Создавать операционные runbooks для команды
- Планировать миграции между технологиями и архитектурами
- Защищать технические решения перед командой и стейкхолдерами
- Использовать C4 model для архитектурных диаграмм
- Поддерживать документацию в актуальном состоянии (living documentation)
11.1 Зачем нужна архитектурная документация
Проблемы без документации
- Новые разработчики тратят недели на понимание системы
- Решения принимаются повторно (изобретение велосипеда)
- Невозможно понять почему система устроена именно так
- Операционные процедуры существуют только в головах
- Миграции проводятся хаотично
Что даёт документация
- Передача знаний: онбординг новых разработчиков
- История решений: почему выбрано именно это решение
- Операционная готовность: runbooks для инцидентов
- Планирование: миграции и эволюция системы
- Коммуникация: общий язык для команды
Типы архитектурной документации
| Тип | Назначение | Пример |
|---|---|---|
| ADR | Запись архитектурного решения | Почему выбрали PostgreSQL |
| RFC | Запрос на комментарии перед решением | Дизайн нового API |
| Runbook | Операционные процедуры | Что делать при High Error Rate |
| Migration Plan | План миграции | Переход Serverless -> VDS |
| Architecture Diagram | Визуализация системы | C4 диаграммы |
| API Documentation | Описание API | OpenAPI спецификация |
Принципы хорошей документации
- Актуальность: документация обновляется с кодом
- Доступность: любой член команды может найти и понять
- Лаконичность: минимум воды, максимум сути
- Структурированность: шаблоны для единообразия
- Версионирование: документация в git рядом с кодом
11.2 ADR (Architecture Decision Records)
Что такое ADR
ADR — короткий документ фиксирующий одно архитектурное решение:
- Контекст: почему возникла необходимость решения
- Решение: что выбрано
- Альтернативы: что рассматривалось
- Последствия: плюсы и минусы решения
Зачем нужны ADR
- История: через год понятно почему система устроена именно так
- Обоснование: решение не выглядит произвольным
- Обсуждение: команда может обсудить до принятия
- Отмена: если решение устарело, пишется новый ADR отменяющий старый
Шаблон ADR
text# ADR-NNN: Название решения ## Статус Proposed | Accepted | Deprecated | Superseded by ADR-XXX ## Дата YYYY-MM-DD ## Контекст Описание ситуации которая требует решения. Какие ограничения и требования существуют. ## Решение Что мы решили сделать. Кратко и чётко. ## Альтернативы Какие варианты рассматривались и почему отвергнуты. ### Альтернатива 1: ... Почему не подошла. ### Альтернатива 2: ... Почему не подошла. ## Последствия ### Положительные - ... ### Отрицательные - ... ### Риски - ... ## Ссылки - Связанные ADR - Внешние ресурсы
Пример ADR из шаблона
text# ADR-01: Serverless vs VDS для деплоя ## Статус Accepted ## Дата 2026-01-15 ## Контекст Нам нужно выбрать модель деплоя для Git-сервиса. Требования: - Обработка Git Smart HTTP протокола (долгие запросы) - Фоновые задачи (outbox relay, saga orchestrator) - Работа с файловой системой (NFS для git repos) - Бюджет ограничен Рассматриваемые варианты: - Serverless (Cloud Functions) - VDS (виртуальный сервер) - Kubernetes ## Решение Используем VDS для production. Serverless для прототипирования. Обоснование: - Git Smart HTTP требует долгих соединений (не подходит для Serverless) - Фоновые задачи проще на VDS (systemd, cron) - NFS монтируется к VDS - Предсказуемая стоимость ## Альтернативы ### Альтернатива 1: Serverless Плюсы: автоскейлинг, оплата за использование. Минусы: cold start, ограничения по времени выполнения, сложность с NFS и long-running процессами. ### Альтернатива 2: Kubernetes Плюсы: автоскейлинг, self-healing, rich экосистема. Минусы: операционная сложность, избыточно для одного сервиса, требует DevOps экспертизы. ## Последствия ### Положительные - Простота деплоя и эксплуатации - Полный контроль над окружением - Нет cold start - Long-running процессы работают ### Отрицательные - Нет автоскейлинга - Ручное управление инфраструктурой - Single point of failure (без доп. мер) ### Риски - При росте нагрузки потребуется миграция на Kubernetes - Нужен мониторинг и алерты для доступности ## Ссылки - ADR-08: NFS vs S3 для хранения - docs/migration/serverless-to-vds.md
Нумерация ADR
ADR нумеруются последовательно:
textdocs/adr/ ├── ADR-01-serverless-vs-vps.md ├── ADR-02-ydb-vs-postgresql.md ├── ADR-03-outbox-vs-direct-publish.md ├── ADR-04-saga-orchestration.md ├── ADR-05-smart-http-design.md ├── ADR-06-observability-stack.md ├── ADR-07-secrets-and-rotation.md ├── ADR-08-nfs-vs-s3.md ├── ADR-09-single-binary-vs-multi.md └── ADR-10-cron-vs-timer.md
Правила:
- Никогда не удаляем ADR (только Deprecated/Superseded)
- Новое решение отменяющее старое — новый ADR со ссылкой
- ADR в git рядом с кодом
Статусы ADR
| Статус | Значение |
|---|---|
| Proposed | Предложено, обсуждается |
| Accepted | Принято, реализуется |
| Deprecated | Устарело, не использовать |
| Superseded | Заменено другим ADR (ссылка) |
11.3 Decision records и RFC process
Когда нужен RFC
RFC (Request for Comments) — документ для обсуждения до принятия решения.
Используйте RFC когда:
- Решение влияет на несколько команд
- Есть несколько равнозначных вариантов
- Нужен feedback от экспертов
- Решение необратимо или дорого
Не нужен RFC когда:
- Решение локальное для одного модуля
- Есть очевидный лучший вариант
- Решение легко отменить
Шаблон RFC
text# RFC: Название предложения ## Метаданные - Автор: @engineer - Статус: Draft | In Review | Accepted | Rejected - Рецензенты: @reviewer1, @reviewer2 - Дедлайн feedback: YYYY-MM-DD ## Резюме Краткое описание предложения (2-3 предложения). ## Мотивация Почему это нужно. Какую проблему решаем. ## Детальный дизайн Подробное описание решения. Диаграммы, примеры кода, API. ## Альтернативы Что ещё рассматривалось. ## План реализации Этапы, сроки, ответственные. ## Открытые вопросы Что ещё не решено. ## Feedback Комментарии рецензентов и ответы автора.
Процесс RFC
text1. Автор пишет RFC (Draft) 2. Публикует для команды 3. Рецензенты оставляют комментарии 4. Автор обновляет RFC 5. Обсуждение на встрече (если нужно) 6. Принятие или отклонение 7. Если принято — создаётся ADR и задачи
Decision log
Для маленьких решений не нужен полный RFC, но фиксируем:
text# Decision Log ## 2026-01-15: Используем pgx вместо database/sql Причина: pgx быстрее и поддерживает PostgreSQL-specific фичи. Решено: @engineer1, @engineer2 ## 2026-01-20: Логирование через slog вместо zap Причина: slog в стандартной библиотеке, меньше зависимостей. Решено: @engineer1
11.4 Runbooks
Что такое runbook
Runbook — пошаговая инструкция для решения конкретного инцидента или операционной задачи.
Структура runbook
text# Runbook: [Название инцидента] ## Метаданные - Алерт: [название алерта] - Severity: Critical | Warning | Info - Владелец: [команда/человек] - Последний review: YYYY-MM-DD - Последний инцидент: YYYY-MM-DD ## Симптомы Как проявляется проблема. Какие алерты срабатывают. ## Диагностика ### Шаг 1: [Название шага] Команда или действие. Ожидаемый результат. ### Шаг 2: [Название шага] Команда или действие. Ожидаемый результат. ## Возможные причины и решения ### Причина 1: [Название] Признаки: ... Решение: ... Команды: ... ### Причина 2: [Название] Признаки: ... Решение: ... Команды: ... ## Эскалация Если не решено за N минут: - Уведомить: @team-lead - Создать инцидент: [ссылка на трекер] - Обновить status page ## Проверка восстановления - [ ] Error rate < 1% в течение 10 минут - [ ] Все health checks проходят - [ ] Нет новых алертов ## Post-incident - [ ] Написать post-mortem в течение 48 часов - [ ] Создать action items - [ ] Обновить runbook если нужно
Пример runbook из шаблона
text# Runbook: High Error Rate ## Метаданные - Алерт: HighErrorRate - Severity: Critical - Владелец: Backend Team - Последний review: 2026-01-15 ## Симптомы - Error rate > 5% в течение 5 минут - Увеличение 5xx ответов - Алерт в Slack/Telegram ## Диагностика ### Шаг 1: Проверить статус сервиса curl https://api.example.com/healthz kubectl get pods -n production Ожидаемый результат: 200 OK, все pods Running. ### Шаг 2: Проверить логи # Grafana/Loki запрос {app="git-server"} |= "ERROR" | last 15m Ищем: паттерны ошибок, stack traces. ### Шаг 3: Проверить метрики Grafana дашборд: API Overview - Error rate по эндпоинтам - Latency p99 - DB connection pool usage ### Шаг 4: Проверить зависимости curl https://db.example.com/health curl https://nfs.example.com/health ## Возможные причины и решения ### Причина 1: Баг в последнем деплое Признаки: error rate вырос сразу после деплоя Решение: Rollback Команды: kubectl rollout undo deployment/git-server -n production # или для VDS: ansible-playbook deploy.yml -e version=previous ### Причина 2: Проблема с БД Признаки: timeout errors, connection refused Решение: Проверить БД, перезапустить если нужно Команды: kubectl get pods -n database kubectl logs postgres-primary -n database ### Причина 3: NFS недоступен Признаки: I/O errors в логах Решение: Проверить NFS mount, перемонтировать Команды: ssh app-server "df -h /mnt/nfs" ssh app-server "sudo mount -o remount /mnt/nfs" ## Эскалация Если не решено за 30 минут: - Уведомить: @backend-lead - Создать инцидент в Jira - Обновить status page ## Проверка восстановления - [ ] Error rate < 1% в течение 10 минут - [ ] Все health checks проходят - [ ] Нет новых алертов
Правила хороших runbooks
- Пишутся ДО инцидента
- Конкретные команды, не абстракции
- Тестируются регулярно (game days)
- Обновляются после каждого инцидента
- Доступны всем on-call инженерам
11.5 Migration plans
Когда нужен migration plan
Миграция между:
- Технологиями (PostgreSQL -> CockroachDB)
- Архитектурами (монолит -> микросервисы)
- Платформами (Serverless -> VDS -> Kubernetes)
- Провайдерами (AWS -> Yandex Cloud)
- Версиями (API v1 -> API v2)
Шаблон migration plan
text# Migration Plan: [Название миграции] ## Метаданные - Автор: @engineer - Статус: Planned | In Progress | Completed - Начало: YYYY-MM-DD - Завершение: YYYY-MM-DD ## Мотивация Почему мигрируем. Какие проблемы решаем. ## Текущее состояние Описание текущей системы. Диаграмма. ## Целевое состояние Описание целевой системы. Диаграмма. ## Стратегия миграции Как мигрируем: big bang, постепенная, dual write. ## Этапы миграции ### Этап 1: Подготовка - Задачи - Ответственные - Дедлайны ### Этап 2: Dual write / Dual read - Задачи - Ответственные - Дедлайны ### Этап 3: Переключение - Задачи - Ответственные - Дедлайны ### Этап 4: Cleanup - Задачи - Ответственные - Дедлайны ## Rollback plan Как откатиться если миграция не удалась. ## Риски и митигация | Риск | Вероятность | Impact | Митигация | |---|---|---|---| | Потеря данных | Низкая | Высокий | Бэкапы, dual write | | Downtime | Средняя | Высокий | Canary, blue-green | ## Критерии успеха - [ ] Все данные мигрированы - [ ] Error rate < 1% - [ ] Latency не деградировала - [ ] Старая система отключена
Пример migration plan из шаблона
text# Migration Plan: Serverless -> VDS ## Мотивация - Git Smart HTTP требует долгих соединений - Фоновые задачи сложнее на Serverless - NFS проще монтируется к VDS - Предсказуемая стоимость ## Текущее состояние - 5 Cloud Functions (api, git-gateway, outbox-relay, saga-orchestrator, hmac-rotator) - Timer Triggers для фоновых задач - YDB для хранения ## Целевое состояние - Single binary (git-server) - HTTP server + workers в одном процессе - Cron scheduler для фоновых задач - PostgreSQL вместо YDB - NFS для git repos ## Стратегия миграции Постепенная, с dual write для данных. ## Этапы ### Этап 1: Подготовка (2 недели) - Настроить VDS инфраструктуру (Terraform) - Развернуть PostgreSQL - Настроить Ansible для деплоя ### Этап 2: Dual write (2 недели) - Приложение пишет в YDB и PostgreSQL - Фоновые задачи на VDS читают из PostgreSQL - Мониторинг консистентности ### Этап 3: Переключение (1 неделя) - Переключаем чтение на PostgreSQL - Переключаем трафик на VDS - Мониторинг error rate ### Этап 4: Cleanup (1 неделя) - Удаляем dual write - Останавливаем Cloud Functions - Архивируем YDB данные ## Rollback plan Если error rate > 5% после переключения: - Переключаем трафик обратно на Cloud Functions - Возвращаем чтение на YDB - Инвестигируем проблему ## Риски | Риск | Вероятность | Impact | Митигация | |---|---|---|---| | Потеря данных при миграции | Низкая | Высокий | Бэкапы, dual write, checksum | | Downtime при переключении | Средняя | Высокий | Canary, blue-green | | Деградация производительности | Средняя | Средний | Load testing до миграции |
11.6 Defense of technical decisions
Что это
Defense — представление и защита технических решений перед:
- Командой разработки
- Tech leads
- Архитектурным комитетом
- Бизнес-стейкхолдерами
Когда нужен defense
- Крупные архитектурные решения
- Выбор технологий с долгосрочным влиянием
- Миграции между системами
- Решения с высоким риском или стоимостью
Структура defense
text# Defense: [Название решения] ## Слайд 1: Проблема Какую проблему решаем. Почему сейчас. ## Слайд 2: Контекст и ограничения Технические, организационные, бюджетные ограничения. ## Слайд 3: Варианты решения 2-3 варианта с плюсами и минусами. ## Слайд 4: Рекомендация Что рекомендуем и почему. ## Слайд 5: Риски и митигация Что может пойти не так. Как mitigируем. ## Слайд 6: План реализации Этапы, сроки, ресурсы. ## Слайд 7: Стоимость Инфраструктура, время команды, операционные расходы. ## Слайд 8: Вопросы Ответы на вопросы аудитории.
Подготовка к defense
-
Знайте свою аудиторию
- Разработчики: технические детали
- Менеджеры: сроки, стоимость, риски
- Бизнес: влияние на продукт, время до рынка
-
Anticipate вопросы
- Почему не альтернатива X?
- Что если Y сломается?
- Сколько это стоит?
- Как откатиться?
-
Подготовьте backup slides
- Детали реализации
- Бенчмарки
- Сравнение технологий
Частые вопросы на defense
| Вопрос | Как отвечать |
|---|---|
| Почему не X? | Объяснить trade-offs, почему X не подходит |
| Что если сломается? | Rollback plan, митигация рисков |
| Сколько стоит? | Инфраструктура + время команды |
| Как масштабировать? | План масштабирования |
| Кто будет поддерживать? | Команда, runbooks, документация |
11.7 C4 model для архитектурных диаграмм
Что такое C4 model
C4 — 4 уровня абстракции для архитектурных диаграмм:
textLevel 1: Context — система и внешние акторы Level 2: Containers — приложения и хранилища внутри системы Level 3: Components — компоненты внутри контейнера Level 4: Code — классы и функции (обычно не рисуется)
Level 1: System Context
Показывает систему и внешних акторов:
text┌─────────────────────────────────────────────────────┐ │ Пользователь │ │ (Git клиент, браузер) │ └────────────────────────┬────────────────────────────┘ │ │ HTTPS, Git Smart HTTP ▼ ┌─────────────────────────────────────────────────────┐ │ Git Server │ │ (Управление репозиториями, PR) │ └────────────────────────┬────────────────────────────┘ │ │ SQL, Files ▼ ┌─────────────────────────────────────────────────────┐ │ PostgreSQL + NFS │ │ (Данные и git объекты) │ └─────────────────────────────────────────────────────┘
Level 2: Containers
Показывает приложения и хранилища:
text┌─────────────────────────────────────────────────────┐ │ Git Server │ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ HTTP Server │ │ Workers │ │ │ │ (API + Git) │ │ (Outbox, │ │ │ │ │ │ Saga, HMAC) │ │ │ └──────┬───────┘ └──────┬───────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ PostgreSQL │ │ NFS │ │ │ │ (метаданные) │ │ (git repos) │ │ │ └──────────────┘ └──────────────┘ │ └─────────────────────────────────────────────────────┘
Level 3: Components
Показывает компоненты внутри контейнера:
text┌─────────────────────────────────────────────────────┐ │ HTTP Server │ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ API Handlers │ │ Git Handlers │ │ │ └──────┬───────┘ └──────┬───────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ Use Cases │ │ Git Adapter │ │ │ └──────┬───────┘ └──────┬───────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ Services │ │ NFS Storage │ │ │ └──────┬───────┘ └──────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────┐ │ │ │ Repositories │ │ │ └──────┬───────┘ │ │ │ │ │ ▼ │ │ ┌──────────────┐ │ │ │ PostgreSQL │ │ │ └──────────────┘ │ └─────────────────────────────────────────────────────┘
Инструменты для C4
- Structurizr (DSL + UI)
- PlantUML (текстовый)
- Mermaid (markdown-friendly)
- draw.io / diagrams.net
Пример Mermaid:
textgraph TB User[Пользователь] --> |HTTPS| API[HTTP Server] API --> PG[(PostgreSQL)] API --> NFS[(NFS)] Workers[Workers] --> PG Workers --> NFS
11.8 Living documentation
Проблема устаревшей документации
Документация устаревает когда:
- Не обновляется с кодом
- Хранится отдельно от кода
- Нет процесса обновления
- Никто не владеет документацией
Living documentation принципы
-
Документация в git рядом с кодом
docs/ ├── adr/ ├── operations/ ├── migration/ └── architecture/
-
Обновление в том же PR что и код
PR: Add new endpoint
text- internal/handlers/http/api/v1/handler.go - docs/api/endpoints.md <- обновлено в том же PR
-
Автоматическая генерация где возможно
OpenAPI из аннотаций
Графики из кода
Metrics documentation из Prometheus
-
Review документации как кода
PR не мержится если документация не обновлена.
-
Регулярный аудит
Каждый квартал: review всех runbooks, ADR, migration plans.
Инструменты
- Markdown в git (простота, версионирование)
- MkDocs / Docusaurus (статические сайты документации)
- Swagger UI (OpenAPI документация)
- Grafana (дашборды как документация)
Привязка к шаблону проекта
Где документация в шаблоне
textdocs/ ├── adr/ # 8+ ADR по единому шаблону │ ├── ADR-01-serverless-vs-vps.md │ ├── ADR-02-ydb-vs-postgresql.md │ ├── ADR-03-outbox-vs-direct-publish.md │ ├── ADR-04-saga-orchestration.md │ ├── ADR-05-smart-http-design.md │ ├── ADR-06-observability-stack.md │ ├── ADR-07-secrets-and-rotation.md │ └── ADR-08-nfs-vs-s3.md ├── cost/report.md # Cost-отчёт ├── dr/plan.md # DR-план ├── defense/qna.md # Defense Q&A ├── migration/ │ ├── ydb-to-postgresql.md │ ├── functions-to-vps.md │ └── nfs-to-s3.md └── adr-template.md # Шаблон ADR
Что изучаем на примере шаблона
- ADR по стандартному шаблону
- Migration plans для эволюции системы
- DR plan для disaster recovery
- Cost report для FinOps
- Defense Q&A для подготовки к защите решений
Задание: изучите docs/adr/
- Какие решения задокументированы?
- Соблюдается ли шаблон ADR?
- Есть ли статусы и даты?
- Есть ли ссылки между ADR?
💱 Компромиссы
- Неизменяемые ADR vs правка на месте: статус
Superseded by ADR-XXXсохраняет всю историю решений, но новичку приходится читать цепочку документов; переписанный на месте ADR короче, однако теряет контекст «почему меняли». - RFC vs решение без процесса: обсуждение с рецензентами ловит дорогие ошибки до реализации, но добавляет дни на согласование; локальное решение быстрое, однако риск необратимой ошибки целиком лежит на авторе.
- Dual write vs big bang миграция: двойная запись в YDB и PostgreSQL позволяет сверять консистентность и легко откатиться, но платит неделями двойной нагрузки; big bang быстрее, однако ошибка при переключении бьёт по всем данным сразу.
- Mermaid vs draw.io: текстовые C4-диаграммы версионруются в git и мержатся как код, но ограничены в выразительности; draw.io рисует сложнее, однако его файл тяжело ревьюить, и диаграммы быстро устаревают.
- Документация в том же PR vs отдельно: обновление
docs/вместе с кодом гарантирует актуальность, но раздувает PR и замедляет мерж; отдельная задача мержится быстрее, однако документация отстаёт от кода.
Практическое задание
Задание 1: Напишите ADR
Выберите архитектурное решение из вашего проекта и напишите ADR:
text# ADR-011: [Название] ## Статус Proposed ## Контекст ... ## Решение ... ## Альтернативы ... ## Последствия ...
Используйте шаблон из модуля.
Задание 2: RFC process
Напишите RFC для нового API эндпоинта:
text# RFC: Add repository statistics endpoint ## Резюме ## Мотивация ## Детальный дизайн ## Альтернативы ## План реализации ## Открытые вопросы
Получите feedback от коллеги.
Задание 3: Runbook
Напишите runbook для инцидента "Database Connection Failed":
- Симптомы
- Диагностика (конкретные команды)
- Возможные причины
- Решения
- Эскалация
- Проверка восстановления
Протестируйте runbook в staging.
Задание 4: Migration plan
Напишите migration plan для перехода с offset-based на cursor-based пагинацию:
- Мотивация
- Текущее состояние
- Целевое состояние
- Стратегия (dual support)
- Этапы
- Rollback plan
- Риски
Задание 5: Defense presentation
Подготовьте defense для выбора архитектуры вашего проекта:
- Проблема
- Контекст и ограничения
- Варианты (2-3)
- Рекомендация
- Риски и митигация
- План реализации
- Стоимость
Проведите defense перед командой.
Задание 6: C4 диаграммы
Нарисуйте C4 диаграммы для вашего сервиса:
- Level 1: System Context
- Level 2: Containers
- Level 3: Components (для основного контейнера)
Используйте Mermaid или draw.io.
Задание 7: Living documentation
Настройте процесс:
- Документация в git рядом с кодом
- PR template с чеклистом "документация обновлена"
- Регулярный аудит (каждый квартал)
Задание 8: Decision log
Создайте decision log для вашего проекта:
text# Decision Log ## YYYY-MM-DD: [Решение] Причина: ... Решено: @...
Фиксируйте маленькие решения которые не требуют ADR.
Quiz "Проверь себя"
Level 1: Context
Level 2: Containers
Level 3: Components
Level 4: Code✅ Итоги модуля
Студент должен:
- Писать ADR по стандартному шаблону
- Вести decision records для важных решений
- Создавать операционные runbooks
- Планировать миграции между технологиями
- Защищать технические решения перед командой
- Использовать C4 model для диаграмм
- Поддерживать документацию в актуальном состоянии
- Ответить на все вопросы Quiz
🔗 Мостик к Модулю 12
Курс 3 завершён! Следующий шаг: Capstone Project — финальный проект объединяющий все знания трека. Два варианта: Serverless и VDS.