[Репозитории в DDD: как правильно работать с данными в доменном слое]
Привет! Сегодня разберём ещё одну важную концепцию Domain-Driven Design — Репозитории (Repositories). Когда я только начал изучать DDD, репозитории казались мне просто "прослойкой над базой данных". Давайте разберёмся, зачем они нужны и как их правильно использовать!
Репозиторий (Repository) — это абстракция, которая:
✔️ Инкапсулирует доступ к данным (БД, API, файлы и т. д.).
✔️ Предоставляет "коллекцию" доменных объектов (как если бы они хранились в памяти).
✔️ Работает только с Aggregate Roots (не с отдельными Entity или Value Object!).
Пример из жизни:
Если
- Сохранять заказ (save).
- Загружать заказ по ID (find_by_id).
- Искать заказы по критериям (find_all_by_customer).
Но он НЕ даёт прямого доступа к
Ниже пример кода.
Почему репозитории — это важно?
1) Отделение домена от инфраструктуры
Домен не знает, как хранятся данные (БД, API, CSV и т. д.).
2) Гибкость
Можно легко поменять базу данных, не трогая доменную логику.
3) Соблюдение DDD-принципов
Работа только с агрегатами, а не с отдельными таблицами БД.
Где должны находиться репозитории в структуре проекта?
Репозитории относятся к инфраструктурному слою, но их интерфейсы (абстракции) определяются в доменном слое.
Ниже пример классической структуры проекта по слоям DDD.
```bash
src/
├── domain/
│ ├── models/
│ ├── repositories/
│ └── services/
│
├── infrastructure/
│ ├── db/
│ ├── repositories/
│ └── caching/
│
├── application/
│ └── services/
│
└── presentation/
```
Типичные ошибки
❌ Репозиторий для каждой Entity
Репозиторий должен быть только для Aggregate Root!
❌ Возвращение DTO вместо доменных объектов
Репозиторий должен возвращать
❌ Нарушение CQRS
Для запросов (Read) иногда лучше использовать отдельные запросы в cлое приложения, а не репозитории.
P.s.
Полезные ссылки по теме:
1) https://dddinpython.hashnode.dev/implementing-the-repository-pattern
2) https://dddinpython.hashnode.dev/implementing-the-repository-pattern-using-sqlalchemy
#DDD #Repository #DomainDrivenDesign #Программирование #Python
Привет! Сегодня разберём ещё одну важную концепцию Domain-Driven Design — Репозитории (Repositories). Когда я только начал изучать DDD, репозитории казались мне просто "прослойкой над базой данных". Давайте разберёмся, зачем они нужны и как их правильно использовать!
Репозиторий (Repository) — это абстракция, которая:
✔️ Инкапсулирует доступ к данным (БД, API, файлы и т. д.).
✔️ Предоставляет "коллекцию" доменных объектов (как если бы они хранились в памяти).
✔️ Работает только с Aggregate Roots (не с отдельными Entity или Value Object!).
Пример из жизни:
Если
Order
— это агрегат, то OrderRepository позволяет:- Сохранять заказ (save).
- Загружать заказ по ID (find_by_id).
- Искать заказы по критериям (find_all_by_customer).
Но он НЕ даёт прямого доступа к
OrderItem
— только через корень (Order
).Ниже пример кода.
from abc import ABC, abstractmethod
from uuid import UUID
from typing import List, Optional
from .order import Order # Агрегат
class OrderRepository(ABC):
"""Абстракция репозитория"""
@abstractmethod
def save(self, order: Order) -> None:
pass
@abstractmethod
def find_by_id(self, order_id: UUID) -> Optional[Order]:
pass
@abstractmethod
def find_all_by_customer(self, customer_id: UUID) -> List[Order]:
pass
from sqlalchemy.orm import Session
class SQLOrderRepository(OrderRepository):
"""SQL реализация (через SQLAlchemy)"""
def __init__(self, session: Session):
self.session = session
def save(self, order: Order) -> None:
self.session.add(order)
self.session.commit()
def find_by_id(self, order_id: UUID) -> Optional[Order]:
return self.session.query(Order).filter_by(order_id=order_id).first()
def find_all_by_customer(self, customer_id: UUID) -> List[Order]:
return self.session.query(Order).filter_by(customer_id=customer_id).all()
Почему репозитории — это важно?
1) Отделение домена от инфраструктуры
Домен не знает, как хранятся данные (БД, API, CSV и т. д.).
2) Гибкость
Можно легко поменять базу данных, не трогая доменную логику.
3) Соблюдение DDD-принципов
Работа только с агрегатами, а не с отдельными таблицами БД.
Где должны находиться репозитории в структуре проекта?
Репозитории относятся к инфраструктурному слою, но их интерфейсы (абстракции) определяются в доменном слое.
Ниже пример классической структуры проекта по слоям DDD.
```bash
src/
├── domain/
│ ├── models/
│ ├── repositories/
│ └── services/
│
├── infrastructure/
│ ├── db/
│ ├── repositories/
│ └── caching/
│
├── application/
│ └── services/
│
└── presentation/
```
Типичные ошибки
❌ Репозиторий для каждой Entity
Репозиторий должен быть только для Aggregate Root!
❌ Возвращение DTO вместо доменных объектов
Репозиторий должен возвращать
Order
, а не OrderData
.❌ Нарушение CQRS
Для запросов (Read) иногда лучше использовать отдельные запросы в cлое приложения, а не репозитории.
P.s.
Полезные ссылки по теме:
1) https://dddinpython.hashnode.dev/implementing-the-repository-pattern
2) https://dddinpython.hashnode.dev/implementing-the-repository-pattern-using-sqlalchemy
#DDD #Repository #DomainDrivenDesign #Программирование #Python