DON'T STOP AND CODE
92 subscribers
41 photos
1 video
1 file
109 links
Мой путь в программировании
#python

Для связи: @avagners
Download Telegram
[Domain Services в DDD: Логика, которая не принадлежит агрегатам]
(Когда и зачем использовать доменные сервисы?)

Продолжаю знакомиться с DDD. Следующий паттерн Domain Services.

Domain Service - это класс, который реализует бизнес-правила, выходящие за рамки одного агрегата.

В Domain-Driven Design (DDD) не вся бизнес-логика уместна внутри агрегатов или сущностей.
Иногда операции:
- Затрагивают несколько агрегатов,
- Зависят от внешних систем (например, проверка кредитного рейтинга),
- Не имеют естественного места в какой-то одной сущности.

Для такой логики создают Domain Services (доменные сервисы).

Отличия от других сервисов в DDD
Domain Service — содержит только бизнес-логику, не зависит от инфраструктуры.
Application Service — оркестрирует вызовы Domain-сервисов и инфраструктуры (например, «создать заказ → сохранить в БД → отправить уведомление»).
Infrastructure Service — технические детали (отправка почты, запросы к API).

Когда использовать Domain Service?
Логика требует нескольких агрегатов.
Зависит от доменных правил, но не принадлежит ни одной сущности (например, проверка сложных условий).
Чистая бизнес-логика без инфраструктурных деталей.

Не используйте, если:
- Логика относится к одному агрегату (лучше поместить в агрегат).
- Нужен доступ к БД, API и т.д. (это Application/Infrastructure Service).

✔️ Плюсы:
- Четкое разделение ответственности.
- Удобство тестирования (чистая логика без побочных эффектов).

Минусы:
- Риск превращения в "God Object" (если сервис делает слишком много).

Domain Services — это мост между агрегатами для сложной доменной логики.

P.s.
Полезная ссылка по теме:
https://enterprisecraftsmanship.com/posts/domain-vs-application-services/

#DDD #DomainServices #CleanArchitecture
[Use Case в DDD: как проектировать сценарии взаимодействия с системой]

Привет! Сегодня поговорим про Use Case (Сценарии использования) — один из ключевых элементов DDD и чистой архитектуры.

1. Что такое Use Case?
Use Case (Сценарий использования) — это:
✔️ Описание конкретного бизнес-действия (например, "Оформление заказа", "Отмена бронирования").
✔️ Изолированная логика, которая координирует работу домена и инфраструктуры.
✔️ Мост между presentation (API/UI) и domain (бизнес-правила).

Примеры:
CreateOrderUseCase → создание заказа.
CancelBookingUseCase → отмена бронирования.
ProcessPaymentUseCase → обработка платежа.

2. Где находятся Use Case в структуре проекта?

Они относятся к application-слою (слое приложения):
src/
├── domain/
├── application/ # Use Cases + Application Services/CQS
│ ├── use_cases/
│ │ ├── commands/
│ │ └── queries/
│ └── services/
├── infrastructure/
└── api/


3. Пример use case "Создание заказа"
# /delivery/core/application/use_cases/commands/create_order/create_order_handler.py
from dataclasses import dataclass

from core.domain.model.order_aggregate.order import Order
from core.domain.model.shared_kernel.location import Location
from core.application.use_cases.commands.create_order.create_order_command import CreateOrderCommand
from infrastructure.adapters.postgres.unit_of_work import UnitOfWork


@dataclass
class CreateOrderCommandHandler:
unit_of_work: UnitOfWork

def handle(self, massege: CreateOrderCommand) -> None:

# Получаем геопозицию из Geo (пока ставим рандомное значение)
location = Location.create_random_location()

# Создаем заказ
order = Order(
order_id=massege.basket_id, # ID заказа совпадает с ID корзины
location=location
)

# Сохраняем
with self.unit_of_work as uow:
uow.orders.add(order)


4. Почему Use Case — это важно?
- Чёткое разделение ответственности
Presentation-слой (API/CLI) не должен содержать бизнес-логику.
Domain-слой не должен знать о внешних сервисах (API, БД).

- Упрощение тестирования
Use Case можно тестировать изолированно, подменяя репозитории на заглушки.

- Гибкость
Один Use Case может быть вызван из разных мест: API, CLI, фоновой задачи.

- Документирование системы
Названия Use Cases (CreateOrder, CancelBooking) явно описывают, что делает система.

5. Типичные ошибки

Use Case = "God Object"
Не нужно пихать всю логику в один Use Case. Разбивайте на мелкие сценарии.

Логика в контроллерах
Код вида if user.is_admin: ... должен быть в Use Case или домене, не в API.

#DDD #UseCase #CleanArchitecture #Python
[Input Adapters в DDD: как внешний мир общается с приложением]

Привет! Сегодня про Input Adapters — элемент гексагональной архитектуры (и DDD), который отвечает за преобразование внешних запросов (HTTP, CLI, события) в команды приложения.

1. Что это такое?

Input Adapter — это не только про REST-эндпоинты, а это единая точка входа для всех внешних взаимодействий.

Он:
- Парсит входящие данные (JSON, protobuf, CLI-аргументы).
- Валидирует их (например, через Pydantic).
- Вызывает Use Case (Command или Query).
- Не содержит бизнес-логики (это задача домена).

Примеры Input Adapters:
- REST API (FastAPI, Django View).
- CLI-команды (Click, Typer).
- Обработчики событий (Kafka Consumer).
- WebSocket-хэндлеры.

Ниже пример REST API
# presentation/api/rest/order_adapters.py
from fastapi import APIRouter, Depends

from application.commands import CreateOrderCommand
from presentation.schemas import OrderCreateRequest

router = APIRouter()

@router.post("/orders")
async def create_order(
request: OrderCreateRequest, # Pydantic-модель для валидации
command: CreateOrderCommand = Depends(), # Use Case
):
# Преобразуем запрос в DTO (без бизнес-логики!)
order_id = command.execute(
user_id=request.user_id,
items=[item.to_domain() for item in request.items]
)
return {"order_id": order_id}


2. Где находятся Input Adapters в структуре проекта?

Они относятся к presentation-слою, но могут выноситься в отдельный модуль для сложных сценариев:

src/
├── domain/
├── application/
├── infrastructure/
└── presentation/ # Input Adapters
├── api/ # HTTP-адаптеры
│ ├── rest/ # REST (FastAPI)
│ └── graphql/ # GraphQL
├── cli/ # CLI-адаптеры (Click)
└── events/ # Обработчики событий (Kafka, RabbitMQ)


3. Почему Input Adapters — это важно?

- Изоляция домена
Домен не знает, откуда пришёл запрос (HTTP, Kafka или CLI).

- Гибкость
Можно добавить новый адаптер (например, gRPC), не меняя Use Case.

- Тестируемость
Адаптеры легко тестировать в изоляции (например, мокая Use Case).

- Согласованность
Все входные данные проходят одинаковую валидацию перед передачей в Use Case.

4. Типичные ошибки

Бизнес-логика в адаптерах
Код вида if user.role == "admin" должен быть в домене, а не в REST-хэндлере.

Прямая работа с репозиториями
Адаптер вызывает только Use Case, не лезет в БД напрямую.

5. Вывод
Input Adapters — это "входные ворота" приложения, которые:
🔹 Преобразуют внешние запросы в команды/запросы.
🔹 Не содержат логики (только парсинг и валидацию).
🔹 Делают систему гибкой к изменениям протоколов.

#DDD #CleanArchitecture #InputAdapters #Python