Разделение намерений изменения и чтения
Функция либо меняет состояние (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 }