Как стать автором
Обновить

Комментарии 19

Вот убейте меня, но я все никак не пойму. Бэкендисты столько страдали, чтобы прийти к таким паттернам архитектуры как микросервисы, разделения всего и вся - от базы до моделей и обратно. И все равно придет кто-то да и посоветует делать shared dependencies.

И как бы сексуально это не выглядело, по моему личному опыту shared stuff это всегда проблемы. Это всегда зависимость от чего-то или кого-то еще.

Переубедите меня Ж)

шарить не код, а интерфейсы (типы) в общую библиотеку вроде всегда было нормой.

Да нет. Как минимум в микро-сервисной архитектуре. В идеале не должно быть общих зависимостей. Ни моделей данных базы, ни dto, ни чего либо еще. Все должно быть по максимуму независимым.

Создание зависимостей, как вы их не назовите - останутся зависимостями и может выйти боком. Версионирование, разный цикл разработки и релизов различных сервисов в конце упрется в эти зависимости.

Хотя возможно для каких-то проектов это и будет работать.

К примеру у вас микросервис users должен возвращать UserInterface

Если не шарить его - у вас в микросервисе users будет UserInterface, на фронте будет такой же дублированный UserInterface, на сервисе orders будет такой же дублированный UserInterface, потому-что каждый дергает /users/1, не лучше этот интерфейс поставить как зависимость?

Именно. Как показывает практика - не лучше. На эту тему много в интернете написано. Кажется контр-интуитивно. Как это!? А как же DRY?

По факту, это то что дает независимость. Естественно не бесплатно. Поэтому у ваш должно быть достаточно тестов чтобы предотвращать всякие инциденты.

У вас в сервисе ордер будут свои DTOошки, свои модели данных базы и т.д. Даже если сегодня они выглядят одинаково (так же как и в сервисе users).

У вас в сервисе ордер будут свои DTOошки, свои модели данных базы и т.д. Даже если сегодня они выглядят одинаково (так же как и в сервисе users).

Они всегда будут одинаковые, так как это результат респонса микросервиса users, он не может быть другим

Поддержу @AlexSpaizNet против дополнительной зависимости.

Как по мне, какая разница межу шаред-типами\сгенерированными клиентами и копипастой типов на клиенте-сервере, если итоговое количество телодвижений при изменении контракта будет одинаковое?

Например, при изменении контракта:
1. если у нас шаред типы или автоматически сгенерированный клиент, нужно:
- скачать / обновить типы или клиент;
- подправить логику и/или UI;

2. если у нас дублирование типов, нужно
- подправить типы на клиенте;
- подправить логику и/или UI;

Поправьте, пожалуйста.

Да, но одно дело запустить короткую команду в консоли, другое обновить 10 интерфейсов, что быстрее? А еще как минимум можно что-то упустить при обновлении и поймать баг, а если автоматом обновить то линтер подсветит несоответствие.

Всё-равно как-то не могу понять профиты.

Часто ли приходится обновлять сразу 10ть интерфейсов? А если и приходится, то после "выполнения короткой команды в консоли", как понять что именно обновилось, всматриваться в какие-то диффы?
При ручной правке, как-то более осознанно всё происходит.. постепенно что-ли, сразу прикидываешь что и где поламается, по очереди правишь себе спокойно.

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

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

А еще как минимум можно что-то упустить при обновлении и поймать баг, а если автоматом обновить то линтер подсветит несоответствие.

тут не совсем понял. Подправил руками тип, оно ж даже не скомпилируется, вперёд править и логику..)

всматриваться в какие-то диффы?

Дальше можно не читать.

Обычно в ide можно посмотреть какие файлы изменились и что в них поменялось. Еще чейнджлог может быть.

Да нет. Как минимум в микро-сервисной архитектуре. В идеале не должно быть общих зависимостей. Ни моделей данных базы, ни dto, ни чего либо еще. Все должно быть по максимуму независимым.

Вы путаете зависимости и API.

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

Для решения таких проблем были придуманы всякие Swagger и GraphQL. Но можно и просто типы TypeScript использовать. Да хоть клинопись, если вашим разработчикам удобно её поддерживать в генераторах. Как-только сервис какому-то разработчику отдали 200-й ответ на запрос, и разработчик на основании этого ответа написал что-то у себя у вас появилось API, хоть и недокументированное.

А микросервис не экспортирующий никакого интерфейса может быть только на выключенном сервере.

Бэкендисты столько страдали...

"Проблемы индейцев бэкэндистов шерифа архитектора не волнуют" (с) Если смотреть на web-приложение с "высоты птичьего полёта", то бэк и фронт де-факто связаны по данным. И если бэк чего-то поменял в своём API, то на фронте, чтобы он продолжал работать правильно, это должно отразиться. Мы не можем убрать зависимость фронта от бэка, мы можем лишь переместить взаимозависимые структуры в отдельный пакет (модуль, файл) и замкнуть на них фронт и бэк, либо параллельно вносить изменения в обе части. И да, shared stuff - это всегда проблемы, даже если они не выделены в отдельный пакет, а "размазаны" по фронту и бэку. Но разрабам как раз и платят деньги за решение подобных проблем. А кто и как их решает - то на собственное усмотрение.

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

И да, я не против BFF. Бизнес логика на клиенте это почти всегда катастрофа. Да и тут вроде понятно в чем минусы-плюсы.

Я против Shared types... нахавались... но опять же, это немного холиварная тема. Мы страдали потому что много разработчиков, продуктов, апишек, клиентов, требований, версийб багов...

Я не знаю, что вы подразумеваете под Shared Types, но в любом API, в котором передаются данные (например, таком), есть структуры, используемые как клиентом, так и (микро)сервисом. И вынесение подобных структур в отдельный пакет и замыкание на них клиента и сервиса - в этом нет ничего плохого. Особенно, если пользоваться версиями.

Полагаю, что тут проблема не в Shared Types, а в том, что "много разработчиков, продуктов, апишек, клиентов, требований, версий, багов...". А в итоге досталось Shared Types ;)

Кстати, заголовочные файлы C/C++ - это тоже в какой-то мере shared types (интерфейсы). Так что эта практика в IT проверена временем.

Почему просто не использовать OpenAPI (Swagger)? Из него можно автоматически генерировать клиентов как фронта так и для общения между сервисами на бэке (refit/retrofit) так же получаем хорошую документацию API

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

Так это все генерируется из комментариев к коду

Да, но большую часть можно не писать, а брать из того что есть. Например валидацию из реквеста, url из роута итд.

не совсем понимаю зачем это писать в комментариях. Валидация берётся из анотаций к модели, про url в сваггере тоже не понятно

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории