8 мин

Архитектура единой ИИ-кодовой базы для веба, мобайла и API

Архитектурный разбор, как одна ИИ-сгенерированная кодовая база может обслуживать веб, мобильные приложения и API: слои, контракты, сборка и тесты.

Архитектура единой ИИ-кодовой базы для веба, мобайла и API

Задача: одна кодовая база для веба, мобильных и API

«Одна кодовая база» — это не попытка сделать абсолютно одинаковым всё. Речь о том, чтобы критически важные части продукта жили в одном месте и менялись синхронно: правила бизнеса, модели данных, проверки, расчёты, статусы, ограничения и формат обмена данными.

Что реально должно быть общим

Обычно в общий «ядро‑пакет» выносят:

  • доменную модель (сущности, значения, инварианты);
  • сценарии (юзкейсы) — что система делает и в каком порядке;
  • контракты данных: схемы запросов/ответов, ошибки, перечисления, версии;
  • общие правила валидации и нормализации данных.

Это даёт главный эффект: изменение правила (например, как считать комиссию или когда заказ считается «оплаченным») вносится один раз и одинаково работает в вебе, мобильном приложении и на сервере.

Что обычно расходится по платформам

Почти всегда остаются специфичными:

  • UI: навигация, компоненты, анимации, доступность;
  • доступ к устройству: камера, геолокация, пуши, биометрия;
  • особенности сети и хранения: кэш, офлайн‑режим, фоновые задачи;
  • интеграции и инфраструктура на сервере: база данных, очереди, внешние сервисы.

Это нормально: у платформ разные ограничения и ожидания пользователей. Важно лишь, чтобы эти различия не «протекали» в бизнес‑логику.

Цель: единые правила и единые контракты

Практичная формулировка цели: любой клиент (веб, iOS/Android, партнёрский сервис) разговаривает с системой на одном языке данных и следует одним правилам. Тогда API — не отдельный проект со своей логикой, а один из способов подключиться к ядру.

Критерии успеха

У подхода есть понятные метрики:

  • скорость изменений: правка правила не превращается в три параллельных задачи;
  • консистентность: одинаковые статусы/ошибки/валидации на всех платформах;
  • качество: меньше регресса из‑за рассинхронизации и больше повторного использования тестов.

Базовая схема слоёв: домен, юзкейсы и адаптеры

Единая кодовая база работает, когда у неё есть «скелет», который не зависит от платформы. Самая практичная схема — разделить систему на домен (что мы делаем), приложение/юзкейсы (как мы это делаем) и адаптеры (через что пользователи и внешние системы с нами общаются).

1) Домен: бизнес‑правила без привязки к технологиям

Домен — это сущности, значения, инварианты и правила предметной области: расчёты, статусы, ограничения, проверки. Здесь не должно быть знаний о UI, HTTP, базе данных, SDK мобильной платформы или конкретном фреймворке.

Почему так важно держать домен независимым:

  • его проще переиспользовать между вебом, мобайлом и сервером;
  • тесты становятся быстрыми и точными (без моков транспорта);
  • изменения фреймворков не «ломают» бизнес‑логику.

2) Приложение (юзкейсы): сценарии как единый центр поведения

Юзкейсы описывают шаги: «создать заказ», «оплатить», «подтвердить доставку». Они оркестрируют домен и обращаются к абстрактным портам (интерфейсам) — например, Payments, OrdersRepo, Notifications.

Ключевая идея: юзкейс не знает, откуда пришёл запрос — из веб‑формы, мобильного экрана или API‑метода. Он получает входные данные, применяет правила домена и возвращает результат в нейтральном виде.

3) Адаптеры и инфраструктура: платформенное — отдельно

Адаптеры переводят «язык платформы» в «язык юзкейса»:

  • Web UI и Mobile UI превращают действия пользователя в команды;
  • API‑слой превращает HTTP/JSON в те же команды;
  • инфраструктура реализует порты: база данных, очереди, внешние сервисы.

Граница простая: всё, что связано с транспортом, хранением, форматами, авторизацией на уровне протокола — в адаптерах/инфраструктуре; правила и сценарии — в домене и приложении.

Где здесь помогает ИИ

ИИ удобно использовать для ускорения каркаса: генерации интерфейсов портов, типовых DTO/мапперов, шаблонов юзкейсов и тестовых заготовок. Но решение о границах слоёв и зависимостях — архитектурное: если домен «потянет» за собой фреймворк, единая база быстро превратится в набор сцепленных платформенных модулей.

Если вы строите процесс вокруг «виб‑кодинга», полезно, когда платформа умеет не только генерировать заготовки, но и поддерживать дисциплину слоёв: например, в TakProsto.AI удобно сначала зафиксировать контракты и структуру модулей (planning mode), а затем поручить генерацию повторяемых частей (DTO, адаптеры, тестовые шаблоны) — с возможностью экспортировать исходники и развивать их в привычном репозитории.

Доменная модель как общий источник правды

Если одна кодовая база обслуживает веб, мобильные клиенты и API, то самым надёжным «центром тяжести» становится доменная модель — описание предметной области, которое не зависит от интерфейса и транспорта.

Единая модель предметной области

В домене фиксируются:

  • Сущности (entities) с идентичностью: например, Заказ, Пользователь, Подписка.
  • Value objects без идентичности: Деньги, Адрес, Период.
  • Инварианты — правила, которые должны соблюдаться всегда: «заказ нельзя оплатить дважды», «скидка не может быть отрицательной».

Важно, что эти правила живут в домене, а не в UI и не в контроллерах. Тогда веб‑форма, мобильный экран и серверная ручка будут одинаково «понимать», что допустимо.

Типизация и схемы данных против расхождения DTO

Расхождение DTO обычно начинается, когда каждый клиент «придумывает» свой формат. Практичнее договориться, что домен задаёт канонические типы, а наружу экспортируются контракты (request/response), полученные из них: так проще синхронизировать API и клиентов.

Хороший признак — когда изменения в полях и их смыслах проходят через домен и автоматически отражаются в схемах, а не размазываются по нескольким приложениям.

Идемпотентность и ошибки домена

Домен должен уметь явно сообщать о проблемах: не «500 что-то пошло не так», а типизированные ошибки вроде НедостаточноСредств, НедопустимыйСтатус. Эти ошибки затем переводятся адаптерами в HTTP‑коды, тексты для UI и аналитику.

Для операций оплаты, создания и отправки используйте идемпотентные ключи на уровне юзкейса/домена: повтор запроса не создаёт дублей, а возвращает тот же результат.

DDD, Clean Architecture, Hexagonal — что выбрать

На практике они хорошо сочетаются:

  • DDD помогает правильно описать предметную область.
  • Clean Architecture дисциплинирует границы слоёв и зависимости.
  • Hexagonal (Ports & Adapters) удобно объясняет, почему веб, мобильный клиент и API — это взаимозаменяемые адаптеры вокруг общего ядра.

Выбирайте терминологию, которая понятна команде, но неизменно держите принцип: домен не знает, как выглядит экран и какой у вас транспорт — HTTP, gRPC или локальная база.

Юзкейсы: один набор сценариев для всех клиентов

Юзкейсы (application layer) — это место, где продуктовые сценарии описываются один раз и одинаково работают для веба, мобайла и API. Здесь нет деталей экранов, HTTP‑эндпойнтов или базы данных: только то, что должно произойти и в каком порядке.

Что входит в приложенческий слой

Обычно юзкейсы оформляют как команды (изменяют состояние) и запросы (читают данные). Внутри сценария живут:

  • правила доступа и политики (кто может выполнить действие, при каких условиях);
  • валидации на уровне сценария (например, «нельзя отменить оплаченный заказ»);
  • координация шагов: загрузить агрегат, применить изменение, сохранить, уведомить.

Важно: доменная модель хранит бизнес‑правила «по смыслу», а юзкейсы — «по процессу» (последовательность и интеграции).

Оркестрация: транзакции, ретраи, события

Юзкейс часто отвечает за границы транзакции: начать, выполнить изменения, зафиксировать. Если есть внешние вызовы (платёж, доставка), сценарий решает, где нужны ретраи и как обрабатывать временные ошибки.

Публикация доменных событий тоже удобна на этом уровне: юзкейс фиксирует факт («заказ создан»), а дальше подписчики (почта, аналитика, пуши) реагируют через адаптеры.

Порты/интерфейсы: как абстрагировать инфраструктуру

Чтобы один и тот же сценарий работал везде, юзкейсы зависят от портов (интерфейсов), а не от реализаций: репозитории, часы (time provider), шифрование, сеть/HTTP‑клиент, генератор идентификаторов. Тогда веб, мобильный и серверный адаптеры подставляют свои реализации, не меняя ядро.

Тонкость: не тащить UI‑логику в юзкейсы

Юзкейс не должен знать про экраны, навигацию, состояния кнопок, тексты ошибок «как показать». Он возвращает понятный результат (успех/ошибка с кодом и данными), а UI‑адаптер решает, как это отрисовать. Это сохраняет переиспользуемость сценариев и не превращает общий слой в сборник компромиссов под разные клиенты.

Контракты API: единые схемы для сервера и клиентов

Когда веб, мобильные приложения и сервер развиваются параллельно, главный источник рассинхронизации — «устные договорённости» о формате запросов и ответов. Поэтому контракт API стоит воспринимать как продукт: он описывает, что именно гарантирует система, и одинаково важен для бэкенда и всех клиентов.

Контракт как продукт: чем описывать

  • OpenAPI уместен для классических HTTP/REST API: удобен для документации, моков, генерации SDK и проверки совместимости.
  • JSON Schema хорошо подходит для описания отдельных объектов/событий (например, payload в очереди или структуру настроек), когда не нужно описывать весь HTTP‑интерфейс.
  • Protobuf логичен для высоконагруженных RPC/стриминговых сценариев и строгой типизации, но требует дисциплины в эволюции схем.

Важно: контракт должен быть один, а реализаций вокруг — много. Сервер генерирует валидаторы и типы, клиенты — типобезопасные модели и методы.

Версионирование без боли

Держите курс на совместимость назад: добавляйте поля как optional, не меняйте смысл существующих, избегайте «ломающих» переименований. Для изменений, которые всё же ломают совместимость, вводите депрекейты: помечайте устаревшее, давайте срок, добавляйте миграционные подсказки. Версионировать можно как endpoint‑ами (/v1/…), так и через эволюцию схем — главное, чтобы правила были одинаковыми для всех команд.

Генерация клиентов из одного контракта

Единый контракт позволяет выпускать SDK для веба и мобайла автоматически: типы, сериализацию, обработку ошибок, ретраи. Это снижает ручной код, а ИИ можно использовать точечно — например, чтобы дописать удобные «обёртки» над сгенерированным API, не трогая сам контракт.

Тесты контракта

Контрактные тесты проверяют, что сервер и клиенты говорят «на одном языке»: сервер действительно возвращает то, что обещано схемой, а клиенты не отправляют лишнего. Хорошая практика — прогонять в CI валидацию схем, тесты совместимости и генерацию SDK как обязательный шаг перед релизом.

Адаптеры: веб‑UI и мобильные клиенты поверх общего ядра

Добавьте мобильное приложение
Создайте мобильный клиент на Flutter поверх общих юзкейсов и контрактов

Адаптеры — это «переводчики» между пользовательским интерфейсом и общими юзкейсами. Они знают про конкретный фреймворк, навигацию, состояние экрана, сетевые особенности — но не содержат бизнес‑правил. Благодаря этому веб и мобильные клиенты могут выглядеть и ощущаться по‑разному, оставаясь логически едиными.

Веб: слой представления как адаптер к юзкейсам

Для веба удобно мыслить UI как адаптер в стиле MVC или SPA: контроллер/экшен (или handler) собирает входные данные, вызывает юзкейс и превращает результат в состояние страницы.

