Ответ
Domain-Driven Design (DDD) — это подход к разработке сложного программного обеспечения, который фокусируется на доменной логике (бизнес-правилах) и ее точном отражении в коде.
Ключевые строительные блоки DDD, которые я применял:
- Агрегат (Aggregate) — кластер связанных объектов (Entity и Value Object), рассматриваемых как единое целое. Доступ к ним идет через корень агрегата (Aggregate Root).
- Entity — объект, имеющий уникальный идентификатор и жизненный цикл.
- Value Object — иммутабельный объект, идентифицируемый по значениям его полей (например,
Moneyс суммой и валютой). - Репозиторий (Repository) — абстракция для хранения и извлечения агрегатов, скрывающая детали инфраструктуры.
- Сервис домена (Domain Service) — операция, которая не естественным образом принадлежит какой-либо Entity или Value Object.
Пример фрагмента доменного слоя на Java:
// Value Object
public record CustomerId(UUID value) {}
// Aggregate Root (Entity)
public class Order {
private OrderId id;
private CustomerId customerId;
private List<OrderLine> lines; // OrderLine — это Entity внутри агрегата
private OrderStatus status;
// Доменная логика внутри агрегата
public void addItem(ProductId productId, Quantity quantity, Price price) {
// Проверка инвариантов (бизнес-правил)
Objects.requireNonNull(productId);
if (quantity.value() <= 0) {
throw new IllegalArgumentException("Quantity must be positive");
}
this.lines.add(new OrderLine(productId, quantity, price));
}
public void cancel() {
if (!status.canBeCancelled()) {
throw new IllegalStateException("Order cannot be cancelled");
}
this.status = OrderStatus.CANCELLED;
}
}
// Repository интерфейс в доменном слое
public interface OrderRepository {
Optional<Order> findById(OrderId id);
void save(Order order);
}
Применял DDD в проектах со сложной и изменчивой бизнес-логикой. Это помогает:
- Сделать код понятным для экспертов предметной области.
- Изолировать ядро системы от инфраструктурных деталей (БД, фреймворки).
- Управлять сложностью через ограниченные контексты (Bounded Contexts).
Ответ 18+ 🔞
Вот, слушай, смотри, как оно на самом деле бывает. Сидишь ты такой, пыхтишь над очередным проектом, а там бизнес-логика такая, что мама не горюй. Вроде «добавить товар в корзину», а на деле — проверь остатки, примени три скидки, убедись, что клиент не в чёрном списке, и ещё хуй знает что. И вот тут-то, блядь, и выплывает эта самая Domain-Driven Design (DDD).
Не какая-то абстрактная хуйня, а реальный способ не сойти с ума. Всё крутится вокруг домена — то есть, вокруг этих самых бизнес-правил, которые заказчик тебе так красочно на пальцах объясняет. Задача — чтобы код стал их прямым отражением, а не этой спагетти-кашей из SQL-запросов и проверок в контроллере.
Вот на чём всё держится, основные киты, блядь:
- Агрегат (Aggregate) — это типа святой святых, такая банда объектов, которых нельзя трогать поодиночке. Как семья, блядь. Есть корень агрегата (Aggregate Root) — главный по тарелкам, через него со всеми и общаешься. Снаружи виден только он, а внутри у него свои Entity и Value Object орудуют.
- Entity — объект с характером. У него есть паспорт (уникальный ID), и он меняется со временем. Заказ, Пользователь — вот это всё.
- Value Object — объект без амбиций. Идентифицируется не по паспорту, а по тому, что в карманах лежит. Деньги (сумма + валюта), адрес (улица, дом). Создал — и забыл, он неизменяемый, как скала, блядь.
- Репозиторий (Repository) — этакий волшебный сундук. Говоришь ему: «Дай заказ №5» или «Сохрани этот заказ». А как он там внутри, в базе или в файле, это его проблемы. Абстракция, ёпта!
- Сервис домена (Domain Service) — операция, которой не место ни в Entity, ни в Value Object. Например, сложный расчёт, который требует данных из кучи разных агрегатов. Такой утилитарный мужик, который всем помогает.
Смотри, как это в коде выглядит, на живом примере:
// Value Object — просто данные, иммутабельные
public record CustomerId(UUID value) {}
// А вот это — корень агрегата! Entity, главный по заказу.
public class Order {
private OrderId id;
private CustomerId customerId;
private List<OrderLine> lines; // OrderLine — это уже внутренняя Entity, своя
private OrderStatus status;
// А вот и доменная логика, прямо тут, в теле! Не где-то в сервисе на 1000 строк.
public void addItem(ProductId productId, Quantity quantity, Price price) {
// Проверяем инварианты, бизнес-правила, ёба!
Objects.requireNonNull(productId);
if (quantity.value() <= 0) {
throw new IllegalArgumentException("Количество должно быть положительным, мудила!");
}
this.lines.add(new OrderLine(productId, quantity, price));
}
public void cancel() {
// Нельзя отменить уже отправленный заказ! Правило.
if (!status.canBeCancelled()) {
throw new IllegalStateException("Заказ уже не отменить, проехали!");
}
this.status = OrderStatus.CANCELLED;
// Тут ещё могут события какие-то генерироваться, но это уже другая история.
}
}
// Репозиторий — интерфейс, абстракция. Реализация — где-то в инфраструктуре.
public interface OrderRepository {
Optional<Order> findById(OrderId id);
void save(Order order);
}
Где это всё применять? Да там, где логика реально ебёт мозг, а не где «CRUD для блога». Когда за «простой» операцией стоит десяток проверок и правил. DDD помогает:
- Сделать так, чтобы заказчик и разработчик начинали говорить на одном языке. Код становится документом.
- Отделить святое (бизнес-правила) от грешного (базы данных, веб-фреймворки, апишки). Ядро системы чистое.
- Разрулить адскую сложность через ограниченные контексты (Bounded Contexts). Типа, в контексте «Доставка» у «Заказа» одни свойства, а в контексте «Оплата» — другие. И они не лезут друг другу в тарелку. Красота, ёпта!