📘 Введение
Domain-Driven Design (DDD) — это не просто набор паттернов, а стратегический подход к проектированию сложных бизнес-приложений. Он помогает выстроить систему вокруг предметной области, а не технических слоёв или внешних фреймворков.
Если у вас болит голова от спагетти-кода, в котором бизнес-логика размазана между контроллерами, сервисами и репозиториями — добро пожаловать в DDD. Здесь царит порядок.
🔑 Главные идеи DDD
- Модель предметной области — это сердце системы. Код должен прямо отражать суть бизнес-объектов и правил.
- Разделение ответственности — бизнес-логика, прикладная логика, инфраструктура — в разных слоях.
- Ubiquitous Language (единый язык) — терминология в коде и среди команды должна быть одинаковой.
- Бизнес-решения — в центре. Не база данных, не фреймворк, не API.
🧱 Базовые строительные блоки
📦 Entity (Сущность)
Объект с идентичностью, которая сохраняется при изменении состояния.
Пример:
User,Order,Product.
🧩 Value Object (Объект-значение)
Иммутабельный объект без собственной идентичности. Два VO равны, если у них равны значения.
Пример:
Money,GeoPoint,PasswordHash.
🔗 Aggregate (Агрегат)
Корневая сущность, которая инкапсулирует всё, что можно менять как единое целое.
- Состоит из корня (
Aggregate Root) и вложенных объектов (entities и VO). - Внешний мир может работать только через корень.
Пример:
Order— агрегат, включающийOrderItems,ShippingInfo,Total.
📥 Repository
Интерфейс доступа к агрегатам. Абстракция над хранилищем.
Пример:
UserRepositoryInterface,OrderRepositoryInterface.
🧠 Domain Service
Содержит бизнес-логику, которая:
- не относится ни к одной конкретной сущности,
- зависит от нескольких сущностей.
Пример:
TransferService,DiscountCalculator.
🧾 Specification (опционально)
Инкапсулирует условие бизнес-логики (например, “пользователь активен и старше 18”).
🎮 Где живёт логика?
| Тип логики | Где размещается |
|---|---|
| Валидация полей | В Value Object |
| Бизнес-правила объекта | В Entity |
| Правила между объектами | В Domain Service |
| Генерация токенов, хэши и т.п. | В Application или Infrastructure Layer |
🗂 Архитектурные слои
src/
├── User/
│ ├── Domain/
│ │ ├── Entity/
│ │ ├── Repository/
│ │ └── ValueObject/
│ ├── Application/
│ │ ├── Command/
│ │ ├── Handler/
│ │ └── DTO/
│ ├── Infrastructure/
│ │ └── Repository/
│ └── UI/
│ └── Controller/
- Domain — чистый, не зависит ни от кого.
- Application — orchestration: use-cases, CQRS.
- Infrastructure — работа с БД, токенами, внешними API.
- UI — контроллеры, HTTP.
📎 CQRS + DDD
Command Query Responsibility Segregation (CQRS) отлично сочетается с DDD:
- Command — изменяет состояние (например,
RegisterUserCommand). - Query — только читает (например,
GetUserByIdQuery).
Каждой команде и запросу соответствует Handler, который работает через агрегаты, не смешивает домен и инфраструктуру и не знает про контроллеры.
🧼 Что важно соблюдать
- Не тяните
Doctrine,Request,TokenStorageв Domain. - Не стройте сущности с
setters. Лучшеreadonly+ фабрики. - DTO — только для передачи данных. Никогда не делайте из них доменные модели.
- Не пишите “умные сервисы” в Application. Логика живёт в домене.
✍️ Заключение
DDD — не серебряная пуля. Но если ваш проект становится всё сложнее, а бизнес-логика начинает душить контроллеры и сервисы — это мощный подход, который помогает выстроить архитектуру вокруг смысла, а не вокруг технологии.
Если интересно — могу в следующих статьях раскрыть:
- как строить агрегаты правильно,
- как интегрировать DDD с Event Sourcing,
- или как внедрить CQRS без боли.