Комментарии 64
Хорошо забытое
Запись на стене
И почему бы не остаться на SOAP + XDTO и т.п.?
wsdl
Шаг влево или вправо - расстрел и тотальное падение. С большим количеством сервисов это пытка.
Думаю, это такая ирония.
Реализация SOAP на JSON тоже странная затея. Как-будто игра в энтерпрайз, наклеим усы и притворимся большими.
Не напоминайте. Я же это видел.
Если отсылка к публикации контрактов, то скажу вот что: часть контрактов может быть платформенная или от СБ, она особо не меняется и обязана поддерживаться, там гибкость может вредить.
Публикация моделей не заставляет абсолютно всех абсолютно все модели использовать. Тут пространство для проектирования и выбора.
Лично мне на моём проекте это полезно.
Такую особенность можно включать и выключать, это не краеугольный камень слоистости, а доп. опция.
SOAP, всё ж, строже намного.
Я просто пытаюсь увидеть, в пределе это выльется в "SOAP", когда вдруг окажется, что риски несоблюдения значительно выше соблюдения контрактов или нет.
Потому что это совсем не редкость, когда в процессе возникает : "Аааа, так вот почему они так сделали".
Ведь JSON и появился для того, чтобы сначала делать, а потом думать. Теперь свежая идея - сначала подумать, нарисовать, спроектировать. А как добиваться соблюдения договоренностей? Где-то достаточно физической силы, а другим нет.
Насколько в обратную сторону качнется, интересно же.
И эти агенты ИИ, которым палец в рот не клади. Там может и еще строже что придумают.
Ну и SOAP придумали в другое время, когда еще яндекс не обучал всех подряд, а систем было на порядки меньше.
Слоистая архитектура для людей
Нет, это написано не для людей.
Для людей бы начали с описания решаемой проблемы: такая то предметная область, столько то сервисов, столько то команд разработчиков. Решили использовать микросервисы и Java как едиснтвенный язык реализации.
И затем уже перешли бы к описанию ваших прости госпроди мавенов, нексусов и прочей фигни, имеющей весьма отдаленное отношение к архитектуре.
Да, можно пойти издалека и налить воды. Да, можно игнорировать NDA и описать предметную область. Это было бы втрое больше.
Да, можно было бы написать ADR и C4, но это была бы другая статья.
Да, можно было написать верхнеуровневые требования и спроектировать платформу. Но это тоже была бы другая статья.
У меня не было таких целей.
Предложенные решения можно применять к разным предметным областям в энтерпрайзе.
Я не описываю архитектуру всей системы, уровень абстракции гораздо ниже. Я не описываю продукт, и не хотел.
Зачем я буду писать, что выбирал джаву и мавен (не знаю, какую вы статью про мавен читали, не уверен, что эту), если я не выбирал это?
Да, можно было бы написать ADR и C4, но это была бы другая статья.
Да, можно было написать верхнеуровневые требования и спроектировать платформу. Но это тоже была бы другая статья.
Я не описываю архитектуру всей системы, уровень абстракции гораздо ниже.
Да, действительно зачем в статье с названием про архитектуру писать что-то про архитектуру.
У меня не было таких целей.
Тогда возможно стоило бы назвать статью например "структурирование кода микросервисов на джаве".
Зачем я буду писать, что выбирал джаву и мавен
Да не пишите что вы их выбирали. Напишите сверху что статья про джаву и мавен. Чтобы люди, которым джава монописуальна сразу закрыли вкладку и не ломали себе глаза.
ИМХА, предложенный подход выглядит несколько эм... нестандартно, и деплоймент микросервисов в "по слоям" выглядит оверинжинирингом(а разбиение отвественности людей "по слоям" также не выглядит самым лучшим менеджерским решением). Но оправдано ли это - мы никогда не поймем потому что не знаем ничего о контексте в котором принимались эти решения и какие альтернативы рассматривались. А может это вообще best practices в экосистеме java, но наверное и это тоже стоило бы упомянуть.
По меткам и хабам должна быть отсылка к java.
Но стоит в тизере указать ещё раз, возможно.
Отсылки к бест практис и книгам по ссылкам в статье. Если никогда не читать и не пользоваться - то никогда не узнать, верно.
Да, действительно зачем в статье с названием про архитектуру писать что-то про архитектуру.
"Что-то" не хочу, я не индус и не Маяковский, нет KPI по строкам.
ADR и C4 неприменимы в этом контексте и на этом уровне абстракции, он слишком низко находится для таких аббревиатур. Употребление этих терминов потребовало бы совсем другую статью, другую целевую аудиторию и другие хабы. Нельзя в одной статье рассказывать и поо контекст контейнера, и про слои микросервиса. Было бы смешение уровней абстракций.
Нельзя в одной статье рассказывать и поо контекст контейнера, и про слои микросервиса.
Да, но только архитектура - это про ADR. Про нефункциональные требования и работу с ними. А про слои внутри микросервиса - это даже не low level design. NFR выполняется, контракты соблюдены - да и пофиг что внутри, оно же МИКРО и если там говнокод - то он и останется локализованным и управляемым.
Код может и да. Но ошибки аналитики, проектирования, контрактов.
Но ошибки аналитики, проектирования, контрактов.
Это все бывает, но причем тут слоистая архитектура микросервисов?
Переизобретенное заново колесо "шарьте бинарные контракты между сервером и клиентом, если у вас один тех стек"? Чем это помогает исправить ошибки аналитиков?
Или связанная с этим гениальная идея
При изменении версии стороннего сервиса, разработчики другого сервиса уведомляются
помогает как то решить проблему версионирования контрактов и синхронизации роадмапов разнызх команд ? Вот уведомили и вуаля, 0-downtime update with breaking contracts changes is done? Это так не работает в реальном мире, даже приведенная пошаговая инструкция не избавляет от необходимости поддерживать 2 версии контрактов одновременно(или избавиться от независимого деплоя микросервисов) - вот тут блин компромисы и сложность.
А в нынешнем мире так вообще, ИИ по контрактам и описанию FR/NFR может говнякать типичные микросервисы штук несколько в сутки. И оно будет вменяемо работать, вот такая незадача. Без слоеных архитектур и хранилищ бинарных файлов. Вот такая незадача.
"Где-то" LLM действительно может штамповать сервисы, а у нас конкретно - куча НФТ, так что без локальной/корпоративной LLM с хорошими ресурсами не обойтись. В любом случае это вопрос, может и недалёкого, но будущего.
ИИ - вообще отдельная тема. Сейчас провожу эксперимент, начал писать статью. Пока скептически отношусь. Может, удастся сделать полезные выводы. Многое, понятное дело, упирается в ресурсы.
На текущий момент мы не можем полностью автоматизировать. Проекты в каком-то необычном гибридном состоянии. Мы с коллегами пытаемся заранее чуть "подстелить соломки". Я в прошлом году, например, отфильтровывал с рынка сильных профессионалов, о чем писал статьи,- даже при наличии материальных ресурсов кому-то надо отслеживать и валидировать результаты, когда внезапно накроет светлым будущим.
Пока что работаем через высокую планку входа и попытки формализации архитектурных нюансов. Время покажет, насколько оправдано. Имхо, результат, каким бы то ни был, покажется в ближайший год.
без локальной/корпоративной LLM с хорошими ресурсами не обойтись
Вы не первые, посмотрите в сторону AWS Bedrock/Azure OpenAI - там они мамой клянутся что дальше вашего аккаунта данные не уйдут.
кому-то надо отслеживать и валидировать результаты
Ессна, полностью автоматизированный цикл разработки по "наброскам требований от бизнеса" - утопия.
В общим вкидываться в архитектуру микросервисов(да еще и затачиваться под один тех стек) - затея стремная и прогресс ИИ это хайлайтит.
Контракты и API (а здесь указаны только внешние API) вещи разные. А тут всё в одну кучу: монолиты, микросервисы, зелёное, длинное.
Микросервисы как-то не слоистая совсем, наоборот: режем по модулям и каждый имеет все слои.
Разработка API по принципу «сначала контракт» приобрела популярность с появлением сервисно-ориентированной архитектуры (SOA), а позже — с развитием микросервисной архитектуры
Но к монолиту подходит. Очень распространено для описания связи фронт бэк так как компилятор её проверить не может. И ещё для связей между доменами в ддд
Наверное контракт это некое ограничение в коде, например интерфейс, что для меня, как разработчика, сразу понятно. А вы про какие-то контракты в текстовом виде что-ли? Под нейросетки готовитесь?)) Замаскировали слово промпт))
Иначе я не понимаю что за контракты могут храниться в конфлюенсе, или рядом с задачей в жире...
Вот такой контрак - делаем хорошо, плохо не делаем. Возле каждой задачи
Вообще это ещё 1 винегрет из "архитектурных" терминов (DTO, DDD, контракты, интерфейсы, слои и тд и тп) а по сути смысловая нагрузка 0 (сугубо моё мнение). У вас такое количество слоев, половина без кода (????) Ошибки генерятся со слоя домена, а если к базе не получится подключиться, эта ошибка будет с доменного слоя тянуться, а не со слоя с базой данных?)
Вот вам и протекание вашей архитектуры, воды налили, слова использовали, а толку...
Люди в конфлюенс выкладывают текстовые описания API например.
Дифы, правки моделей описывают в комментариях к задачам.
Документация может лежать в папочке на сетевом диске.
Как только не хранят контракты и договоренности!
Тут вопрос в организации процессов разработки, зрелости команды, наличия инструментов. Например, почти на каждом проекте мне дают почитать OpenAPI синхронную интеграцию (модели и методы) как таблицу на странице в конфлюенсе. И во многих компаниях это считается нормально.
Какая именно половина без кода? Можно поинтересоваться алгоритмом подсчета?
Ошибки генерятся со слоя домена, а если к базе не получится подключиться, эта ошибка будет с доменного слоя тянуться, а не со слоя с базой данных?)
Если обработать на слое хранения, до за свой слой она не выпадет никуда. Аналогично ошибки от условного RestTemplate.
Как запрос вообще может добраться до домена если проект к базе даже не подключился?))
База может отвалиться в процессе работы
Stateless?
Вместо БД кеш?
Разные варианты бывают. Не понятна суть вопроса.
Насчет проброса ошибок. В принципе, от слоёв ddd отличий почти нет.
В "портовых" слоях ловим asap, оборачиваем в ошибку (которая exception или которая data class, в этом контексте не важно), ошибка через интерфейс- порт доходит до доменного слоя (тут не важно, склеены domain и domain-logic), дальше или возвращается в качестве ответа в web client, либо спринговый aop перехватывает и формирует ответ.
Если же доменная логика вызвана не из web-слоя, то по ошибке формируется event или response, смотря по какой схеме работаем с асинхронщиной.
Возможен гибридный подход, когда в условную кафку event всегда генерируется, независимо от успешности, и дальше в web возаращается.
Так что отвечая на ваш вопрос
будет с доменного слоя тянуться, а не со слоя с базой данных?
Да, доменное исключение с доменного слоя
И
эта ошибка
Нет, не "эта". Сама ошибка jpa инкапсулирована в своем слое хранения и не идет за границы, как, например, не идут dao-модели.
А вот на этот вопрос:
а если к базе не получится подключиться
ответ такой: это подключение в Java-spring-data происходит несколько раньше клиентского вызова, не в иомент обработки запроса. Условно говоря, его делают нагенерированные спрингом классы, стартующие с сервисом.
Я не знаю что такое DDD слои, вы говорите много, а толку...
Можно перейти по ссылкам в статье, почитать упомянутые книги, может появится толк.
Вот вы пишете, что были на 25+ собеседованиях. А я - на 250+, и чуть меньше - сам проводил.
Это архитектурная статья, не совсем для разработчиков. Для ее прочтения нужно как минимум хорошо понимать такие буквы, как DRY, ACID, SOLID, CAP, API, TCP, SDK, MQ, REST, RPC, RESTFul, k8s, DDD, а еще владеть буржуйским языком, в котором: concurrency, api first, swagger, asyncapi, и много чего другого.
И статья в основном про глубокую степень контейнеризации элементов системы, сиречь jvm-стек в оркестрации.
И это я не упомянул массу других нюансов, как безопасность и инкапсуляция инфраструктуры и данных.
Толк будет, если всё это изучить. Таков беспощадный оскал современного облачного энтерпрайза.
Дак вы сами не знаете ничего из этого, скрин ниже с вашей архитектурой это хорошо показывает, значит и писать, а темболее учить, вам, как минимум меня, нечему
Ну и если вы про контейнеризацию это про микросервисы, то я на этот недоинженерный подход не ведусь. Вы учите что хотите, какой хотите "энтерпрайз" стройте. Только вам других пока нечему учить, только путать все
Че я тут вообще расписываю, у вас 3 слоя без кода в проекте, я уже и забыл ахахаха)))
И не пытался учить, нет таких целей. Я рассказываю, как делают у меня на проекте. Кто не понимает подходов - волен реализовывать все в одном методе.
Нет, не три слоя.
В openapi наборы ямлов от аналитиков и архитекторов, каждый может отвечать за свою часть, дальше арх. надзор , аппрув и компиляция в общий openapi, по которому отрабатывает openapi-generator. Это полноценный слой, в котором работают только аналитики и архитекторы. Код там ямлы, который они собирают. В этом же слое, при необходимости, можно настроить генерацию схемы для документации.
В asyncapi ямл и dto. В зависимости от микросервиса и особенностей стека эти dto contract first или написаны разработчиком. Могут быть вспомогательные классы при необходимости. Цель слоя-публикация артефакта в нексус и фиксация контракта. Возможна гибкость. При наличии доп. кода юнит-тесты, обычно нет или мало.
Api - слой со сгенерированными классами для обмена, тоже могут быть вспомогательные классы, тоже нужно для публикации.
Как тут вообще люди считают? То половина пустых слоев, то три.
Мне искренне жаль людей которые прислушиваются к вашему "экспертному" мнению, так и карьеру можно потерять толком не начав её, если в голову отсебятину псевдоинженерную заталкивать, а не нормальные знания.
Ещё раз вам по поводу пустых слоев - это ваша цитата из вашей статьи и это правда очень меня смешит каждый раз, спасибо что напомнили про такой случай 🤣
Нет, цитата о половине пустых слоев не от меня. И у меня в продуктовом коде не так. У каждого слоя свое предназначение, разделение по зоне ответственности даже для людей : что-то правит разработчик, что-то аналитик.
Удачи вам в ваших компаниях, надеюсь они хотя-бы не выдуманные
Я же названия конкретные писал. Названия выдуманные? Серьёзно? Можно устроиться на работу, если возьмут, посмотреть всё изнутри.
Отличная статья. Но довольно сложная для восприятия, потому что тема на самом деле ооооочень многогранная и сложная.
Было бы очень круто увидеть демонстрационный проект. Это позволило бы ответить на большое количество вопросов, а тем, кто готов этим пользоваться - позволило бы намного быстрее начать.
Да, тема важная, горячая, сложновата. Я давно варюст в таком энтерпрайзе, для меня это скорее средний уровень, но перестраховался и поставил сложный. Как оказалось - не зря. (Такое ощущение, что комментируют не читая).
Сам проект - увы. Для написания питомца тоже сложновато, нет столько времени. И для питомцев все это не нужно.
Но. Я тут уговариваю электронного товарища сварганить картинку - имитацию дерева проекта в идее. Добавлю в статью, лучше должно стать.
Не, не, не)) Вместо картинки лучше уж в самых простых вариантах пример. Я сам сторонник такого подхода, но подступиться очень тяжело. И самому тяжело и плюс сопротивление коллег как правило нешуточное. Какое там апи, которое аналитики напишут с архитектором... Сваггер + @Schema наше все, rest-service-dao самые лучшие и понятные слои. И вообще, работать надо, а не фигней всякой страдать, времени на это сейчас нету...
Да, вы говорите про слои ddd, как кажется, я тоже когда-то делал так или dto-api-impl(domain-dao-web).
Верно, работать надо)
Наверно со временем нейронкой по картинке сгенерирую прототип, чтоб подсунуть в статью в качестве примера.
А чему коллеги сопротивляются, если не NDA? И какие аргументы?
Быстро структуру проекта можно показать только так
Не NDA конечно. Обычные человеческие слабости. Сложно, не нужно, непонятно, непривычно, избыточно...
За структуру спасибо, очень интересно! Есть несколько вопросов.
1) АПИ в отдельном слое/модуле - ок. Домен в отдельном слое/модуле - ок. Но насколько оправданно выносить из слоя api слои connector, messaging-int, web? Не было бы удобнее перенести их в app ? Ведь по сути это то, что нужно для работы приложения.
2) Почему домен разбит на два модуля - domain и domain-logic? Не является ли это избыточным разбиением? Сущности домена - анемичные или с логикой? Если с логикой, то не является ли избыточным domain-logic и почему дополнительная логика не реализована в app/service вместо целого модуля domain-logic?
3) Насколько оправдан вынос entity из домена? Я имею ввиду, почему не стали реализовывать entity используя доменные объекты, а вместо этого решились на введение дополнительных мапперов и конвертаций? Насколько это оправданно и удобно?
4) Где тесты (вижу только пакет с интеграционными) ? :)
Набор слоёв частично пришёл "сверху", немного другой. Добавить получилось, убрать - нет. Громко ныл на собраниях, в будущем доменные слои может удастся склеить. Но будет уже много кода, и будет не так просто убирать.
1 Connector, messaging, persistence - имплементация портов, это про гексагональность. В будущем действительно может измениться тип СУБД. Остальные имплементации вряд ли. У меня тоже сомнения в уместности.
Что касается коннекторов. Обращения к общим, системным сервисам, постепенно выносится в корпоративную библиотеку, так что там скоро останутся импорты. Обращения к другим сервисам продукта сейчас пытаются кодогенерировать по контракту, так что, наверно, со временем количество кода в этом слое уменьшится.
Что касается messaging. Если условно приватные и публичные интеграции. Такие контракты утверждаются разными способами, чуть разные требования. Разделение на внешние и внутренние позволит лучше контролировать рзменения, и показывает разработчику, что можно шатать, а что - ни в коем случае.
Что касается app. Там интеграционные тесты и отдельный подсчет покрытия. Имхо получился сплав жёсткого насаждения и компетенций девопсеров. С продуктовой точки зрения наверно бесмыссленный слой, только приложение, стартующее всю спринговую машину.
2 Разбиение домена на модели и логику насадили извне можно сказать. От этого вижу один сравнительно маленький плюс: слои чуть меньше, модели почти не меняются, меняется логика, оптимизация сборки градлом. Слабый аргумент. Думаю, через год может что-то измениться, когда получим опыт разработки и поддержки.
Доменные модели лично я запрещал с логикой. Дата-классы. В других командах мягче требования.
Дополнительную логику от дата-классов выносили в экстеншены (это в котлине типа утилитарных методов), отдельно, но при необходимости. Это обычно для логов, мониторинга, упрощение обращений к каким-то полям. Ничего длинного и сложного.
Принял по всем пунктам, большое спасибо за развернутые ответы!
"Доменные модели лично я запрещал с логикой. Дата-классы." - тут просто решили не связываться с DDD ?
Логика рядом, чем не DDD? Может не очень канонично.
Там вопрос еще расчета покрытия тестами. Интерфейсы и дата-классы не нуждаются. По маскам имен и путей проще исключать единообразно.
Ну все таки DDD это про перенос логики прямо в доменный объект. А если логика оттуда выехала, то это уже анемичная модель.
Но это я так, просто расставить точки над i. Мне самому не до конца нравится история, что в классическом DDD все равно приходится сидеть на шпагате - часть логики у нас в классах доменных объектов, а часть (это неизбежно) выезжает в отдельные сервисы.
3 А вот вынос DAO оправдался. За счёт Contract First сложная вложенность классов в DTO, почти 1-к-1 маппится на доменную модель, она тоже "структурированная", в одном из продуктов видно. На это опираются валидации и всякие пользовательские истории. А вот модели хранения упростили, "уплостили", в одном из продуктов навесили проекций.
Для будущей поддержки, поиска данных должно быть проще. Ну и часть искусственных требований нам выдвинули.
Но, к слову, там удалось модели сделать так, чтоб чуть оптимизировать хранение и поиск. Использовали особенности РСУБД. Еще один аргумент за слой persistence.
4 Юниты в каждом слое с кодом кроме app. Вроде писал. Рисовать не стал, чтоб не мусорить.
Представляется совершенно логично, что domain содержит 2 раздела - Entities и Logic. Совершенно непонятно зачем его разбивать на 2 модуля.
В предыдущих коммантариях отвечал. Если кратко - это решение "сверху".
Постарались получить плюсы от такого подхода.
О, у вас такая же статья для решётки.
Не знал, насколько onion популярен в других ЯП.

Слоистая архитектура для людей