Блог AST-SoftPro
Проектирование систем: с чего начинается архитектура — обсуждение требований
Проектирование систем: с чего начинается архитектура — обсуждение требований
Любой процесс проектирования системы начинается не с выбора технологий, а с обсуждения требований. Без чёткого понимания того, что система должна делать, какой объём нагрузки она должна выдерживать и какие гарантии должны быть у пользователей, архитектура превращается в набор случайных решений. В этой статье разберём, как проводить discovery-сессию, формулировать требования и переводить их в архитектурные решения.
Discovery-сессия: кто участвует и что выясняем
Discovery-сессия — это встреча (или серия встреч) между бизнес-заказчиком, техническим лидером, архитектором и ключевыми стейкхолдерами. Цель — сформировать общее понимание задачи до начала разработки.
Ключевые вопросы:
-
Какую бизнес-проблему решаем? Это первый и самый важный вопрос. Без ответа на него невозможно оценить, насколько архитектура соответствует бизнес-целям.
-
Кто пользователи системы? Разные пользователи предъявляют разные требования: администратору важна полнота данных, конечному пользователю — скорость ответа, разработчику — удобство API.
-
Какой объём данных и нагрузки? Сколько пользователей, сколько запросов в секунду, какой объём данных за год. Эти цифры определяют выбор баз данных, необходимость кэширования и масштабирования.
-
Какие гарантии нужны? Должна ли система быть доступна 99.9% времени? Можно ли потерять данные при сбое? От этого зависят решения по репликации, бэкапам и отказоустойчивости.
-
Какой бюджет и сроки? Бюджет определяет, можно ли использовать управляемые сервисы (AWS RDS, managed Kubernetes) или нужно разворачивать всё самостоятельно. Сроки влияют на выбор между "быстро и просто" и "с запасом на будущее".
Функциональные требования
Функциональные требования описывают, что система должна делать. В контексте проектирования систем их полезно формулировать как пользовательские истории (user stories):
Как пользователь, я хочу авторизоваться через OAuth,
чтобы не запоминать ещё один пароль.
Как администратор, я хочу видеть дашборд с метриками,
чтобы быстро реагировать на инциденты.
Как система, я хочу отправлять email-уведомления,
чтобы пользователи получали подтверждения.
Каждая история должна быть достаточно конкретной, чтобы разработчик мог её реализовать, но достаточно общей, чтобы не привязываться к конкретному решению.
Нефункциональные требования
Нефункциональные требования — это то, что отличает хорошее проектирование систем от просто работающего кода. Именно они определяют архитектуру.
Категории нефункциональных требований:
| Категория | Примеры | Влияние на архитектуру |
|---|---|---|
| Производительность | < 200ms на чтение, < 1s на запись | Кэширование, индексация, асинхронные операции |
| Масштабируемость | 10K RPS в пике | Горизонтальное масштабирование, load balancer |
| Доступность | 99.9% uptime | Репликация, health-check, failover |
| Согласованность | Данные актуальны в пределах 1 сек | Eventual consistency, materialized views |
| Безопасность | GDPR-совместимость | Шифрование, RBAC, аудит |
| Наблюдаемость | Логи, метрики, трейсы | Structured logging, Prometheus, OpenTelemetry |
Конкретные цифры вместо размытых формулировок
Вместо «система должна быть быстрой» — «95-й перцентиль ответа < 200 мс при 5000 RPS».
Вместо «система должна быть надёжной» — «99.9% SLA, RTO < 1 час, RPO < 5 минут».
Цифры позволяют:
-
Оценить, достаточно ли выбранной архитектуры
-
Сравнивать альтернативные решения
-
Настроить мониторинг и алертинг
-
Обосновать бюджет на инфраструктуру
Формулирование Constraints
Constraints (ограничения) — это условия, которые не могут быть нарушены. Они сужают пространство решений и часто определяют выбор архитектуры.
Примеры constraints:
-
Технологический стек: «Используем Python, потому что команда уже работает с ним» — это constraint, который исключает Go или Rust из рассмотрения для core-сервисов.
-
Инфраструктурный: «Деплой только в Kubernetes на AWS» — определяет доступные сервисы и ограничения.
-
Юридический: «Данные пользователей не могут покидать ЕС» — влияет на выбор региона и провайдера.
-
Бюджетный: «Операционные расходы < $500/мес» — ограничивает выбор между managed и self-hosted решениями.
-
Временной: «MVP за 6 недель» — диктует компромиссы между идеальной и достаточной архитектурой.
Перевод требований в архитектурные решения
После того как требования и constraints сформулированы, начинается самое интересное — проектирование. Каждый архитектурный паттерн решает определённый набор проблем.
Пример: проектирование API-сервиса для интернет-магазина
Требования:
-
10 000 активных пользователей
-
Пиковая нагрузка: 500 RPS (чёрная пятница)
-
99.9% SLA
-
Данные в России
-
Python-стек
Архитектурные решения:
- API-сервис: FastAPI (асинхронность, автоматическая генерация документации, высокая производительность)
from fastapi import FastAPI, Depends
from sqlalchemy.ext.asyncio import AsyncSession
app = FastAPI(title="Shop API")
@app.get("/products/{product_id}")
async def get_product(
product_id: int,
db: AsyncSession = Depends(get_db),
):
product = await db.get(Product, product_id)
return product
-
База данных: PostgreSQL с репликацией (основной + 1 реплика для чтения). Для 10K пользователей и 500 RPS — достаточно одного экземпляра.
-
Кэширование: Redis для кэширования популярных запросов (каталог товаров, цены). Cache-aside паттерн.
import redis
import json
r = redis.Redis(host="redis", port=6379, db=0)
async def get_product_cached(product_id: int):
cached = r.get(f"product:{product_id}")
if cached:
return json.loads(cached)
product = await db.get(Product, product_id)
r.setex(f"product:{product_id}", 300, json.dumps(product.dict()))
return product
-
Асинхронные задачи: Celery + Redis для фоновых операций (отправка email, генерация отчётов).
-
Мониторинг: Prometheus + Grafana для метрик, structured logging в JSON-формате.
Частые ошибки на этапе обсуждения требований
-
Слишком абстрактные требования. «Система должна быть масштабируемой» без цифр — это не требование, а пожелание. Масштабируемость до какого RPS? До какого объёма данных?
-
Игнорирование нефункциональных требований. Фокус только на функционале, а производительность и надёжность — «потом». Потом обычно бывает слишком поздно.
-
Отсутствие приоритизации. Не все требования одинаково важны. P0 (критично), P1 (важно), P2 (желательно) — помогает принимать решения при компромиссах.
-
Пропуск edge cases. «А что если пользователь отменил заказ после того, как товар был отправлен?» — такие вопросы нужно задавать на этапе обсуждения, а не после деплоя.
-
Слишком ранний выбор технологий. Выбор базы данных до формулировки требований — классическая ошибка. Сначала требования, потом технологии.
Документация требований
Хорошая практика — зафиксировать требования в одном документе, к которому можно вернуться. Минимальная структура:
# Project Requirements
## Business Goal
Одна-две строки о бизнес-цели.
## Users
- End users: ..., ~X активных пользователей
- Admins: ..., ~Y пользователей
## Functional Requirements
1. ...
2. ...
## Non-Functional Requirements
- Performance: P95 < 200ms at X RPS
- Availability: 99.9% SLA
- Data: < Z GB/year
## Constraints
- Tech stack: Python
- Infra: AWS, EU region
- Budget: < $X/month
## Open Questions
- ...
Заключение
Обсуждение требований — это не бюрократия, а инвестиция в архитектуру. Чёткие требования позволяют:
-
Выбрать правильные архитектурные паттерны
-
Избежать избыточной сложности
-
Обосновать бюджет и сроки
-
Снизить риски на этапе разработки
Без этого этапа архитектура становится набором случайных решений, каждое из которых может быть неоптимальным. С требованиями — архитектура становится обоснованным выбором.
Ключевые моменты:
-
Discovery-сессия с бизнесом — обязательный первый шаг перед проектированием.
-
Нефункциональные требования (производительность, SLA, объёмы) определяют архитектуру не меньше, чем функциональные.
-
Цифры вместо размытых формулировок: 500 RPS, а не «много запросов».
-
Constraints сужают пространство решений и делают выбор технологий обоснованным.
-
Документируйте требования — это спасает при изменении команды и масштабировании проекта.