Primary source
Uber Engineering, 2020
Оригинальная статья Adam Gluck про редизайн архитектуры Uber и переход к DOMA.
DOMA (Domain-Oriented Microservice Architecture) - подход Uber к управлению очень большой микросервисной экосистемой. Ключевая идея: проектировать не набор изолированных сервисов, а домен-ориентированные коллекции сервисов со строгими контрактами, слоями зависимостей и точками расширения.
По духу этот подход объединяет идеи из DDD и архитектурной модульности, но применяет их к масштабу тысяч инженеров и тысяч сервисов.
Эволюция архитектуры Uber
Монолитная архитектура
У Uber было два крупных сервиса. По мере роста команды от десятков к сотням инженеров начали расти риски доступности, сложность деплоев и стоимость изменений.
- Риски доступности: падение крупного компонента влияло на большую часть продукта.
- Опасные деплои: большие релизы с высоким blast radius.
- Слабая separation of concerns между бизнес-возможностями.
- Медленный execution изменений в бизнес-логике.
Переход к микросервисам
Ставка на надежность, ownership и скорость разработки сначала сработала. Но при росте до тысяч инженеров появился distributed monolith с избыточными связями.
- Чрезмерное число межсервисных зависимостей.
- Сложная трассировка причин инцидентов через много команд.
- Неочевидные границы ответственности и моделей данных.
- Рост когнитивной нагрузки для разработчиков.
DOMA (Domain-Oriented Microservice Architecture)
Uber переосмыслил микросервисную систему как одно большое распределенное приложение и применил к ней архитектурные принципы доменных границ, слоев, контрактов и расширяемости.
- Фокус смещается с отдельных сервисов на домены как единицы дизайна.
- Зависимости становятся управляемыми через layered design.
- Внешние интеграции идут через gateway-контракты.
- Кросс-доменные интеграции идут через точки расширения, а не прямую связность.
Принципы DOMA
Дизайн вокруг доменов, а не отдельных сервисов
Ключевая единица проектирования - коллекция сервисов, которая решает доменную задачу end-to-end. Это упрощает ownership и roadmap изменений.
Домены группируются в уровни (layers)
Сервисы верхнего уровня могут зависеть только от нижнего. Такой dependency rule ограничивает циклы зависимостей и уменьшает blast radius при изменениях.
У домена есть clean interface через gateway
Gateway становится единой входной точкой в домен, стабилизирует внешний контракт и позволяет безопасно менять внутреннюю реализацию.
Прямых кросс-доменных зависимостей нет
Ни shared code, ни shared data model между доменами. Для кастомной интеграции используются контролируемые extension points.
Слои DOMA в Uber
| Слой | Назначение | Примеры |
|---|---|---|
| Infrastructure layer | Базовые capability, нужные любой инженерной организации: storage, networking, observability, platform primitives. | Storage APIs, network primitives, infra identity, runtime tooling |
| Business layer | Общие бизнес-возможности Uber, не привязанные к конкретной LOB (Rides/Eats/Freight). | Платежные политики, fraud-сигналы, пользовательские профили |
| Product layer | Логика конкретной продуктовой линии, но без привязки к одному клиентскому приложению. | Ride request lifecycle, dispatch policies, driver supply logic |
| Presentation layer | Функциональность, привязанная к пользовательским интерфейсам (mobile/web). | Флоу экрана заказа, UI-driven orchestration, app-specific UX rules |
| Edge layer | Безопасная экспозиция API наружу и адаптация под особенности клиентских приложений. | Edge gateways, auth policies, API composition, request shaping |
Базовое правило: сервисы верхнего слоя зависят только от сервисов нижележащих слоев.
Контракты
Паттерны межсервисной коммуникации
Gateway и extension points работают только при явных, стабильных контрактах между командами.
Gateway и точки расширения
Расширение логики через плагины
Сервисы внутри домена предоставляют plugin interfaces. Команды подключают дополнительную доменную проверку без форка базовой логики.
Расширение модели данных через optional fields
К core-модели добавляются доменно-специфичные атрибуты, чтобы не создавать прямую связь между доменами на уровне общей схемы.
Локальные extension points команд
Команды могут вводить дополнительные точки расширения внутри своего домена, сохраняя контроль контракта и жизненного цикла.
Практический эффект gateway: домен может мигрировать внутренние сервисы, не ломая потребителей, пока внешний контракт остается стабильным.
Что получилось на выходе
- Снижение сложности за счет перехода от 2200 сервисов к ~70 доменам как управляемым единицам.
- Более предсказуемые зависимости благодаря layered design и строгому dependency direction.
- Более простые миграции и независимые релизы доменов через стабильные gateway-контракты.
- Снижение когнитивной нагрузки разработчиков и ускорение локализации инцидентов.
Когда выбирать монолит, микросервисы и DOMA
| Размер организации | Базовый выбор | Почему |
|---|---|---|
| Стартап | Монолит / modular monolith | Минимальная операционная сложность, быстрый product-market fit, низкая цена изменений. |
| Средняя компания | Классические микросервисы | Нужна независимая поставка несколькими командами и контроль технологических рисков по подсистемам. |
| Крупная организация | DOMA-подход | Нужна управляемость тысяч инженеров, доменные границы, масштабируемый governance и снижение системной связности. |
Типичные ошибки при внедрении DOMA
Называть доменом любой набор случайных сервисов без явной бизнес-границы и ownership-модели.
Делать gateway тонким proxy без контракта, versioning и SLA между доменами.
Оставлять shared database/shared schema между доменами и называть это «DOMA».
Строить слои формально, но нарушать правило зависимостей (верхние слои ходят в peers/верх).
