АрхитектураМикросервисы и интеграцииАрхитектор распределённых систем

В событии заказа передаётся сумма без валюты, и разные потребители трактуют её по разному. Какой вывод о гр...

В событии заказа передаётся сумма без валюты, и разные потребители трактуют её по-разному. Какой вывод о границе интеграционного контракта должен сделать архитектор?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

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

Исторический контекст

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

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

Постановка проблемы

Поле amount без валюты допускает несколько интерпретаций: рубли, доллары, валюта заказа или валюта аккаунта. Потребитель может корректно обработать формат сообщения, но принять неверное бизнес-решение.

Последствия зависят от сценария: неправильное отображение цены, ошибочный расчёт комиссии, некорректное списание или искажение финансовой отчётности. Версионирование схемы само по себе не устранит проблему, если новая версия по-прежнему допускает неоднозначное толкование.

Подробное решение

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

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

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

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

Есть компромисс: более полный контракт увеличивает объём данных и требования к документации. Однако это обычно дешевле, чем переносить доменные догадки в каждый потребитель, где они начнут расходиться и станут трудноуправляемыми.

Ситуация из практики

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

Рассматривались три варианта. Первый — договориться, что валюта всегда одна: это просто, но ограничивает домен и создаёт риск скрытой зависимости. Второй — заставить каждый потребитель получать валюту отдельным синхронным запросом: это сохраняет компактность события, но добавляет связанность, задержки и новую точку отказа. Третий — включить валюту и правила интерпретации непосредственно в событие.

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

Что кандидаты часто упускают

  1. Достаточно ли добавить код валюты, чтобы контракт стал корректным?

Нет. Нужно определить, что именно означает сумма: включает ли она налог, скидку, доставку и комиссию, в какой момент зафиксирована и какие правила округления применяются. Код валюты устраняет только одну часть неоднозначности.

  1. Можно ли считать изменение смысла поля обратно совместимым, если его тип и название не изменились?

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

  1. Где должна находиться логика конвертации валюты — у продюсера или у потребителя?

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