Ключевой принцип: веб‑слой не «лезет» в домен напрямую. Он оперирует DTO/моделями представления и маппингом:

  • валидация формы и форматирование — в UI;
  • правила «можно/нельзя», расчёты, статусы — в ядре (домен + юзкейсы);
  • ошибки юзкейсов превращаются в понятные сообщения и UX‑сценарии.

Мобильные: офлайн, фон, разрешения и пуши

Мобильный адаптер почти всегда сложнее из‑за окружения:

  • офлайн‑режим: локальный кэш, очередь действий и последующая синхронизация;
  • фоновые задачи: догрузка, трекинг статусов, периодические обновления;
  • разрешения ОС (камера, гео, уведомления) как отдельные зависимости, которые внедряются в адаптер;
  • push‑уведомления: обработчик пуша переводит событие в команду/вызов юзкейса, а не меняет доменные сущности напрямую.

Важно: офлайн‑механика — это инфраструктура клиента, но «что считать конфликтом» и «как решать» должно оставаться в юзкейсах, иначе логика расползётся.

Общий UI: где переиспользовать, а где разделять

Реально переиспользуются дизайн‑токены, иконки, тексты, схемы состояния (empty/loading/error), иногда — простые компоненты. Но компоновку экранов, навигационные паттерны и интерактивность лучше делать отдельно: веб и мобильные платформы ожидают разный UX.

Навигация и состояние без привязки домена к фреймворку

Домен и юзкейсы должны возвращать нейтральные результаты (например, «успех/ошибка + данные»), а решение «куда перейти» и «как показать» остаётся в адаптере. Для состояния используйте view‑model/Presenter слой: он хранит UI‑состояние и подписывается на результаты юзкейсов, не затягивая в ядро детали роутера, реактивности или жизненного цикла экранов.

Серверные интерфейсы: API как ещё один адаптер

Если домен и юзкейсы — «ядро», то HTTP/GraphQL/gRPC — всего лишь способы доставить запрос до этих сценариев и вернуть ответ. В чистой архитектуре серверный API — такой же адаптер, как веб‑UI или мобильный клиент: он не содержит бизнес‑правил и не диктует их форму.

REST, GraphQL или gRPC: выбираем транспорт, не ломая домен

Критерий выбора — не «мода», а тип взаимодействий и окружение:

  • REST удобен для публичных интеграций и простого кэширования, хорошо ложится на ресурсную модель.
  • GraphQL полезен, когда клиенты часто меняют состав данных и важно уменьшать over/under‑fetching.
  • gRPC выигрывает во внутренних сервисах: строгие контракты, бинарный протокол, стриминг.

При этом домен не должен «знать» про URL, резолверы и protobuf. Меняется транспорт — юзкейсы остаются теми же.

Серверная композиция: тонкий слой контроллеров/резолверов

Контроллер (или резолвер) делает три вещи: валидирует вход, маппит DTO ↔︎ доменные типы и вызывает юзкейс. Всё остальное — в ядре. Это позволяет держать API предсказуемым и не размазывать правила по роутам.

Аутентификация и авторизация: где живут правила

Аутентификация (токены, сессии, OAuth) — инфраструктура адаптера. Авторизация (кто что может) — часть доменных правил: политика доступа должна быть тестируема на уровне юзкейсов (например, «владелец может редактировать, наблюдатель — нет») без запуска сервера.

Ошибки и трассировка: единый стандарт для всех потребителей

Заранее зафиксируйте формат ошибок: стабильный code, человекочитаемый message, поле details для валидации, и trace_id для поиска в логах. Один стандарт облегчает поддержку всех клиентов и снижает «зоопарк» обработчиков на вебе, мобайле и в интеграциях.

Инфраструктура: базы, интеграции, очереди без смешивания слоёв

Быстро выведите в тест
Запускайте приложение с деплоем и хостингом, не меняя архитектурные границы

Единая кодовая база начинает «расползаться», когда доменная логика тянет за собой конкретную БД, SDK платёжки или клиент очереди. Чтобы этого не произошло, инфраструктуру важно держать на периферии: ядро описывает что нужно системе, а внешний слой решает как именно это сделать в конкретной среде.

