Ответ
Отделение бизнес-логики от инфраструктурного кода (работа с БД, фреймворками, внешними API) — это фундаментальный принцип проектирования, лежащий в основе таких архитектур, как Clean Architecture и Hexagonal Architecture.
Ключевые преимущества:
-
Повышение тестируемости. Бизнес-правила можно тестировать в полной изоляции, подменяя инфраструктурные зависимости (например, репозиторий базы данных) на mock-объекты. Это делает тесты быстрыми и надежными.
-
Гибкость и взаимозаменяемость. Можно легко заменить один инфраструктурный компонент на другой (например, сменить СУБД с PostgreSQL на MongoDB или перейти с REST на gRPC), не затрагивая ядро бизнес-логики.
-
Улучшение поддерживаемости. Код становится более организованным и понятным. Разработчики могут сфокусироваться на бизнес-требованиях, не отвлекаясь на детали реализации конкретной технологии.
Пример: Принцип инверсии зависимостей (DIP)
Вместо прямого вызова ORM, бизнес-логика зависит от абстракции (интерфейса).
Плохо: Логика смешана с инфраструктурой (Django ORM)
# services.py - бизнес-логика напрямую зависит от Django
from orders.models import Order
def complete_order(order_id: int):
# Прямая зависимость от конкретной реализации ORM
order = Order.objects.get(id=order_id)
if order.status != 'paid':
raise ValueError("Заказ не оплачен")
order.status = 'completed'
order.save() # Инфраструктурный вызов
Хорошо: Логика отделена через абстракцию (репозиторий)
# domain/repositories.py - Абстракция
from abc import ABC, abstractmethod
from .entities import Order
class OrderRepository(ABC):
@abstractmethod
def get_by_id(self, order_id: int) -> Order:
...
@abstractmethod
def save(self, order: Order):
...
# services.py - Чистая бизнес-логика
class OrderCompletionService:
def __init__(self, order_repo: OrderRepository):
self.order_repo = order_repo
def complete_order(self, order_id: int):
order = self.order_repo.get_by_id(order_id)
if not order.is_paid(): # Бизнес-правило в доменной модели
raise ValueError("Заказ не оплачен")
order.complete() # Изменение состояния внутри домена
self.order_repo.save(order)
В этом случае OrderCompletionService
ничего не знает о Django. Реализация OrderRepository
может использовать Django ORM, SQLAlchemy или даже обращаться к файловой системе, но сервис останется неизменным.