# Domain-Driven Design (DDD) ## Навигация - [🏠 Главная страница курса](../../../README.md) - [📚 Модуль 2](../README.md) --- ## Что такое DDD **Domain-Driven Design** — это подход к разработке программного обеспечения, который: - Фокусируется на бизнес-домене - Использует единый язык (Ubiquitous Language) - Разделяет систему на ограниченные контексты (Bounded Contexts) ## Стратегическое проектирование ### 1. Bounded Context (Ограниченный контекст) **Определение:** Четко определенная граница, внутри которой модель домена применима. **Пример:** ``` E-commerce система: - Order Context → заказы, платежи - Inventory Context → товары, склад - Customer Context → клиенты, профили - Shipping Context → доставка, логистика ``` ### 2. Context Map (Контекстная карта) **Определение:** Диаграмма, показывающая отношения между ограниченными контекстами. **Типы отношений:** - **Shared Kernel** — общая модель - **Customer-Supplier** — клиент-поставщик - **Conformist** — соответствие - **Anticorruption Layer** — антикоррупционный слой - **Open Host Service** — открытый хост-сервис - **Published Language** — опубликованный язык ### 3. Ubiquitous Language (Единый язык) **Определение:** Общий язык, используемый командой для описания домена. **Принципы:** - Используется в коде - Используется в документации - Используется в общении - Эволюционирует с пониманием домена ## Тактическое проектирование ### 1. Entity (Сущность) **Определение:** Объект с уникальной идентичностью. ```java public class Order { private OrderId id; // уникальный идентификатор private CustomerId customerId; private List items; private OrderStatus status; // методы бизнес-логики public void addItem(ProductId productId, int quantity) { // бизнес-правила } } ``` ### 2. Value Object (Объект-значение) **Определение:** Объект без идентичности, определяемый только своими атрибутами. ```java public class Money { private final BigDecimal amount; private final Currency currency; public Money(BigDecimal amount, Currency currency) { this.amount = amount; this.currency = currency; } // методы для работы с деньгами public Money add(Money other) { if (!this.currency.equals(other.currency)) { throw new IllegalArgumentException("Different currencies"); } return new Money(this.amount.add(other.amount), this.currency); } } ``` ### 3. Aggregate (Агрегат) **Определение:** Граница консистентности данных. **Правила агрегатов:** - Один агрегат = одна транзакция - Ссылки только на корень агрегата - Обновления только через корень ```java public class Order { // корень агрегата private OrderId id; private CustomerId customerId; private List items; // сущности внутри агрегата private OrderStatus status; // методы для изменения состояния public void addItem(ProductId productId, int quantity) { // валидация бизнес-правил items.add(new OrderItem(productId, quantity)); } } ``` ### 4. Repository (Репозиторий) **Определение:** Интерфейс для доступа к агрегатам. ```java public interface OrderRepository { Order findById(OrderId id); void save(Order order); List findByCustomerId(CustomerId customerId); } ``` ### 5. Domain Service (Доменный сервис) **Определение:** Операция, которая не принадлежит ни одной сущности. ```java public class OrderPricingService { public Money calculateTotalPrice(Order order, PricingRules rules) { // сложная логика расчета цены // не принадлежит ни Order, ни PricingRules } } ``` ### 6. Domain Event (Доменное событие) **Определение:** Событие, произошедшее в домене. ```java public class OrderCreatedEvent { private final OrderId orderId; private final CustomerId customerId; private final LocalDateTime occurredAt; // конструктор и геттеры } ``` ## Event Storming (Мозговой штурм событий) **Event Storming** — методология для изучения домена через события. ### Процесс: 1. **Доменные события** — что происходит в системе 2. **Команды** — что вызывает события 3. **Агрегаты** — что обрабатывает команды 4. **Политики** — бизнес-правила 5. **Read Models** — что нужно для отображения ### Пример: ``` Команда: CreateOrder ↓ Агрегат: Order ↓ Событие: OrderCreated ↓ Политика: SendConfirmationEmail ↓ Команда: SendEmail ```