Привет Хабр! В этой статье мне бы хотелось рассказать про чистую архитектуру Роберта Мартина. Чистая архитектура это набор правил и идей, которые делают систему независимой от фреймворков, 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, сторонних сервисах и т.д.
Делитесь своими впечатлениями от статьи в комментариях!
Комментарии (9)

Emelian
11.01.2026 14:07UI может меняться (веб, консоль, мобильное приложение) без изменения бизнес-правил
А GUI (оконные приложения)? – Не, не, не слышали!

Akon32
11.01.2026 14:07"Чистая архитектура" по идее позволяет относительно легко подключать любые ui к приложению, в т.ч. gui. Взаимодействие с gui выполняется через интерфейсы. Бизнес-логика, работа с БД вынесены в отдельные классы, поэтому смена ui ни на что не влияет (при "правильной" реализации, естественно). Возможна ли такая реализация во всех случаях - отдельный вопрос, но на небольших проектах у меня получалось подключать cli и gui через единый интерфейс.

Emelian
11.01.2026 14:07Взаимодействие с gui выполняется через интерфейсы.
Практически, так никто не делает. Хотя я, в качестве эксперимента, пробовал этот вариант (см. мою статью: «Модульное программирование в C++. Статические и динамические плагины» в https://habr.com/ru/articles/566864/ ). Там как раз использовались интерфейсы (статические и динамические плагины) для создания GUI. Идея интересная, но народ её воспринял в штыки, поскольку это не вписывалось в парадигму: «Есть только два мнения: моё и неправильное!».
Бизнес-логика, работа с БД вынесены в отдельные классы, поэтому смена ui ни на что не влияет (при "правильной" реализации, естественно).
В своей статье: «Новая компьютерная программа для запоминания иностранных слов и фраз» ( https://habr.com/ru/articles/848836/ ) я, практически, этим и занимался.
Только я бы не сказал, что это всё просто. В данном случае, вместо «бизнес-логики» использовалась «программная логика», в качестве «БД» – «Sqlite», Для классов, главной проблемой была организация их в иерархию. Нужно было, чтобы одна база данных выдавала разные данные для шести режимов работы в разных «видах» (т.е., дочерних окнах) плюс дополнительный выбор на фильтрацию и сортировку данных, с учетом выбранных пунктов меню.
В MFC, подобная парадигма называлась «Документ-Вид», т.е., одному «окументу» (порции данных из БД) сопоставлялась несколько дочерних окон («видов»), в которых они могли быть представлены по-разному. Причем управление этими данными, осуществлялось через обработчики сообщений, которые имеют свою иерархию в циклах сообщений (от родительского окна к его потомкам). При этом, теоретическим, могут еще использоваться потоки (хотя режим «Видео», для своих данных, я реализовал с помощью таймера),
Да, MFC я не использовал из-за его трудно обходимых недостатков, а применял WTL, очень близкому к WinAPI, что не слишком упрощало разработку.
Кроме того, иерархия классов работала не только с одной БД, но и с разной графикой, различной для разных видов (графический текст, звук, фоновый изображения и логотипы, а также их корректное обновление при изменении размеров и т.п.).
Всё это, вместе, составило чрезвычайно сложный алгоритм взаимодействия разрабатываемых классов. Я себе чуть мозги не сломал, пока не добился, более-менее, приемлемого результата. Да, он не оптимальный, но, вполне рабочий. Со временем, займусь его оптимизацией и, возможно, опубликую весь код.
Поэтому, насчет «не влияет», я бы не сказал. GUI менять на UI / web / консоль и т.п., не нужно от слова «совсем». Нужно, просто добиться разной работы программной логики в разных видах (по факту, режимах работы). Эти «режимы работы» можно добавлять (в которых одни и те же порции данных из БД будут разными и отображаться по-разному в разных видах), но не более. «Кросплатформа» тоже не актуальна, тратить на нее силы не вижу смысла.
Возможна ли такая реализация во всех случаях - отдельный вопрос, но на небольших проектах у меня получалось подключать cli и gui через единый интерфейс.
Однако, «количество переходит в качество», поэтому, уже даже для «средних» проектов, вроде описанного, ситуация сильно усложняется, а концепцию «чистой архитектуры» нужно, очевидно, дополнять собственными идеями.

errorcost
11.01.2026 14:07Независимость
Это как купить УАЗ, чтобы ездить на работу, потому что «а вдруг дорогу размоет (или снег пойдет), а я готов». В итоге 10 лет стоишь в пробке, а дороги так ни разу и не размыло.

Stanislav_Z
11.01.2026 14:07Такой информации довольно много в открытом доступе. Было бы интереснее, если бы Вы взяли реальную компанию/бизнес, описали бы её подробно человеческим языком, а потом показали бы архитектуру для неё. Хочется больше авторства в таких статьях, а не копипаст

Akon32
11.01.2026 14:07Боюсь, такое обычно под NDA... Впрочем, можно попробовать соорудить pet project, но эта "чистая архитектура" не слишком приятна при реализации.

mityukov
11.01.2026 14:07Не первый раз вижу эту тему, как тут все кристально, по полочкам, идеально.. но вот только начал читать, и сразу же возник вопрос: почему "посчитать процент" это метод у сущности, а "перевести деньги" - это use case? Кто определяет границу?

Akon32
11.01.2026 14:07Чистую архитектуру уже кто только не разбирал... Например тут - https://habr.com/ru/articles/905148/

как правильно сами знаете что Картинка оттуда показывает, что любой hello world должен состоять минимум из 13 классов/интерфейсов. На практике мало кто так делает :) Обычно проект гвоздями прибивают ко фреймворку, интерфейсы тоже в принципе не обязательны... и т.д. И вроде нормально работает.
На мой взгляд, очень полезны следующие идеи из "чистой архитектуры": инверсия зависимостей (и всё, что говорится о зависимостях), тестируемость, слои (как хоть какая-то структура кода), и также идея о том, что "СУБД, UI, интеграции - это маловажные детали реализации, а более важен домен и его работа". Этим идеям нужно следовать в большинстве проектов, без этого даже средне-малый проект может оказаться тяжёлым для разработки.
Остальные идеи тоже хороши, но порождают переусложнение на ровном месте.
jlllk
Шо, опять?! ©