Совместное использование объектов DTO между микросервисами

15

TL; DR. Можно ли делиться библиотекой POJO между службами?

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

В моем случае - я рассматриваю сервис, который создает объект данных. Давайте предположим, что этот объект является ПЭТ. Это не объект базы данных, а строго POJO, который неявно представляет базовые данные. Этот POJO - это то, что определил API. Предположим: домашнее животное - возраст, вес, имя, владелец, адрес, вид и т. Д.

Сервис 1 - PetKeeper: он будет генерировать питомца по любой причине и сохранит все данные и должен ссылаться на эту услугу для получения питомца или внесения изменений в питомца, скажем, изменение имени или изменение адреса должно быть выполнено через API вызов этого сервиса.

Служба 2 - PetAccessor: эта служба собирает питомца и делает проверки

Сервис 3,4 - Дополнительные промежуточные сервисные звонки

Сервис 5 - Интерфейс пользователя

Это очень произвольно, но суть проста. Пользовательский интерфейс или какой-либо пользовательский сервис желает каким-то образом представить этот объект «PET». Он должен вызывать через API сервис, который вызывает сервис, который вызывает сервис и т. Д., Пока он не достигнет сервиса, который собирает необходимую информацию и запускает ретрансляцию. Наконец, у сервиса UI есть объект PET для отображения.

Это довольно часто - но с нашим абсолютным менталитетом мы дублировали объект PET в каждом сервисе. Принцип СУХОЙ (не повторяйся) применим только к коду ВНУТРИ услуги и не распространяется на другие службы, но суть все еще в силе. Что если мы добавим поле ... мы должны изменить 5 сервисов POJO в каждом.

--OR-- Мы можем предоставить Pet-Objects-Library, которая содержит некоторые pojo из API, и каждый сервис может импортировать / зависеть от библиотеки. Нет зависимости от самих сервисов, но есть только общая библиотека. Мне нравится эта идея, так что каждый сервис имеет один и тот же тип объекта, и обновления проще. Но я беспокоюсь о Боге-объектах.

Какие плюсы / минусы - какой дизайн лучший? Что вы сделали для передачи данных между сервисами, чтобы минимизировать повторение тех же классов POJO, оставаясь при этом не связанными?

Aerith
источник
@DaiKaixian: Конечно, вы не предлагаете , чтобы ОП шли с объектом Бога, не так ли? Это обычно считается анти-паттерном.
Макото
Я согласен с ответом @javaguy.
И я также хочу сказать, что вы можете рассмотреть шаблон посетителей. en.wikipedia.org/wiki/Visitor_pattern . Создайте все поля и методы установки / получения в POJO и поделитесь ими между микросервисами. Если вы хотите выполнить некоторую операцию над POJO в другом микросервисе, напишите некоторый VisitorClass.
Благодарю. Мое сомнение в том, что эта «общая библиотека» будет расти. И там будут объекты, о которых заботятся только службы 1 и 3, или 2 и 4, или все, или любая их комбинация. Тип общего пакета библиотеки DTO, в котором есть все DTO, использую ли я шаблон Vistor или простой DTO POJO или что-то еще. Допустимо ли включать все эти объекты, но стараться поддерживать его как можно лучше? По крайней мере, объекты предоставляются всем, кто в них нуждается, если они хотят их использовать ...

Ответы:

5

Какой дизайн самый лучший?

Вы можете повторно использовать один и тот же объект Pet DTO среди внутренних сервисов (которые обрабатывают типичную бизнес-логику), но когда дело доходит до уровня представления (пользовательский интерфейс), обычно рекомендуется использовать FormBean (другой компонент с добавленными полями). для логики представления), чтобы было четкое разделение между логикой представления и бизнес-логикой .

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

Что вы сделали для передачи данных между сервисами, чтобы минимизировать повторение тех же классов POJO, оставаясь при этом не связанными?

Если вы используете один компонент между бизнес-уровнями и веб-уровнями, то вы тесно связываете логику представления с бизнес-логикой, что не является хорошей практикой, и в итоге вы меняете службы для требований во внешнем интерфейсе (как, например, другой формат даты). быть показано в пользовательском интерфейсе). Кроме того, чтобы сделать этот процесс заполнения / копирования данных между компонентами (такими как DTO в FormBean или Viceversa), вы можете использовать библиотеки, такие как Apache BeanUtils.copyProperties() или Dozer, чтобы избежать шаблонного кода .

разработчик
источник
Я согласен с тем, что уровень представления, вероятно, должен десериализовать входящую полезную нагрузку как компонент представления с другими атрибутами, если это необходимо. Но в целом можно ли повторно использовать один и тот же объект (ы) DTO во всех серверных службах? Как правило, мы пытаемся выделить эти пакеты DTO в меньшие пакеты только для тех немногих служб, которые в них нуждаются. Я устал от того, что у меня есть какой-то хлам для пакета библиотеки DTO, в котором есть DTO для более чем 75 микросервисов, от которых зависят все сервисы. Разве это нормально, так как это просто DTO-объекты, которые являются необязательными?
Да, очевидно, что вы можете повторно использовать один и тот же объект DTO во всех однотипных внутренних службах, например, PetServicesво избежание дублирования. Но моя точка зрения не в том, чтобы тесно связывать бэкэнд и фронтэнд, вот и все.
разработчик
4

Если DTO представляет один и тот же бизнес-объект во всех микросервисах, то должен быть только один класс, совместно используемый службами. (Почти) никогда не правильно иметь дублированный код для одного и того же объекта.

Джим гаррисон
источник
3
Совместное использование DTO через микросервисы - это кошмар. "У этой версии уже есть это поле? Хм, может быть?" Через некоторое время вы получите настоящий беспорядок. Дублированный код хорош в этом случае.
Mejmo
1

Способ, которым я планирую сделать это сейчас, заключается в том, что каждый сервис упаковывает только DTO и помещает их в Nexus как jar lib. Когда другие сервисы нуждаются в них, они получают DTO lib (s) в качестве зависимости в manve / gradle. Если новая версия DTO выпущена на одном сервисе, это нормально, если одновременно поддерживается и старая версия, поэтому не нарушайте обратную совместимость, управление версиями и т. Д., Так что это область backend-to-backend. Также для предотвращения циркулярной зависимости лучше отделить сервис от dto-упаковки

Теперь посмотрим на бэкэнд-интерфейс, и наоборот, я не согласен с предыдущими комментариями о том, что пользовательский интерфейс как уровень представления отличается. НЕ ТО!!! Интерфейс для меня - это просто еще один микросервис, который также потребляет и генерирует события.

Направление от бэкенда к внешнему интерфейсу Что я делаю, так это конвертирую POJO (dtos) в интерфейсы Typescript, упаковываю в NPM и загружаю их в Nexus. Затем проект, основанный на UI nodejs, использует и использует их. Это способ обслуживания пользовательского интерфейса.

Направление от внешнего интерфейса к внутреннему Для событий пользовательского интерфейса на уровне сервисов я конвертирую интерфейсы Typescript и преобразую их в POJO (dtos), упаковываю как jar и загружаю в Nexus (или некоторое хранилище) в виде jar для использования бэкэнд-сервисами.

Эти процессы легко обрабатываются процессами CI (Travis, Gitlab CI и т. Д.)

Любые комментарии к этому подходу приветствуются.

Kensai
источник