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

Для связи: @avagners
Download Telegram
[Репозитории в DDD: как правильно работать с данными в доменном слое]

Привет! Сегодня разберём ещё одну важную концепцию 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