← Назад к вопросам

Хорошо ли когда бизнес логика не зависит от инфраструктуры

1.0 Junior🔥 251 комментариев
#DevOps и инфраструктура#Django

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Независимость бизнес-логики от инфраструктуры

Да, это абсолютно хорошо и является одним из ключевых принципов современной архитектуры программного обеспечения. Это фундамент чистой архитектуры, DDD (Domain-Driven Design) и SOLID принципов.

Почему это важно

Гибкость и масштабируемость — когда бизнес-логика не зависит от технических деталей, вы можете легко:

  • Менять базу данных (PostgreSQL → MongoDB)
  • Переходить на другой фреймворк
  • Внедрять новые внешние сервисы
  • Масштабировать приложение

При этом бизнес-логика остаётся неизменной и не требует переписания.

Архитектурные принципы

Clean Architecture (Чистая архитектура) предлагает следующую структуру слоёв:

┌─────────────────────────────────┐
│   Presentation (UI, API)        │ ← Самый внешний слой
├─────────────────────────────────┤
│   Application (Use Cases)       │
├─────────────────────────────────┤
│   Domain (Entities, Rules)      │ ← Бизнес-логика
├─────────────────────────────────┤
│   Infrastructure (DB, APIs)     │ ← Самый внутренний слой
└─────────────────────────────────┘

Зависимости только ВНУТРЬ (от внешних слоёв к внутренним)

Domain — это центр, который содержит чистую бизнес-логику без знания о базах данных, веб-фреймворках или HTTP.

Практический пример

# ❌ ПЛОХО: бизнес-логика зависит от инфраструктуры
from django.db import models

class User(models.Model):  # Django привязка
    name = models.CharField(max_length=100)
    email = models.EmailField()
    
    def process_payment(self, amount):
        # Бизнес-логика смешана с ORM
        if self.balance >= amount:
            self.balance -= amount
            self.save()  # Django-зависимость!
            return True
        return False
# ✅ ХОРОШО: разделение concerns
# domain/user.py
class User:
    """Чистая бизнес-логика, без зависимостей от фреймворков"""
    def __init__(self, name: str, email: str, balance: float):
        self.name = name
        self.email = email
        self.balance = balance
    
    def process_payment(self, amount: float) -> bool:
        """Бизнес-правило: можно ли списать сумму"""
        if amount > 0 and self.balance >= amount:
            self.balance -= amount
            return True
        return False

# infrastructure/repositories.py
from django.db import models
from domain.user import User

class DjangoUser(models.Model):
    """ORM модель — только для персистентности"""
    name = models.CharField(max_length=100)
    email = models.EmailField()
    balance = models.DecimalField(max_digits=10, decimal_places=2)

class UserRepository:
    """Repository pattern — абстракция над хранилищем данных"""
    def save(self, user: User) -> None:
        django_user = DjangoUser.objects.get(email=user.email)
        django_user.balance = user.balance
        django_user.save()
    
    def find_by_email(self, email: str) -> User:
        django_user = DjangoUser.objects.get(email=email)
        return User(
            name=django_user.name,
            email=django_user.email,
            balance=float(django_user.balance)
        )

# application/use_cases.py
class ProcessPaymentUseCase:
    def __init__(self, repository: UserRepository):
        self.repository = repository
    
    def execute(self, email: str, amount: float) -> bool:
        user = self.repository.find_by_email(email)
        success = user.process_payment(amount)  # Чистая бизнес-логика
        if success:
            self.repository.save(user)
        return success

Преимущества такого подхода

  1. Тестируемость — легко писать unit-тесты без базы данных:
import pytest

def test_user_cannot_pay_more_than_balance():
    user = User(name="John", email="john@example.com", balance=100)
    assert user.process_payment(150) is False  # Не зависит от DB!
    assert user.balance == 100

def test_user_can_pay_within_balance():
    user = User(name="John", email="john@example.com", balance=100)
    assert user.process_payment(50) is True
    assert user.balance == 50
  1. Переносимость — бизнес-логика работает везде:
  • В разных фреймворках (Django, FastAPI, Flask)
  • В разных БД (PostgreSQL, MongoDB, SQLite)
  • В CLI, Telegram Bot, Web API
  1. Поддержка и эволюция — когда приходит новый разработчик, ему легче понять чистую бизнес-логику без знания всех технических деталей.

SOLID принципы в контексте

Dependency Inversion Principle — классический пример:

# Определяем абстракцию (интерфейс)
from abc import ABC, abstractmethod

class UserRepository(ABC):
    @abstractmethod
    def save(self, user: User) -> None:
        pass
    
    @abstractmethod
    def find_by_email(self, email: str) -> User:
        pass

# Конкретные реализации
class PostgresUserRepository(UserRepository):
    def save(self, user: User) -> None:
        # PostgreSQL-specific code
        pass

class MongoUserRepository(UserRepository):
    def save(self, user: User) -> None:
        # MongoDB-specific code
        pass

# Use case зависит от абстракции, а не от конкретной реализации
class ProcessPaymentUseCase:
    def __init__(self, repository: UserRepository):  # Принимаем интерфейс!
        self.repository = repository

Вы можете в любой момент поменять PostgresUserRepository на MongoUserRepository без изменения ProcessPaymentUseCase.

Заключение

Чтобы ответить на вопрос: Да, это не только хорошо, но и необходимо для создания качественного, масштабируемого и поддерживаемого кода. Разделение бизнес-логики от инфраструктуры — это основа профессиональной разработки и следование современным архитектурным паттернам.