Подтвердить что ты не робот

Поддержание чистой архитектуры в Spring MVC с помощью подхода, ориентированного на данные

Поддержание чистой архитектуры в Spring MVC с ориентированным на данные подходом

Я пытаюсь отобразить архитектуру для внешнего интерфейса нового веб-приложения на основе Java (приложение типа портала), которое мы делаем на работе. Я хочу получить это право с первого дня, и я хотел бы начать обсуждение здесь, чтобы помочь мне реализовать дядю Боба "Чистая архитектура" в моей архитектурной дизайн.

Здесь быстрый прорыв нашего технического стека, сверху вниз (технология не важна, структура):

  • База данных Oracle
  • Oracle Service Bus, предоставляющая услуги с использованием WSDL
  • JAX-WS генерирует Java-классы из WSDL (позвольте назвать этот "сгенерированный сервисный уровень" )
  • Модуль домена, состоящий из POJO, сопоставленных с созданными объектами данных
  • Потребительский модуль, отображающий "сгенерированный сервисный уровень" для внешнего приложения.
  • A Spring Основанный на MVC модуль с использованием FreeMarker для визуализации представлений

Ключевой момент:

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

Попытка присоединиться к архитектуре Bob Clean Architecture, я немного поучался себе в том, где разместить логику приложения, а именно слой "Use Case" в его архитектуре.

Вот такой подход, который я придумал:

Уровень 1 - Объекты

Объекты заключают в себе корпоративные бизнес-правила.

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

Доступ к нашей базе данных осуществляется через WSDL с использованием служебной шины, которая преобразует данные, в отличие от ORM, например JPA или Hibernate. Из-за этого у нас нет "сущностей" в традиционном смысле (с идентификаторами), но подход, ориентированный на данные, делает этот слой уровнем доступа к данным, представленным остальной частью приложения модулем Consumer.

Уровень 2 - Использовать случаи

Программное обеспечение на этом уровне содержит бизнес-правила, специфичные для приложения.

Здесь логика, специфичная для нашего приложения, использует случаи жизни. Изменения этого слоя не должны влиять на уровень доступа к данным (уровень 1). Изменения в реализации GUI или каркаса (Spring MVC) не должны влиять на этот уровень.

Здесь он становится немного сложным: Поскольку наш уровень доступа к данным (в слое 1) должен быть очищен от логики приложения, нам нужен слой, который облегчает использование этого слоя таким образом, который подходит для использования. Одним из решений, которое я нашел для этой проблемы, является использование варианта "MVVM-шаблона", который я выбираю для вызова MVC-VM. См. Ниже объяснение. "VM" -части этого живет в этом "Использовании Case-слоя", представленном *ViewModel -классами, которые инкапсулируют эту логику с использованием конкретного случая.

Уровень 3 - Адаптеры интерфейса

Программное обеспечение на этом уровне представляет собой набор адаптеров, которые преобразуют данные из формата, наиболее удобного для использования и сущностей, в формат, наиболее удобный для некоторых внешних агентств, таких как База данных или Интернет.

Здесь находится MVC-архитектура нашего GUI ( "MVC" в нашей "MVC-VM" ). По существу это когда классы Controller получают данные из классов *ViewModel и помещают его в теги Spring MVC ModelMap, которые напрямую используются шаблонами FreeMarker в представлении.

То, как я это вижу, servicebus в нашем случае также попадет под этот слой.

Уровень 4 - Рамки и драйверы

Как правило, вы не пишете много кода в этом слое, кроме кода клея, который связывается со следующим кругом внутрь.

Этот уровень - это всего лишь слой конфигурации в нашем приложении, а именно конфигурация Spring. Это будет, например, указать, где мы указываем, что FreeMarker используется для визуализации представления.


Модель ViewModel Pattern

MVVM облегчает четкое разделение разработки графического пользовательского интерфейса (либо как язык разметки, либо код GUI) от разработки бизнес-логики или логики конца, известной как модель (также известная как модель данных, чтобы отличить ее из модели просмотра). Модель представления MVVM представляет собой преобразователь значений, означающий, что модель представления отвечает за отображение объектов данных из модели таким образом, что эти объекты легко управляются и потребляются.

Подробнее о MVVM-шаблоне в Wikipedia.

