Среди множества сложных диаграм Гексагональных, Слоеных и абревиатурных архитектур можно быстро усложнить себе жизнь в полевых испытаниях жизнеспособности их в реальном проекте и масштабировании на новых сотрудников. По этому я разделяю подход к разработке “Ресторанный” и “Фастфудный”.

Ресторанный - изысканое изделие которое могут повторить только крутые повара, а если за них берутся менее квалифицированные специалисты или повара которые не любят такую кухню, то блюдо превращается в винегрет и теряет свой вкус со временем.

Фастфуд - максимально упрощенная система которая понятна на любом уровне экспертизы. Блюдо съедобное и конвеерное. Из-за чего становится скучно его использовать изысканному повору. Но легко может повторить средний специалист.

Я скланяюсь к фастфуду в web разработке. Из моего опыта бизнесу легче находить специалистов, разработка более стабильна и предсказуема для всех участников.

За годы работы, для веб приложений я вывел несоклько основных принципов:

  • Имплементация ничто, интерфейс все - имплементацию легко поменять интерфейс сложно
  • Явное лучше неявного - чем меньше отвлекаешься тем лучше видишь
  • Слабая связанность спасет приложение - чем меньше связь тем легче подменить составляющие
  • Приложение это бургер, а не винегрет - ингредиенты четко разделены между собой и не перемешаны

Для следования этим принципам нам нужна структура приложения в виде бургера, где вся суть в начинке, а булочки можно поменять.

  • Application - место где окружающий мир взаимодействует с приложением
  • Domain - описаны бизнес логики
  • Infrastructure - место где приложение взаимодействую с имплементацией интерфейсов которые нужны для выполнения бизнес логики

Давайте разберем подробней каждый ингредиент

Application - какие рычаги мы предоставляем пользователям Link to heading

Application слой предоставляет достуы к приложенюи через любые протоколы. Задача слоя конвертировать входящую инфрмацию в домен структуры и перевести доменные данные в представление для клиентов на выходе.

  • HTTP api
  • GraphQL
  • cli/cron jobs
  • Подписчики на очереди
  • и так далее

Задача Application слоя конвертировать входящую инфрмацию в домен интерфейс и перевести доменные данные в представление для клиентов

Application не знает ничего про Infrastructure слой

Domain Бизнес логика Link to heading

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

Чем управляет Domain

  • Структуры данных - Entity, ValueObject, Event
  • Интерфейсы сервисов которые нужны для выполнения бизнес логик - SomeRepositoryInterface, SomeServiceInterface
  • Имплементация бизнес логики в которая производит все манипуляции с входящей информацией - UseCase

Domain ничего не знает о Application и о Infrastructure

Infrastructure Взаимодействие нашей программы с другими программами Link to heading

Infrastructure - занимается имплементиацие интерфейсов из Domain логики. Тут у нас находятся наши базы данных, кеши, обращение по http к сторонним приложениям, публикация информации в очередь.

Из-за того что infrastructure имплементирует инерфейс, он становится легко заменяем без изменения Domain логики.

Следуя этим требованиям мы можем кешировать данные и сбрасывать их после определенных событий и никто кроме infrastructure не будет поддерживать эту логику. Использовать любые СУБД и плавно мигрировать между несколькими структурами данных без изменения domain логики.

Infrastructure ничего не знает про Application слой

Что нам надо делать чтоб этот подход работал Link to heading


title: “\u0421\u043a\u0443\u0447\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 web \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f” date: “2022-04-07” image: “/img/boring-architecture/burger.jpeg” Link to heading

Действие: Максимально описывать структуры данных.

  • Понятно что передавать в аргументы и что вернется из метода
    • явное указание типы аргументов и возвращаемый тип, если это невозможно из-за ограничений ЯП, то описывать это в анотациях
    • использовать массивы нигде и никогда

Результат: При обращении к сущности сразу понятно что она умеет и что возвращает без ныряния в методы


title: “\u0421\u043a\u0443\u0447\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 web \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f” date: “2022-04-07” image: “/img/boring-architecture/burger.jpeg” Link to heading

Действие: Не смешивать бизнес действия. UseCase это бизнес действие, бизнес действие не вызывается в другом бизнес действие.

Результат: Масштаб поражения кода ошибкой всегда относится только в том UseCase который менялся, остальные бизнес действия не пострадают.

Хорошей готовки