
Откройтелюбой пулл‑реквест в проекте с любой «чистой архитектурой», и вы скорее всего увидите не обсуждение бизнес‑логики, а срач. «Это нельзя класть в UseCase, это логика домена!», «Зачем тут еще один DTO, мы же просто поле прокидываем!», «Этот интерфейс не нужен, у нас никогда не будет другой реализации!». Полагаю, с очень многими такое случалось.
Это и есть главная проблема. «Чистая архитектура» — это не инженерная дисциплина. Это множество концепций, который каждый понимает по своему. И это касается не только чистой архитектуры, которую описывает «о великий Роберт Мартин». Это касается вообще всех архитектур. Из‑за отсутствия конкретных ответов каждая команда превращается в парламент, где все спорят, но никто ничего не может решить. Архитектура из инструмента для разработки превращается в причину, по которой разработка стоит на месте, а страдают все.
Если вам интересен процесс и вы хотите следить за дальнейшими материалами, буду признателен за подписку на мой телеграм‑канал. Там я публикую... ну примерно тоже самое, что и здесь. Только чаще и короче раз в миллион. А, ну и конечно мемы. МНОГО МЕМОВ.
Наглядный пример на котах: Что такое, бл***, Entity?
Это самый фундаментальный конфликт, с которого все начинается. Спросите двух разработчиков, что такое «Сущность», и вы получите два разных ответа, за которые они готовы умереть.
Лагерь первый: «Анемичные модели»
Эти ребята считают, что сущность — это просто набор полей, тупая структура данных. Отражение таблицы из базы. Вся логика должна жить в отдельных классах-сервисах.
// Сущность - просто данные
класс Кот {
переменная имя
переменная сытость // 0 - голоден, 100 - сыт
}
// Логика - в отдельном сервисе
класс СервисКормленияКотов {
функция покормить(кот, количество_еды) {
кот.сытость = кот.сытость + количество_еды
если (кот.сытость > 100) то {
кот сдох от обжорства
}
// ... какая-то еще логика
}
}
Их аргументы: это просто, это разделяет данные и поведение, это легко тестировать. Звучит неплохо.
Лагерь второй: «Богатые модели»
Эти же разработчики смотрят на предыдущий код как на процедурное го*но из прошлого века. Для них сущность — это полноценный объект, который сам управляет своим состоянием и поведением. Это основа ООП.
класс Кот {
переменная имя
приватная переменная сытость
функция покормить(количество_еды) {
// Логика инкапсулирована внутри объекта
эта.сытость = эта.сытость + количество_еды
если (эта.сытость > 100) то {
кот сдох от обжорства
}
// ...
}
}
Их аргументы: это правильно с точки зрения ООП, это предотвращает создание невалидных состояний бла, бла, бла и + еще 100500 аргументов. Сами придумаете, суть и так понятна
И вот в этом-то и заключается вся проблема. Не в том, что один подход хороший, а другой плохой. Проект, последовательно написанный на анемичных моделях, может быть успешным. Проект, целиком построенный на богатых моделях — тоже.
Проблема в том, что никто ни о чем не может, договориться.
Большинство людей банально по своему понимает каждую концепцию, а некоторые концепции типа DDD и вовсе не могут осилить. И в итоге проект превращается в шизофреника. В модуле Users у вас анемичные модели и толстые сервисы, потому что его писал один старший разработчик. В соседнем модуле Orders — богатые сущности, которые сами управляют своим состоянием, потому что его делал другой, адепт ООП.
Новый человек приходит в команду, смотрит на это лоскутное одеяло и у него взрывается мозг. Какому правилу следовать? А никакого правила нет. Есть только легаси монолит личные предпочтения и бесконечные споры на ревью. Архитектура перестает быть единым стандартом и превращается в набор личных фетишей. И пока идет эта война, проект стоит на месте, а технический долг растет не из-за плохих решений, а из-за их полного отсутствия.
И это только один, гиперболизированный пример. Таких вопросов, на которые нет ответа полно: каким должен быть эталонный UseCase? Нужно ли плодить DTO, чтобы передать один-единственный параметр между слоями? Можно ли использовать библиотеку для расчета даты прямо в сценарии, или это «загрязнение» и нарушение священных границ?
Этот список можно продолжать бесконечно. И пока команда не договорилась по каждому из этих пунктов, любой пулл-реквест превращается в минное поле.
Что делать? Перестать воевать и начать договариваться

