Что такое Чистая архитектура и каковы ее ключевые принципы

Ответ

Чистая архитектура (Clean Architecture) — это предложенный Робертом Мартином (Uncle Bob) подход к проектированию программного обеспечения, цель которого — разделение ответственностей (Separation of Concerns) и создание системы, независимой от внешних факторов, таких как фреймворки, база данных или UI.

Архитектура строится на основе слоев, напоминающих луковицу, где внутренние слои ничего не знают о внешних.

Ключевой принцип — Правило зависимостей (The Dependency Rule)

Зависимости в исходном коде могут быть направлены только внутрь. Ничто во внутреннем круге не может знать что-либо о внешнем круге. В частности, код, реализующий бизнес-логику, не должен зависеть от деталей реализации (например, от конкретной СУБД).

Основные слои (от центра к периферии):

  1. Entities (Сущности): Объекты доменной логики, содержащие ключевые бизнес-правила. Они не зависят ни от чего.
  2. Use Cases (Сценарии использования): Реализуют специфичные для приложения бизнес-правила. Они оркестрируют поток данных к сущностям и от них.
  3. Interface Adapters (Адаптеры интерфейсов): Слой, который преобразует данные из формата, удобного для Use Cases и Entities, в формат, удобный для внешних систем (например, веб-фреймворка или базы данных). Сюда входят Presenters, Controllers, Gateways.
  4. Frameworks & Drivers (Фреймворки и драйверы): Самый внешний слой, содержащий конкретные реализации: веб-фреймворк (Django, FastAPI), СУБД (PostgreSQL), UI и т.д.

Пример на Python (упрощенно):

# 1. Entities (не зависит ни от чего)
class User:
    def __init__(self, name: str):
        if not name:
            raise ValueError("Name cannot be empty")
        self.name = name

# 2. Use Cases (зависит от абстракции репозитория)
from abc import ABC, abstractmethod

class UserRepository(ABC):
    @abstractmethod
    def save(self, user: User):
        pass

class CreateUserUseCase:
    def __init__(self, user_repo: UserRepository):
        self.user_repo = user_repo

    def execute(self, name: str):
        user = User(name)
        self.user_repo.save(user)
        return user

# 4. Frameworks & Drivers (реализация для внешнего слоя)
class InMemoryUserRepository(UserRepository):
    def save(self, user: User):
        print(f"User '{user.name}' saved in memory.")

# Использование
repo = InMemoryUserRepository()
use_case = CreateUserUseCase(repo)
new_user = use_case.execute("Alice")

Преимущества:

  • Независимость от фреймворков: Легко заменить веб-сервер или СУБД.
  • Тестируемость: Бизнес-логику можно тестировать в изоляции, без UI и базы данных.
  • Гибкость: Система легко адаптируется к изменениям требований.