Роли MVC-VM выполняются в нашем приложении так:

  • Модель - представлена ​​просто datastructure ModelMap в Spring MVC, которая используется шаблонами представлений.
  • Просмотр - шаблоны FreeMarker
  • Контроллер Spring Controller -классы, которые направляют запросы URL-адресов HTTP определенным обработчикам (и как такие функции, как FrontController). Обработчики в этих классах отвечают за выборку данных из прецедента и вывод его в шаблоны представлений при показе данных (HTTP GET), а также передачу данных для хранения (HTTP POST). Таким образом, он по существу функционирует как связующее средство между ViewModel и View, используя Model.

  • ViewModel. Эти классы отвечают за: 1) структурирование данных с уровня доступа к данным способом, который можно использовать View и 2) обрабатывать данные ввода из представления. "Обработка" означает проверку и разбиение данных, чтобы их можно было отправить в стек для хранения. Этот слой будет выглядеть как <UseCase>VM -классы в пакете viewmodel в нашем интерфейсе Spring MVC.

Ключевым компонентом здесь является неявное связывание, которое происходит в Spring MVC между ModelMap и шаблонами FreeMarker. Шаблоны используют только модель (ModelMap s), где контроллер помещает данные в формат, который он может использовать. Таким образом мы можем сделать шаблоны так:

<body>
  <h1>Welcome ${user}!</h1>
  <p>Our latest product:
  <a href="${latestProduct.url}">${latestProduct.name}</a>!
</body>

Я извиняюсь за подробное объяснение, но я не мог объяснить эту (относительно простую) архитектуру в меньшем количестве слов.

Я был бы очень признателен за внесенный вклад в мой подход здесь - я на правильном пути? Имеет ли смысл MVC-VM смысл? Я нарушаю принципы чистой архитектуры?

Конечно, есть много решений для этого, но я пытаюсь найти решение, которое является 1) не чрезмерно спроектированным и 2) придерживается принципов архитектуры Bob Clean.


Обновление:

Я думаю, что ключевая проблема, которая меня отталкивает, заключается в том, какую форму использует слой "Use case" в этом приложении. Помните, что у нас есть интерфейс MVC, который получает данные с уровня доступа к данным. Если часть MVC соответствует Бобу "Интерфейсные адаптеры", а модели домена слоя данных соответствуют слою "Entities" Боба, то что я называю классами использования, которые реализуют логику приложения? У меня возникает соблазн просто называть их <UseCase>Model и помещать их в проект MVC, но согласно Bob

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

так что мои объекты модели должны быть "тупыми" (как простой Map. ModelMap в Spring), а затем контроллер должен помещать данные из класса Use Case в эту карту -состав.

Итак, в какой форме используются мои классы использования Case? Как насчет <UseCase>Interactor?

Но в заключение я понимаю, что MVC-MV-вещь является чрезмерной (или просто неверной) - поскольку "mikalai" указывает ниже, это, по существу, просто двухслойное приложение в его текущей форме; уровень доступа к данным и внешний уровень MVC. Просто как это.

4b9b3361

Ответ 1

Мое решение

Итак, оказывается, что реализация Bob "Чистая архитектура" в Java/Spring MVC является пограничной нетривиальной и требует более архитектурных аспектов, чем я первоначально включил. И я действительно не мог найти какой-либо пример реализаций в Интернете.

Очевидно, в моей архитектуре отсутствовал отдельный модуль для слоя "Use Case", так как эта логика не должна жить в веб-модуле Spring MVC (и не называться "*ViewModel" ). Модуль Web/MVC - это просто деталь приложения, и логика приложения должна быть полностью отделена от него и отдельно тестироваться.

Этот новый "Use Case" -модуль теперь содержит *Interactor -классы, которые получают данные из модуля домена (сущности). Кроме того, "Объекты запроса/ответа" необходимы для облегчения связи между MVC/Web-модулем и модулем Use Case.

Теперь моя цепочка зависимостей выглядит так:

Spring Модуль MVC → Модуль использования → Модуль домена

где каждая стрелка (зависимость) принимает форму как границу, то есть интерфейс определен в модуле справа от стрелки, которая реализуется там, где это необходимо, и вводится там, где это необходимо (инверсия управления).

Вот интерфейсы, в которые я закончил (за использование):

I<UseCase>Request - реализован в модуле MVC, созданный в контроллере I<UseCase>Response - реализован в модуле Use Case, созданный в Interactor I<UseCase>Interactor - реализован в модуле UseCase, введенном в контроллер I<UseCase>Consumer - реализован в модуле Domain, введенный в Interactor