Я пишу эту стать не только потому что это серьезная проблема, а еще и потому что у меня с этого конкретно горит. Настолько много срачей на всяких редитах, SO, что начинаешь уже сомневаться в шарообразности земли. Один говорит это, другой говорит то. Поэтому внести свою лепту я просто обязан, чтобы уменьшить этот процент детерменированности.
Надо перестать искать правоту в книгах, во всех этих формулировках и тоннах кода. Книги дают пищу для размышлений, а не готовые рецепты для вашего конкретного проекта. Единственный источник правды для вашей команды — это... ваша команда. Так вот дам советы, которые помогли мне и команде.
1. Напишите свой собственный закон.
Это не просто совет, это требование для существования продукта в целом. Соберитесь всей командой (да, это будет долгий и, возможно, неприятный митинг) и создайте один документ. Назовите его как угодно, это не имеет значения. И впишите туда четкие, однозначные правила по всем спорным вопросам.
Не «желательно использовать богатые модели», а «1. Сущности в нашем проекте — богатые. Логика, управляющая состоянием сущности находится в методах самой сущности».
Не «пж не усложняйте там», а «UseCase отвечает исключительно за оркестрацию — он координирует работу с адаптерами и доменными моделями. Любая логика, содержащая бизнес‑правила (условия, проверки, вычисления), должна находиться в слое domain, независимо от её сложности.
Примеры абстрактны, но понятны. Этот документ — устав. Ваш паспорт от холодильника. Любой спор на ревью решается ссылкой на него. Несогласен? Предлагай поправку в устав, обсуждайте ее всей командой, и если ее примут — меняйте правило для всех. Но не блокируй задачу коллеги из-за своих личных предпочтений.
2. Принцип YAGNI на стероидах
Одна из главных причин архитектурного онанизма — страх будущего и желание построить систему «на века». Мы создаем интерфейсы для каждого класса, потому что «а вдруг понадобится другая реализация?». Мы вводим сложнейшие абстракции, потому что «а вдруг бизнес захочет это поменять?». Ну вот все так делают, все пытаются создать архитектурный «шедевр».
Это то, что Мартин Фаулер называет «преждевременной оптимизацией» архитектуры.
Aбстракция, которая не используется, — это не актив, это долг.
Вы платите за нее сложностью кода прямо сейчас, в пользу того, что может быть, никогда и не получите.
И принцип который почему-то большинство игнорирует. YAGNI (You Ain't Gonna Need It - "Вам это не понадобится"). Не пишите код для гипотетического будущего. Решайте сегодняшнюю проблему самым простым и прямым способом. Но простой и прямой способ != напихать костылей. Пример:
Нужен один способ достать пользователя из базы и вы точно знаете, что в ближайшем будущем пока не нужно еще.
Пишите конкретную реализацию. Понадобится второй из другого места — вот тогда и выделите интерфейс. Этот процесс называется «эволюционная архитектура„, и он гораздо эффективнее, чем попытки предсказать будущее.“»
3. Смените фокус на ревью: от «чистоты» к «понятности».
Вообще все программисты задают этот вопрос. Причем всегда. Но эта практика задавать на ревью вопрос «Насколько это чисто?» субъективен и ведет только к спорам. Задать вопросы лучше через призмы:
«Насколько это понятно?» Сможет ли новый джун разобраться в этом коде без посторонней помощи? Если нет, код — го*но, даже если он написан по всем канонам.
«Насколько легко это будет изменить?» Если завтра придет задача поменять в этой логике одно условие, сколько файлов нам придется затронуть? Если больше двух — код, скорее всего, го*но.
"Насколько легко это тестировать?" Могу ли я написать простой юнит-тест на эту логику, не поднимая половину приложения? Если нет, то код - ГО*НО!
Поддерживаемость и простота — объективные метрики качества. А «чистота» — это вкусовщина, которая порождает конфликты. Цель — не написать код, который понравится Роберту Мартину, а написать код, который не захочется сжечь вашему коллеге (или вам же) через полгода.
Я все. Гудлак!
Комментарии (5)

olku
12.11.2025 17:23Как правило, статьи про "чистую архитектуру" заканчиваются списком лучших практик без определения этой самой "чистоты" и методов ее измерения. Оценки "легко" и "понятно" такие же субъективные. Есть научные статьи, которые предлагают разные формулы измерения трудности восприятия кода, но мне известна лишь одна метрика - cognitive complexity от Campbell. Есть ли ещё?

yapaxi
12.11.2025 17:23Поддерживаемость и простота — объективные метрики качества.
Вот нет, к сожалению. Если во главу угла ставить поддерживаемость и простоту, то исчезает например идемпотентность и адекватная обработка ошибок. Простоту использовать во вред также легко как и оверинжениринг.
Я для себя отказался от YAGNI, KISS и SOLID, это всё уже стало частью поп-культуры программирования и мало что значит. Вбрасывать это в разговор - к срачу.
Кстати, и overengineering и oversimplification можно использовать для успокоения нервов особо бесноватых индивидуумов. Иногда выходить за рамки, мне кажется, можно и нужно.

sergey_prokofiev
12.11.2025 17:23Столько букв дял декларации очевидной мысли: "перед тем как начинать что-то делать, договоритесь что и как вы делаете."
В ряде случаев это становится проблемой. И да, иногда нерешаемая. Но об этом в статье не написано ни слова.

karrakoliko
12.11.2025 17:23Могу ли я написать простой юнит-тест на эту логику, не поднимая половину приложения? Если нет, то код - ГО*НО!
Aбстракция, которая не используется, — это не актив, это долг.
ну, удачи вам с легкотестируемым кодом без неиспользуемых абстракций
Zeddushka
Важно, что команда перед построением правил организации кода должна понимать, как будет продукт выглядеть в целом, как будет развиваться. Вопросы, которые остались без ответа, как раз и вносят степень неопределённости. Исходя из всех данных и неизвестных, как правило и выбирается подход к организации кода.
Как пример, надо накидать приложение для проверки доступов с мобильного устройства к определённым ресурсам, чтобы быть готовым к тестовому запуску реального приложения, когда придёт заказчик проверять. Никаких паттернов — god object, несколько минут — и готово.
Или же приложение-комбайн для автоматизации всех внутренних процессов на магазинах, на старте уже гора бизнес-процессов, и потенциально ещё гора, о которой не знает даже зам заказчик. Вот тут начинаем уже хорошо закладываться и корректно организовывать всё.
Само-собой, лучший вариант — адаптация всех подходов под ваши задачи.