Репозитории и хранилища: SQL/NoSQL/кеш — через интерфейсы

В домене и юзкейсах говорим языком бизнеса: «получить заказ», «сохранить пользователя», «проверить лимит». Для этого вводятся порты (интерфейсы) репозиториев и хранилищ.

Например, юзкейс зависит от UserRepository и SessionStore, но не знает, это PostgreSQL, MongoDB или Redis. Реализации живут в инфраструктурном модуле и могут отличаться для разных деплойментов, при этом сценарии и тесты остаются неизменными.

Интеграции: платежи, почта, аналитика — изоляция через порты

Любая внешняя система — это риск: меняются API, тарифы, поля, появляются ограничения. Поэтому интеграции лучше оформлять как «адаптеры» к порту, например PaymentsGateway, EmailSender, AnalyticsTracker.

Так вы избегаете ситуации, когда UI или юзкейс начинает разбираться в специфике провайдера. В результате проще заменять поставщика, делать фейковые реализации для тестов и безопасно подключать окружения (песочница/прод).

Очереди и события: когда уместно, а когда нет

Событийная модель полезна для действий «после факта»: отправить письмо, пересчитать статистику, запустить антифрод — то, что не должно блокировать ответ пользователю.

Но не стоит превращать очередь в «чёрный ящик» бизнес‑транзакций: если операция требует строгой согласованности (например, списание и подтверждение), синхронный юзкейс с явной обработкой ошибок обычно понятнее и надёжнее.

Конфигурация и секреты: принцип минимальных зависимостей

Конфигурацию (URL БД, ключи API, фиче‑флаги) подаём снаружи через контейнер/провайдер зависимостей. Ядро не должно читать переменные окружения напрямую и тем более хранить секреты в коде.

Минимум зависимостей в центре — максимум свободы на краях: один и тот же домен и юзкейсы спокойно обслуживают веб, мобильные клиенты и API, даже если инфраструктура в каждом окружении отличается.

Организация репозитория и сборки

Правильная структура репозитория решает две задачи: делает «общее ядро» действительно общим и не даёт платформенным деталям протечь в домен и юзкейсы. Если это не закрепить на уровне сборки и зависимостей, единая кодовая база быстро превращается в набор взаимных костылей.

Монорепозиторий или несколько репозиториев

Монорепо удобно, когда веб, мобильное приложение и сервер развиваются синхронно: единые правки контракта и юзкейсов проходят одним PR, проще настроить сквозные проверки и единый стиль. Минусы — тяжелее CI, сложнее права доступа и больше риск «случайно» потянуть лишнюю зависимость.

Мульти‑репо лучше, когда команды и релизные циклы разные, либо часть кода должна быть изолирована юридически. Компромиссный вариант: монорепо для продуктов и отдельных пакетов + публикация «ядра» как версионируемых библиотек.

Рекомендуемая структура каталогов

Практичная схема (названия условные, смысл важнее):

  • core/ — домен, юзкейсы, контракты (без UI и без инфраструктуры)
  • adapters/ — реализации портов: HTTP, БД, очереди, файловые хранилища
  • apps/ — веб, мобильные клиенты, сервер (композиция зависимостей)
  • packages/ — переиспользуемые библиотеки (например, валидация, логирование)
  • tools/ — генераторы, скрипты, линтеры, шаблоны

Сборка, публикация и версионирование

Даже в монорепо полезно относиться к core как к продукту: отдельная сборка, отдельные артефакты, понятное версионирование (часто достаточно семантического).