Как это работает?
Controller принимает параметры из HTTP-запроса и упаковывает его в RequestModel, который он передает до Interactor. Interactor извлекает необходимые данные из модуля домена *Consumer и накладывает на него свою прикладную логику, затем помещает его в ResponseModel и отправляет обратно обратно в Controller. Controller затем, наконец, просто помещает простые (теперь GUI-дружественные) простые данные в объект Map и перенаправляет его в шаблон FreeMarker, который затем напрямую использует эти данные и отображает HTML.

A Presenter может участвовать в этой последней части, делая это реализацией шаблона Model-View-Presenter, но сейчас я ухожу.

Мое заключение

В итоге у меня появилось больше файлов, чем это необходимо в начале разработки, строго говоря. Однако по мере роста сложности и размера приложения я уверен, что эта структура позволяет нам поддерживать низкую связь и высокую степень сцепления. Кроме того, теперь Web-модуль легко заменяется - он просто доставляет запросы к модулю использования и получает объекты ответа. Кроме того, каждый уровень приложения (логика домена, логика приложения и логика GUI) отдельно тестируется, и только для части просмотра требуется веб-сервер для тестирования.

Спасибо за все советы и указатели, которые я получил здесь. И прокомментируйте мое решение - я не утверждаю, что он совершенен.

Ответ 2

Это было много. И я думаю, что вы в основном перевели дядю Боба жаргон в ваше приложение Spring Java.

Так как архитектура - это в основном мнение, и поскольку ваш вопрос - это своего рода запрос...

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

Что важно MOST (IMHO) - это зависимости. Создание множества небольших проектов в отличие от одного гигантского монолитного проекта - лучший способ получить "чистую" архитектуру.

Ваша самая важная технология для чистой архитектуры не будет "технологией Spring MVC" или языком шаблонов "Freemarker", или другой статьей доктора Добба с диаграммами ящиков, шестиугольников и других абстрактных полигонов.

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

Также, если ваш код трудно проверить.. у вас, вероятно, есть плохая архитектура.

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

Если вы это сделаете, будет легко изменить код без беспокойства... так вы могли бы даже изменить свою архитектуру:)

Остерегайтесь слишком много фокусироваться на правилах быка #% [email protected]#. Серьезно: если ваш код легко тестировать, легко изменить, легко понять и выполнить колодцы, тогда у вас будет хорошая архитектура. Для этого нет 6 недель до 6 штук абс статьи (извините, дядя Боб). Это требует опыта и времени... нет плана волшебной пули.

Итак, моя собственная "чистая" архитектура... Я имею в виду рекомендации:

  • Сделать несколько небольших проектов
  • Использовать управление зависимостями (например, Maven, Gradle)
  • Рефакторинг постоянно
  • Понимание и использование какой-либо инъекции зависимостей (Spring)
  • Напишите модульные тесты
  • Понимать проблемы с перекрестными проблемами (например, когда вам нужен AspectJ, метапрограммирование и т.д.).

Ответ 3

Из-за этого у нас нет "сущностей" в традиционном смысле (с идентификаторами), но подход, ориентированный на данные, делает этот слой данными уровень доступа, представленный остальной части приложения Потребитель-модуль.

Что-то кажется странным для меня в этой части. Почему ваши объекты не имеют идентификаторов, даже если вы получаете их из веб-служб?

В подходе "Чистая архитектура" уровень "Объекты" - это точно не уровень доступа к данным. Доступ к данным должен быть подробно в вашей архитектуре, а не в центре внимания. Как вы сами сказали, сущности содержат бизнес-правила, специфичные для домена. Бизнес-правила или поведение сильно отличаются от способов получения ваших данных.

Сущности - это то, где происходит вся логика домена, а не где вы получаете свои данные. Согласно Clean Architecture, вы получаете свои постоянные или внешние данные со шлюзов.

Одним из решений, которое я нашел для этой проблемы, является использование варианта "MVVM-pattern", который я выбираю для вызова MVC-VM. См. Ниже объяснение. "VM" - часть этого живет в этом слое Use Case, представленный * ViewModel-классами, которые инкапсулируют это использование Логика, зависящая от конкретного случая.

ViewModel ясно указывает на представление, которое представляет собой артефакт презентации, - еще одна деталь. Случаи использования/Взаимодействие должно быть лишено таких деталей. Вместо этого, Interactors должны отправлять и получать механизмы доставки - агностические структуры данных (RequestModels и ResponseModels) через границы.

Я понимаю, что это ваш собственный шаблон и не включает ссылку на структуру представления, но слово "View" просто вводит в заблуждение.