Привет Хабр! В этой статье мне бы хотелось рассказать про чистую архитектуру Роберта Мартина. Чистая архитектура это набор правил и идей, которые делают систему независимой от фреймворков, UI, баз данных и любых внешних агентов. Цель — создать систему, которую легко тестировать, поддерживать и изменять. Попытаюсь рассказать вам все кратко и понятно.
1. Фундаментальное правило: Зависимости направлены внутрь
Самый важный принцип, на котором всё держится. Зависимости в коде должны быть направлены к центру архитектуры, к самым важным бизнес-правилам. Внешние слои (UI, база данных, фреймворки) зависят от внутренних слоёв, а не наоборот. Бизнес-логика ничего не знает о том, как её данные сохраняются или как она отображается.
2. Принцип разделения на слои (Концентрические круги)
Архитектура делится на концентрические круги (слои), где каждый внутренний круг — это более высокий уровень политик (бизнес-логики), а внешний — детали реализации.
От внутренних к внешним:
Entities (Сущности): Ядро системы. Это бизнес-объекты и правила, которые не меняются при изменении внешних обстоятельств. Например, класс
BankAccountс методомcalculateInterest().Use Cases (Сценарии использования): Содержат специфическую бизнес-логику для конкретного приложения. Они определяют, как внешний мир взаимодействует с сущностями для достижения цели (например,
TransferMoneyUseCase). Они ничего не знают о UI или базе данных.Interface Adapters (Адаптеры интерфейсов): Преобразуют данные между форматами, удобными для Use Cases и Entities, и форматами, удобными для внешних агентов (например, базы данных, веб-фреймворков). Сюда входят:
Контроллеры (Presenters, ViewModels)
Шлюзы (Gateways) / Репозитории (Repositories) — интерфейсы, которые определяют, какие данные нужны Use Cases, но не как они будут получены.
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) для интерфейсов репозиторий и презентеров.
Ключевые выгоды (Почему это стоит делать):
Независимость от фреймворков: Ядро приложения не привязано к Spring, Django, React и т.д. Их можно заменить с минимальными затратами.
Тестируемость: Бизнес-логику можно тестировать в изоляции.
Независимость от UI: UI может меняться (веб, консоль, мобильное приложение) без изменения бизнес-правил.
Независимость от базы данных: Вы можете легко сменить MongoDB на PostgreSQL или наоборот, потому что база данных — это "деталь", которая подключается через интерфейс.
Независимость от внешних агентов: Бизнес-правила ничего не знают о внешних API, сторонних сервисах и т.д.
Делитесь своими впечатлениями от статьи в комментариях!