Подход: изменения в core публикуются как пакет(ы), а apps/* зависят от конкретной версии. Так проще откатываться и поддерживать несколько веток приложений. Для внутренних пакетов обычно достаточно приватного реестра.

Как держать платформенные зависимости за границами ядра

Ключевое правило: core не импортирует ничего из веба/мобайла/сервера. Любые платформенные вещи оформляются как порты (интерфейсы) в core, а их реализации лежат в adapters.

Технические меры:

  • запрет импортов на уровне линтера/правил зависимостей (например, «apps не могут быть зависимостями core»)
  • отдельные зависимости и lock‑файлы/воркспейсы для пакетов, чтобы core не видел лишних библиотек
  • сборочные таргеты: core собирается в «чистом» окружении без платформенных SDK

Эта дисциплина делает сборку предсказуемой, а единое ядро — действительно переносимым между вебом, мобильными клиентами и сервером.

Тестирование и наблюдаемость для единого качества

Единая кодовая база даёт сильное преимущество: вы можете проверять ключевую бизнес‑логику один раз — и быть уверенными, что одинаковые правила работают в вебе, мобайле и на сервере. Но для этого тесты и наблюдаемость должны быть частью архитектуры, а не «добавкой» в конце.

Стратегия тестов: от ядра к краям

Начинайте с самого стабильного слоя — домена и юзкейсов. Это дешевле всего поддерживать и быстрее всего гонять.

  • Юнит‑тесты домена: проверяют сущности, правила, валидации, расчёты. Здесь не должно быть сети, БД и UI — только чистая логика.
  • Тесты юзкейсов: проверяют сценарии «как пользователь получает результат», но через подменяемые порты (репозитории, отправка событий, уведомления). Это помогает ловить регрессии до того, как изменится любой клиент.
  • Контрактные тесты: фиксируют соглашения API/событий (поля, статусы, ошибки). Клиенты и сервер должны падать на тестах, если контракт нарушен, — так несостыковки не доезжают до продакшена.
  • Интеграционные тесты: минимальный набор проверок реальной БД, очереди и внешних интеграций. Их меньше, они медленнее, но подтверждают, что «провода подключены» правильно.

Фикстуры и тестовые данные: единый подход

Сделайте библиотеку тестовых данных общей: один генератор пользователей, заказов, прав доступа, типовых ошибок. Тогда веб, мобильные тесты и серверные проверки говорят «на одном языке» и не расходятся в трактовках.

Практика, которая окупается: хранить фикстуры в одном месте и давать доступ из всех пакетов, а также иметь несколько «срезов» данных — минимальный, типовой и стресс‑набор.

Наблюдаемость: видеть систему целиком

Чтобы понимать, что происходит в разных адаптерах, вводите единые правила:

  • Логи с корреляционным идентификатором запроса/сессии.
  • Метрики (ошибки, латентность, конверсии ключевых действий) на уровне юзкейсов, а не только HTTP.
  • Трассировка цепочек: клиент → API → очередь/интеграция, чтобы быстро находить узкие места.

Важно договориться о формате ошибок и событий, чтобы диагностика была одинаково понятна всем командам.

CI: быстрые проверки без тормозов

Разделите пайплайны:

  • Быстрые проверки для общего ядра (линтер, юниты, тесты юзкейсов, контракты) — запускаются на каждый PR.
  • Отдельные пайплайны для веба/мобайла/сервера (сборки, e2e, интеграции) — можно запускать параллельно и/или по изменившимся пакетам.

Так единая кодовая база остаётся предсказуемой: критичная логика защищена постоянно, а тяжёлые проверки не превращают разработку в ожидание.

Роль ИИ: ускорение разработки без потери управляемости

Начните с контрактов и слоёв
Зафиксируйте контракты и структуру модулей в planning mode перед генерацией кода

ИИ действительно помогает строить единую кодовую базу быстрее — но только если он работает «в рамках правил» архитектуры, а не подменяет их. Лучший результат получается, когда вы просите ИИ генерировать повторяемые заготовки, а решения по границам слоёв и контрактам принимаете осознанно и фиксируете в репозитории.

Где ИИ полезен в единой базе

ИИ особенно эффективен там, где много механической работы и мало архитектурной неопределённости:

  • каркасы модулей и шаблоны слоёв (домен → юзкейсы → адаптеры);
  • DTO/схемы контрактов, маппинги между доменными моделями и транспортными моделями;
  • генерация тест‑кейсов (включая граничные условия) по описанию юзкейса;
  • черновики документации: описания сценариев, ошибок, примеров запросов/ответов.

Важно: пусть ИИ генерирует «провода» (glue code), но не «истину» домена. Доменную модель и правила лучше держать максимально ручными и обсуждаемыми.

В этом смысле полезны платформы, которые ориентированы именно на производство приложений, а не на разовые ответы в чате. Например, TakProsto.AI позволяет собирать веб‑приложения (React), сервер (Go + PostgreSQL) и мобильные клиенты (Flutter) через диалог, при этом поддерживает экспорт исходников, деплой/хостинг, снапшоты и откат — что удобно для итераций без потери контроля.

Контроль качества: как не потерять управляемость

Чтобы ИИ не превратил монорепозиторий в набор случайных решений, нужны автоматические и процессные ограничители:

  • обязательные линтеры/форматтеры и статанализ на CI;
  • архитектурные правила (например, запрет импорта из адаптеров в домен) и их проверка;
  • ревью по чек‑листу: «не добавлено ли обходных путей мимо юзкейсов», «не потекли ли детали БД в домен».

Типичные риски

Чаще всего проблемы выглядят так:

  • скрытые зависимости (UI тянет инфраструктуру, юзкейс — HTTP‑клиент);
  • дублирование сущностей и схем (почти одинаковые DTO в разных пакетах);
  • «неправильные абстракции» ради переиспользования, которые усложняют всем.

Практика: мини‑чек‑лист промптов и критерии приёмки

Промпт: укажите слой, вход/выход, ограничения и примеры.

  • «Сгенерируй DTO и маппинг только для адаптера X. Домен не трогать.»
  • «Добавь тесты для юзкейса Y: позитивные, негативные, граничные случаи. Без моков инфраструктуры внутри домена.»

Приёмка изменений:

  • сборка и тесты зелёные;
  • нет новых зависимостей, нарушающих правила слоёв;
  • контракты API/схемы не разъехались с клиентами;
  • изменения минимальны: без “улучшений” вне запроса.

Границы подхода: когда единая база мешает и что делать

Единая кодовая база даёт скорость и согласованность, но со временем может начать тормозить развитие продукта. Важно заранее видеть сигналы и иметь план «мягкого расхождения», чтобы не превратить монолит в узкое горлышко.

Признаки, что пора разделять

На практике тревожные симптомы довольно приземлённые:

  • Разные циклы релизов: мобильные клиенты завязаны на ревью магазинов и хотят редких стабильных релизов, а веб и API — частых выкладок.
  • Разные команды и приоритеты: общие изменения превращаются в бесконечные согласования, и «быстро поправить» занимает дни.
  • Разные SLA и требования к стабильности: API для партнёров требует жёсткой обратной совместимости, а UI может меняться смелее.

Если вы всё чаще откладываете улучшения ядра «чтобы никого не сломать», единая база начинает стоить дороже, чем приносит.

Антипаттерны, которые ускоряют деградацию

Есть несколько типичных ошибок:

  • «Общий UI любой ценой»: попытка вынести в ядро слишком много UI‑логики приводит к компромиссам и ухудшает опыт на каждой платформе.
  • Домен зависит от сети/БД: когда доменная модель знает про HTTP, JSON, SQL или SDK конкретной базы — вы теряете переносимость и тестируемость.
  • «Бог‑слой»: слой “common” без правил, куда складывают всё подряд. Он быстро превращается в свалку зависимостей.

Стратегия эволюции: разделять без шока

Вместо резкого «переписываем на микросервисы» лучше идти по шагам:

  1. Выделяйте библиотеки по ответственности: домен и юзкейсы — отдельно, контракты API — отдельно, инфраструктура — отдельно.
  2. Вводите чёткие границы модулей и запреты зависимостей (линтеры/правила сборки), чтобы ядро не «протекало».
  3. Выносите сервисы по факту нагрузки: когда конкретная часть домена требует своего SLA/масштабирования, отделяйте её в самостоятельный сервис с теми же контрактами.

Чтобы углубиться, посмотрите другие материалы в /blog. Если выбираете формат внедрения и поддержку процесса разработки, может быть полезна страница /pricing.

Похожие статьи