We detected you are likely not from a Russian-speaking region. Would you like to switch to the international version of the site?

К списку статей

Domain‑Driven Design в монолитных и микросервисных архитектурах

26 янв 2026 в 07:30 Усачёв Денис Евгеньевич

Domain‑Driven Design (DDD) – это набор принципов и практик, позволяющих построить программную систему, тесно соответствующую бизнес‑требованиям. При правильном применении DDD упрощает коммуникацию между разработчиками и экспертами предметной области, делает код более понятным и облегчает масштабирование.

Ключевые понятия DDD

Основные элементы DDD:

  • Ubiquitous Language – общий язык, используемый всеми участниками проекта.
  • Bounded Context – граница, внутри которой определён один набор моделей и терминов.
  • Entity – объект с уникальной идентификацией, меняющий своё состояние.
  • Value Object – неизменяемый объект, определяемый своей ценностью.
  • Aggregate – кластер связанных сущностей, управляемый корневым агрегатом.
  • Repository – абстракция доступа к агрегатам.
  • Domain Service – сервис, инкапсулирующий бизнес‑логику, не принадлежащую отдельной сущности.

DDD в монолитных приложениях

В монолитной архитектуре DDD помогает разделить код на логически независимые модули, каждый из которых отвечает за свой Bounded Context. Это достигается за счёт организации слоёв (Presentation → Application → Domain → Infrastructure) и использования паттернов репозитория и фабрики.

// PHP: пример Entity и Value Object
class Money
{
    private float $amount;
    private string $currency;

    public function construct(float $amount, string $currency)
    {
        $this->amount   = $amount;
        $this->currency = $currency;
    }

    public function getAmount(): float { return $this->amount; }
    public function getCurrency(): string { return $this->currency; }
}

class Order
{
    private int $id;
    private Customer $customer;
    private Money $total;

    public function construct(int $id, Customer $customer, Money $total)
    {
        $this->id       = $id;
        $this->customer = $customer;
        $this->total    = $total;
    }

    // Геттеры и бизнес‑логика
    public function getTotal(): Money { return $this->total; }
}

Репозиторий реализуется как отдельный слой, позволяющий менять источник данных без влияния на доменную логику.

DDD в микросервисных архитектурах

При переходе к микросервисам каждый Bounded Context обычно становится отдельным сервисом. Это приводит к нескольким важным изменениям:

  • Сервис отвечает только за один контекст, что повышает автономность.
  • Взаимодействие между сервисами происходит через асинхронные сообщения или API‑контракты.
  • Domain Model внутри сервиса остаётся неизменным, но теперь он «выживает» в распределённой среде.

Ключевой момент – согласованность границ контекстов. При проектировании микросервисов необходимо явно определить, какие данные являются «домены», а какие – «служебные».

# Python: микросервис с FastAPI, демонстрирующий Domain Service
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI()

class OrderDTO(BaseModel):
    id: int
    customer_id: int
    total: float

class OrderDomainService:
    def create_order(self, dto: OrderDTO) -> dict:
        # Здесь могла бы быть сложная бизнес‑логика
        if dto.total <= 0:
            raise ValueError('Total must be positive')
        # Сохранение в репозитории (условно)
        return {"status": "created", "order_id": dto.id}

service = OrderDomainService()

@app.post("/orders")
def create_order(order: OrderDTO):
    try:
        result = service.create_order(order)
        return result
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))

В примере сервис инкапсулирует бизнес‑правила, а контроллер отвечает лишь за транспортный слой.

Стратегический дизайн: согласование монолита и микросервисов

При миграции от монолита к микросервисам рекомендуется использовать Strangler Fig Pattern. Сначала выделяют отдельные Bounded Contexts, реализуете их как микросервисы и постепенно перенаправляете запросы через фасад.

# Пример роутинга запросов через API‑Gateway (pseudo‑code)
if request.path.startswith('/orders'):
    forward_to('order-service')
else:
    forward_to('legacy-monolith')

Такой подход позволяет поддерживать работоспособность системы во время перехода и минимизировать риски.

Технические детали интеграции

Для согласования данных между сервисами используют:

  • Событийный брокер (Kafka, RabbitMQ) – публикация доменных событий.
  • Схемы данных (Avro, Protobuf) – гарантируют совместимость контрактов.
  • API‑контракты (OpenAPI/Swagger) – документируют взаимодействие.

Важно, чтобы каждый сервис хранил только свои агрегаты, а копии данных из других контекстов были «read‑only» и обновлялись через события.

Типичные подводные камни и как их избежать

  • Слишком тонкая грануляция контекстов. Деление на слишком мелкие микросервисы приводит к повышенной связанности и сложности оркестрации.
  • Дублирование бизнес‑логики. При неправильном разделении иногда одна и та же логика реализуется в нескольких сервисах.
  • Неправильное управление транзакциями. В микросервисах нельзя полагаться на распределённые ACID‑транзакции; используйте SAGA‑паттерн.

Регулярные ревью контекстов и автоматическое тестирование помогают поддерживать чистоту модели.

Заключение

Domain‑Driven Design – мощный инструмент, который одинаково эффективен как в монолитных, так и в микросервисных системах. Главное – правильно определить границы контекстов, поддерживать Ubiquitous Language и использовать стратегический подход к миграции.

Услуги RybinskLab

RybinskLab предлагает полный спектр услуг по разработке и трансформации бизнес‑приложений: от проектирования доменных моделей и построения монолитных систем до создания масштабируемых микросервисных архитектур с применением DDD. Наши эксперты помогут сформулировать грамотный Ubiquitous Language, определить Bounded Contexts и реализовать надёжные сервисы на PHP, Python и других современных стеков.

* Материал подготовлен с использованием ИИ-ассистента, проверен и отредактирован экспертом RybinskLab.

Поделиться материалом:

Нужна сложная разработка?

Усачёв Денис Евгеньевич — проектирование архитектуры, бэкенд на PHP/Python, интеграции API и базы данных.

Обсудить проект
Поддержать проект