Commands / Queries

Разделение намерений изменения и чтения

Границы темы

  • Здесь — CQS (Command-Query Separation): правило проектирования методов и обработчиков.
  • Не про раздельные хранилища/модели — это уже CQRS (см. соответствующую презентацию).
  • Цель: повысить предсказуемость и тестируемость кода, убрав смешение чтения и побочных эффектов.

Command / Query Separation

Функция либо меняет состояние (Command), либо возвращает данные (Query), но не делает одновременно.
# Плохо: и побочный эффект, и возврат
class Cache:
    def get_or_clear(self):
        self.clear()          # side effect
        return self._values   # и возврат значения

# Хорошо: разделение
class Cache:
    def clear(self):
        self._values = {}
    def get(self):
        return self._values

Команды

from dataclasses import dataclass

@dataclass
class CreateUserCommand:
    name: str
    email: str
    password: str

class CreateUserHandler:
    def __init__(self, user_repo, mailer, hasher):
        self.user_repo = user_repo
        self.mailer = mailer
        self.hasher = hasher
    def handle(self, cmd: CreateUserCommand) -> int:
        if self.user_repo.find_by_email(cmd.email):
            raise ValueError('Exists')
        user = User.create(cmd.name, cmd.email, self.hasher.hash(cmd.password))
        self.user_repo.save(user)
        self.mailer.send_welcome(user.email)
        return user.id

Запросы

from dataclasses import dataclass

@dataclass
class GetUserQuery:
    user_id: int

class GetUserHandler:
    def __init__(self, user_read_repo):
        self.user_read_repo = user_read_repo
    def handle(self, q: GetUserQuery) -> dict:
        u = self.user_read_repo.find_by_id(q.user_id)
        if not u:
            raise ValueError('Not found')
        return { 'id': u.id, 'name': u.name, 'email': u.email }

Где используется

  • Внутри слоя приложения (чёткая организация кода)
  • Как часть CQRS (разделение моделей чтения/записи)
  • В pipeline-ах: validate → handle → publish

Паттерны рядом

  • Command Bus / Mediator — маршрутизация команд/запросов
  • Validation/Authorization Behaviors — cross-cutting (pipeline)
  • Eventing — публикация событий после команд