TGViewer
DON'T STOP AND CODE DON'T STOP AND CODE @start_py · 100 subscribers
Post #567 128
[Репозитории в 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
  • 👍 3
More from @start_py
  1. Sep 25, 2026[Скорость моделей] Стал обращать исключительное внимание в работе на скорость ответа ии-мо…
  2. Aug 16, 2026[Санкции] Failed to load URL https://www.nvidia.com/ru-ru/geforce/billboards/displaydriver…
  3. Jul 29, 2026[Будни вайбкодера. Или как ИИ не мог выключить проверку SSL] Сейчас была очередная забавна…
  4. Jul 20, 2026[Про впн, прокси и первый опыт с живыми пользователями] Этой весной, когда начались массов…
  5. Jul 7, 2026Наше время ограничено. "На экзистенциальном уровне :) у нас не так уж и много времени на э…
  6. Jul 2, 2026"если вам нужно прочитать исходный код функции, чтобы понять, что она делает (в частности,…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →