Архитектура
Как закладывать рост без преждевременной сложности
Что действительно стоит продумать в первой версии, а какие технические решения можно отложить до появления реальной потребности.
Разговор о масштабировании часто начинается с технологий: микросервисы, очереди, кластеры. Но первая полезная схема описывает не серверы, а работу продукта. Кто создаёт данные? Кто может их менять? Какие действия зависят друг от друга? Что должно произойти, если внешний сервис недоступен?
Например, в сервисе бронирования важно отделить каталог мест, наличие свободных слотов, создание брони и уведомления. Это не означает, что каждому блоку сразу нужен отдельный сервис. Достаточно, чтобы ответственность была понятна в коде и изменение уведомлений не требовало переписывать правила бронирования.
Такие границы проще обсуждать с бизнесом: они связаны с поведением пользователей. Архитектурная схема приносит пользу, когда по ней можно объяснить, где хранится состояние, кто отвечает за изменение и какие ошибки предусмотрены.
Есть вещи, которые трудно и дорого добавлять задним числом: права доступа, целостность важных данных, правила изменения состояния и возможность разобраться в ошибке. Их стоит продумать до запуска, даже если аудитория пока небольшая.
Для бронирования недостаточно скрыть занятую кнопку в интерфейсе. Два человека могут отправить запрос одновременно. Ограничение должно действовать там, где сохраняется результат. Документация PostgreSQL описывает ограничения уникальности и связи между записями: такие механизмы помогают закрепить правила в базе, а не только в интерфейсе.
Полезная основа также включает воспроизводимое развёртывание, резервное копирование и проверку восстановления. Резервная копия ценна не наличием файла, а возможностью вернуть рабочие данные. Для важных сценариев стоит предусмотреть повторные запросы: повторная попытка не должна создавать вторую оплату или дублирующую заявку.
Один развёртываемый сервис с понятными внутренними модулями может быть разумным началом. Он уменьшает число связей, которые нужно обслуживать, и позволяет быстрее менять ещё не устоявшиеся правила. При этом простота не означает один огромный файл или отсутствие тестов.
Мартин Фаулер в заметке Monolith First описывает подход, при котором границы системы сначала уточняются в монолите. Это полезный ориентир, а не универсальное правило: если независимое развёртывание или изоляция уже необходимы, их нужно учитывать с начала проекта.
Хороший вопрос для любого усложнения: какая текущая проблема исчезнет после этого решения? Если ответ сводится к «когда-нибудь пригодится», стоит сравнить стоимость решения сейчас с вероятной стоимостью изменения позже.
После запуска полезно смотреть, где именно тратятся время и ресурсы. Причиной медленной страницы может быть запрос к базе, повторная обработка одного файла или внешний API. Добавление серверов не исправит каждую из этих проблем.
Отдельный сервис, кеш или очередь стоит вводить под конкретную нагрузку и понятный сценарий отказа. Например, длительную подготовку отчёта можно перенести в фоновую задачу, чтобы пользователь не ждал завершения внутри одного запроса. Тогда нужно также продумать статус, повторную попытку и уведомление о результате.
План развития лучше фиксировать как условия: что изменится при росте числа пользователей, увеличении объёма данных или появлении новой роли. Так архитектура сохраняет направление, но не превращает первую версию в строительство инфраструктуры на все случаи жизни.
Основа для роста — понятные границы и надёжные правила. Дополнительная сложность оправдана, когда решает уже сформулированную проблему.
- Архитектура
- Разработка