у меня есть опыт написания подобного сервиса с небольшой нагрузкой, но необходимостью быстро отдать ответ, собранный из нескольких источников. тогда это было оправдано и неплохо работало.
а грабли и костыли в вашем случае говорят скорее о неопытности разработчиков.
отчасти согласен. после перехода из слака очень не хватало тредов, где можно было внутри чата обсудить конкретный вопрос. а так для структурирования достаточно имеющейся функциональности чатов/папок
Проблема 2. Телеграм мешает нормально вести задачи
они и не должны там быть, для этого есть трекеры/вики/рабочая почта. вопрос дисциплины
Проблема 3. Телеграм отвлекает
чаты можно мьютить. незамьюченный чат будет отвлекать вне зависимости от того, используете ли вы для работы телеграм или какой-то отдельный инструмент
public class MyService {
private final DbClient dbClient;
public void doSomething(Request request) {
Long id = dbClient.getLastId();
dbClient.update(id, request);
}
}
public class DbClient {
public Long getLastId() {
//запрос в БД
}
public void update(Long id, Request request) {
//запрос в БД
}
}
public class MyServiceTest {
private MyService myService;
public void doSomethingTest() {
DbClient dbClient = mock(DbClient.class);
when(dbClient.getLastId()).thenReturn(1);
doNothing().when(dbClient.update(any(), any()));
Request request = createRequest();
myService.doSomething();
verify(dbClient).getLastId();
veryfy(dbClient).update(eq(1), eq(request));
}
}
пример очень простой, но для более сложных случаев разница будет лишь в количестве тестов и моков. поведение мокается в самом тестовом методе, и для разных случаев можно определить разное поведение.
если такая операция вызывается только извне, создаётся обработчик для неё (handler/operation), последовательно вызывающий шаги (service)
можно использовать движок бизнес-процессов, где "создание заявки на кредит" выделено в отдельный процесс, который можно переиспользовать. и вызываться он будет непосредственно движком БП.
если операция должна переиспользоваться в рамках приложения, можно сделать класс типа "сервис", который и будет фасадом. но в случае, если это какие-то крупные шаги, придётся всё-таки нарушить правило "сервис не вызывает сервис".
если данная операция может выполнятся асинхронно, можно реализовать отправку сообщения в рамках одного приложения, использовав либо внешний брокер, либо возможности языка/фреймворка, чтобы положить событие в какую-то внутреннюю очередь. дальнейшая обработка согласно п. 1.
у меня на одной руке longines, чтобы смотреть дату-время (а ещё они красивые), а на другой браслет xiaomi с будильником и прочими уведомлениями. удобно.
у спецификации asyncApi есть особенность - там описываются параметры и запросов и ответов, а также топики/очереди, куда они кладутся (или откуда берутся). этим она принципиально отличается от openApi.
Отчасти с вами согласен, в массиве ошибок ошибки пишутся в произвольном формате, который схемой не задаётся. На нашем проекте о нём мы просто договорились. На бэке он генерится
Однако, если в email пришёл null, то это и есть null, т.к. в противном случае пришла бы ошибка.
Минусом же можно отметить необходимость в реализации как схемы, так и кода — это может занимать чуть больше времени при разработке API + теперь появляется 2 источника, которые обязаны не конфликтовать друг с другом и быть полностью синхронизированы - лишнее звено, которое может поломаться.
Можно генерить код из схемы, тогда конфликтов не будет, а вам не придётся писать лишний код. Мы используем для генерации graphql-java-codegen. Он позволяет генерить как DTO, так и интерфейсы API, которые потом можно реализовать, используя ваш любимый фрейсворк.
сейчас примерно так и сделал бы: завернул запросы в CompleatableFeature и смерджил результат. а тогда я был молод и горяч
у меня есть опыт написания подобного сервиса с небольшой нагрузкой, но необходимостью быстро отдать ответ, собранный из нескольких источников. тогда это было оправдано и неплохо работало.
а грабли и костыли в вашем случае говорят скорее о неопытности разработчиков.
спасибо за статью! интересно было бы посмотреть исходный код микросервисов.
ещё вопрос - пробовали ли добавлять трассировку (MDC)? какой это даст оверхед для WebFlux?
по пунктам
отчасти согласен. после перехода из слака очень не хватало тредов, где можно было внутри чата обсудить конкретный вопрос. а так для структурирования достаточно имеющейся функциональности чатов/папок
они и не должны там быть, для этого есть трекеры/вики/рабочая почта. вопрос дисциплины
чаты можно мьютить. незамьюченный чат будет отвлекать вне зависимости от того, используете ли вы для работы телеграм или какой-то отдельный инструмент
при изменении реализации DbClient сломается интеграционный тест. мок не сломается, т.к. его поведение задаётся в тесте
что вы подразумеваете под контрактом?
пример
пример очень простой, но для более сложных случаев разница будет лишь в количестве тестов и моков. поведение мокается в самом тестовом методе, и для разных случаев можно определить разное поведение.
если такая операция вызывается только извне, создаётся обработчик для неё (handler/operation), последовательно вызывающий шаги (service)
можно использовать движок бизнес-процессов, где "создание заявки на кредит" выделено в отдельный процесс, который можно переиспользовать. и вызываться он будет непосредственно движком БП.
если операция должна переиспользоваться в рамках приложения, можно сделать класс типа "сервис", который и будет фасадом. но в случае, если это какие-то крупные шаги, придётся всё-таки нарушить правило "сервис не вызывает сервис".
если данная операция может выполнятся асинхронно, можно реализовать отправку сообщения в рамках одного приложения, использовав либо внешний брокер, либо возможности языка/фреймворка, чтобы положить событие в какую-то внутреннюю очередь. дальнейшая обработка согласно п. 1.
для моков интерфейс не нужен. не скажу за другие ЯП, но в Java всё прекрасно мокается без использования интерфейсов
можно, но это не будет так хорошо масштабироваться по мере роста проекта
враньё. я могу не заполнять поля в запросе. и это будет корректно с т.з. proto. а вот null выставить явно нельзя. только тут про это ни слова.
у меня на одной руке longines, чтобы смотреть дату-время (а ещё они красивые), а на другой браслет xiaomi с будильником и прочими уведомлениями. удобно.
у спецификации asyncApi есть особенность - там описываются параметры и запросов и ответов, а также топики/очереди, куда они кладутся (или откуда берутся). этим она принципиально отличается от openApi.
Ситуация:
сервис ServiceA умеет отправлять сообщения формата FormatA и получать сообщения формата FormatB
сервис ServiceB умеет отправлять сообщения формата FormatB и читать сообщения формата FormatA
вопросы:
где должна лежать спецификация в этом случае, в сервисе ServiceA или в сервисе ServiceB?
где будет лежать спецификация, если схема взаимодействия усложнится и количество сервисов увеличится?
Если бы контракт содержал только описание моделей, то можно было бы держать его в сервисе-отправителе.
Лайфхак - если непосредственно перед генерацией в контракте заменить
asyncapi: 2.6.0наopenapi: 3.0.2, а модели предварительно вынести в блокдля генерации моделей можно будет использовать gradle-плагин.
спросите легендарную hr хоум кредита, как мотивировать сотрудника. удивлён, что её не пригласили в качестве эксперта.
Отчасти с вами согласен, в массиве ошибок ошибки пишутся в произвольном формате, который схемой не задаётся. На нашем проекте о нём мы просто договорились. На бэке он генерится
Однако, если в email пришёл null, то это и есть null, т.к. в противном случае пришла бы ошибка.
про schema-first не понял
Можно генерить код из схемы, тогда конфликтов не будет, а вам не придётся писать лишний код. Мы используем для генерации graphql-java-codegen. Он позволяет генерить как DTO, так и интерфейсы API, которые потом можно реализовать, используя ваш любимый фрейсворк.
Убираем обязательность из полей ответа. Клиент сам может решить, что ему запрашивать.
Пишем ошибку доступа в стандартный блок ошибок.
И не нужно заморачиваться с юнионами
PersonItem/PersonError.PostgREST даст вам возможность не только логику в БД положить, но и выставить наружу API! Вот только стоит ли так делать?
На Android в приложении Сбера работает