Привет Хабр! В этой статье мне бы хотелось рассказать про чистую архитектуру Роберта Мартина. Чистая архитектура это набор правил и идей, которые делают систему независимой от фреймворков, UI, баз данных и любых внешних агентов. Цель — создать систему, которую легко тестировать, поддерживать и изменять. Попытаюсь рассказать вам все кратко и понятно.

1. Фундаментальное правило: Зависимости направлены внутрь

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

2. Принцип разделения на слои (Концентрические круги)

Архитектура делится на концентрические круги (слои), где каждый внутренний круг — это более высокий уровень политик (бизнес-логики), а внешний — детали реализации.

От внутренних к внешним:

  1. Entities (Сущности): Ядро системы. Это бизнес-объекты и правила, которые не меняются при изменении внешних обстоятельств. Например, класс BankAccount с методом calculateInterest().

  2. Use Cases (Сценарии использования): Содержат специфическую бизнес-логику для конкретного приложения. Они определяют, как внешний мир взаимодействует с сущностями для достижения цели (например, TransferMoneyUseCase). Они ничего не знают о UI или базе данных.

  3. Interface Adapters (Адаптеры интерфейсов): Преобразуют данные между форматами, удобными для Use Cases и Entities, и форматами, удобными для внешних агентов (например, базы данных, веб-фреймворков). Сюда входят:

    Контроллеры (Presenters, ViewModels)

    Шлюзы (Gateways) / Репозитории (Repositories) — интерфейсы, которые определяют, какие данные нужны Use Cases, но не как они будут получены.

  4. Frameworks & Drivers (Фреймворки и драйверы): Внешний слой: база данных (PostgreSQL, MongoDB), веб-фреймворки (Spring, Express), UI, внешние API, библиотеки и т.д.

3. Принцип зависимостей (Dependency Rule)

Это техническая реализация 1-го пункта. Код зависимостей может указывать только внутрь, к центру. Это означает:

  • Внутренний круг не должен ничего знать о внешнем круге. Имя класса, типа данных, функции или любой другой сущности из внешнего круга не должно упоминаться во внутреннем круге.

  • Внешний круг реализует интерфейсы, объявленные во внутреннем круге (например, UserRepository интерфейс объявлен в слое Use Cases/Entities, а его реализация MySQLUserRepository — во внешнем слое). Это достигается с помощью инверсии зависимостей (DIP).

4. Принцип инверсии зависимостей (Dependency Inversion Principle — DIP)

Модули верхнего уровня (бизнес-логика) не должны зависеть от модулей нижнего уровня (детали реализации). Оба должны зависеть от абстракций (интерфейсов).

  • Бизнес-логика объявляет, какие данные ей нужны (например, "мне нужен способ сохранить пользователя" → интерфейс UserRepository).

  • Внешний слой предоставляет реализацию этой абстракции (например, UserMongoRepository).

5. Принцип единственной ответственности для слоёв

Каждый слой, компонент и класс должен иметь одну, четко определенную причину для изменения. Изме��ения в способе рендеринга UI (внешний слой) не должны влиять на бизнес-правила (внутренний слой) и наоборот.

6. Принцип тестируемости

Бизнес-правила (Entities и Use Cases) должны быть полностью тестируемыми без UI, базы данных, веб-сервера или любого другого внешнего элемента. Их можно тестировать с помощью модульных тестов, используя заглушки (stubs) и моки (mocks) для интерфейсов репозиторий и презентеров.

Ключевые выгоды (Почему это стоит делать):

  1. Независимость от фреймворков: Ядро приложения не привязано к Spring, Django, React и т.д. Их можно заменить с минимальными затратами.

  2. Тестируемость: Бизнес-логику можно тестировать в изоляции.

  3. Независимость от UI: UI может меняться (веб, консоль, мобильное приложение) без изменения бизнес-правил.

  4. Независимость от базы данных: Вы можете легко сменить MongoDB на PostgreSQL или наоборот, потому что база данных — это "деталь", которая подключается через интерфейс.

  5. Независимость от внешних агентов: Бизнес-правила ничего не знают о внешних API, сторонних сервисах и т.д.

Делитесь своими впечатлениями от статьи в комментариях!