Оглавление
Время чтения: 8 минут
На одном из прошлых проектов наша команда решила реализовать монолитное приложение, построенное на принципах чистой архитектуры. Это был нетривиальный и местами противоречивый опыт: мы добились большей точности в оценках, сократили время вывода фич на рынок — и при этом неожиданно осложнили работу системным аналитикам.
В этой статье мы поделимся практическими наблюдениями: как мы подошли к архитектурным решениям, какие паттерны применяли, какие плюсы и минусы обнаружили, и что в итоге получилось. В качестве технологического стека — Django, PostgreSQL, Redis, ELK и Grafana.
Почему вообще возникла идея перейти на чистую архитектуру
Наш проект представлял собой монолит на Django с вкраплениями микросервисов. К тому моменту система уже работала в продакшене порядка семи лет, и нам регулярно приходилось сталкиваться с легаси. Типичные симптомы — раздутые модели, повторяющаяся логика, хаотичное распределение бизнес-функционала по слоям и неясная картина с покрытием тестами.
Отдельная боль — слой представления. Он был перегружен, бизнес-логика часто дублировалась, а предсказуемость поведения системы страдала. После нескольких неудачных попыток выровнять консистентность базы, стало понятно: нужно менять архитектурный подход.
Кроме технических причин были и организационные:
- Оценка задач строилась на мнении одного тимлида. Это часто приводило к расхождению между ожиданиями и реальностью, так как в расчет не брались риски, проектирование и ревью.
- Мы хотели, чтобы код лучше отображал бизнес-логику, а не был просто набором технических решений.
- Монолит сильно связан: любое изменение в одной части системы влияло на другие. Нужна была архитектура, которая снизит связанность компонентов.
Так мы пришли к идее применить принципы чистой архитектуры даже в условиях монолитной системы.
Что такое чистая архитектура — простыми словами
- Независимость от фреймворков. Код не должен диктоваться рамками Django или другого инструмента. В чистой архитектуре фреймворк — просто способ доставки, а не основа архитектурного мышления.
- Высокая тестируемость. Бизнес-правила должны быть протестированы без привязки к UI, БД или API. Это упрощает поддержку и тестирование.
- Изоляция от источников данных. Можно легко перейти, скажем, с PostgreSQL на MongoDB, не переписывая бизнес-логику.
- Независимость от внешних сервисов. Слой use-case не должен «знать» о внешнем мире — он работает в рамках бизнес-контекста.
Бизнес-правила как драйвер архитектурных решений
Ключевое понятие — бизнес-правила. Это не просто требования к системе, а скорее описания того, что система должна соблюдать: нормативы, регламенты, политики и т. д. Они понятны бизнесу, в отличие от технических требований, и позволяют быстрее выявлять ошибки в постановке задач.
Реализация чистой архитектуры позволила нам строить код вокруг таких правил. Благодаря этому снизилось количество ненужных итераций, а ошибки фиксировались раньше — ещё на стадии анализа требований.
Богатая vs бедная модель предметной области
Мы выбрали анемичную (бедную) модель. Несмотря на то что она нарушает классический ООП-принцип инкапсуляции, она отлично справляется с изоляцией бизнес-логики. Это позволяло:
- хранить поведение отдельно от данных;
- снижать связанность классов;
- упрощать сериализацию и передачу между слоями.
Сущности у нас представляли собой классы-контейнеры. Сложную бизнес-логику мы выносили в отдельные сервисы. Для примеров использовали наследование и миксины — например, сущность "Клиент" могла быть основой для сущности "Пользователь клиента".
Ключевые паттерны
Unit of Work
Базовый механизм для работы с состоянием сущностей. Он позволял нам:
- следить за консистентностью данных;
- управлять транзакциями;
- реализовать независимый от БД сервисный слой;
- удобно проводить тестирование.
Благодаря этому мы могли безопасно использовать как реляционные, так и KV-хранилища, не привязываясь к конкретной реализации.
Data Mapper
Низкоуровневый интерфейс для работы с хранилищами. Он отвечал за трансформацию сущностей и реализацию CRUD-операций. Mapper позволял:
- держать предметную область изолированной;
- адаптировать сущности под разные источники данных;
- гибко управлять сериализацией.
Репозиторий
Этот паттерн позволял отвязать слой бизнес-логики от фреймворка. Репозиторий выглядел как коллекция доменных объектов с возможностью фильтрации. Мы старались не делать логику сложной — валидация и фильтрация выносились в спецификации.
Спецификация
Позволила формализовать условия фильтрации и валидации отдельно от логики и хранилища. Мы описывали правила в явном виде — это устраняло неясности. Если возникал вопрос "почему так, а не иначе", — ответ был в спецификации.
Связка Use-case, Unit of Work и сервисов
Use-case описывал конкретный пользовательский сценарий. Он управлял:
- вызовами сервисов;
- работой с репозиториями;
- состоянием через Unit of Work.
Это сделало код модульным, переиспользуемым и проще в сопровождении. Однако у этой модульности был побочный эффект: аналитикам пришлось втянуться в бизнес глубже. Разработчики стали задавать более конкретные вопросы и ожидали точных ответов.
На практике это привело к росту нагрузки на аналитиков. Если раньше на девять человек хватало полутора аналитиков, то теперь нужен был один на троих.
Эффект на команду и процессы
Внедрение чистой архитектуры снизило энтропию в коде. Мы начали:
- обсуждать архитектуру на старте задач;
- вести реестр архитектурных решений;
- проектировать систему, отталкиваясь от бизнес-сценариев.
Толщина сервисного слоя начала уменьшаться, код стал переиспользуемым, а use-case начали мигрировать в разные части системы. Количество багов снизилось, разработчики стали лучше понимать проект, а процессы — прозрачнее.
Неожиданный бонус — наблюдаемость
Благодаря структуре use-case и Unit of Work мы получили видимость действий пользователей в системе. Появились метрики, графики и возможность отслеживать, где и когда возникали сбои. В связке с инструментами мониторинга это дало мощную платформу для анализа поведения пользователей и расследования инцидентов.
Что в итоге
После внедрения чистой архитектуры каждый разработчик получил четкий алгоритм работы над задачей. Появился чек-лист: какие шаги сделать, какие артефакты получить, где фиксировать архитектурные решения.
Это:
- упростило ревью;
- улучшило оценки;
- ускорило доставку фич;
- обеспечило коллективное владение кодом.
Кому подойдет чистая архитектура
Такой подход имеет смысл только при наличии опытной и зрелой команды. Он требует вовлеченности, самостоятельности и навыков проектирования. Все участники должны быть готовы обсуждать бизнес, архитектуру, взаимодействие и совместно принимать решения.
Важно: внедрение чистой архитектуры — это не просто «смена подхода к коду», это пересмотр всей командной культуры. Мы провели сессии по ролям, зонам ответственности, проработали процессы — только после этого изменения действительно заработали.
Итоговое наблюдение
Хорошо реализованная чистая архитектура — это не просто способ организации кода. Это инструмент, который помогает связать бизнес и разработку, ускорить выход фич, и — да, иногда напрячь аналитиков. Но в конечном итоге — сделать проект лучше.