Я не открываю внутреннюю модель данных системе-партнёру, даже если так быстрее

Я не открываю внутреннюю модель данных системе-партнёру, даже если так быстрее. Внутри каждого продукта есть таблицы, статусы, технические поля и временные обходы. Они помогают ему жить сегодня, но не обязаны становиться обещанием для другого продукта.
Интеграция ломается не в тот день, когда два API впервые соединили. Она ломается позже, когда одна команда честно улучшила свою внутреннюю модель, а другая незаметно зависела от детали, которую никто не называл контрактом.
Внутреннее устройство и договор — разные вещи
Представим систему заказов. Внутри неё может быть десяток статусов: технический, расчётный, складской, статус доставки, флаг ручной проверки. Партнёру не нужна вся эта кухня. Ему нужно надёжно получить несколько понятных событий: заказ принят, отменён, готов к отгрузке.
Когда наружу выдают все внутренние поля «на всякий случай», партнёр начинает использовать их как основу своей логики. Потом команда меняет один флаг, объединяет два статуса или переносит расчёт в другой сервис — и изменение превращается в чужую аварию.
Я стараюсь сначала описать внешний смысл, а потом уже форму данных. Не «поле status содержит 7», а «заказ подтверждён и может быть передан в склад». Это медленнее на старте, но дешевле при первом серьёзном изменении.
Почему прямой доступ почти всегда кажется удобным
Прямое чтение таблицы или базы данных даёт быстрый результат. Не нужно обсуждать формат, ждать новый метод API, описывать событие. В коротком проекте это выглядит разумным. Но вместе с данными наружу уходит скрытая зависимость: структура хранения становится частью чужого процесса, хотя команда её такой не планировала.
Особенно опасны служебные поля. Сегодня они заполнены всегда, завтра их расчёт переносится в другой сервис или меняется порядок обновления. Внутренней команде это может быть безразлично: интерфейс и отчёты продолжают работать. Партнёр же получает неполные данные и начинает принимать неправильные решения.
Внешний контракт создаёт полезную паузу. Он заставляет задать вопрос: кому и зачем нужна эта информация? Иногда после такого вопроса выясняется, что партнёру нужен не список полей, а одно новое событие. Оно проще, понятнее и переживает рефакторинг.
Хорошая граница отвечает на три вопроса
Первый: какое бизнес-событие произошло? Второй: какие данные партнёру действительно нужны, чтобы отреагировать? Третий: что он обязан считать неизменным, а что может меняться?
Если на эти вопросы нет ответа, API обычно быстро обрастает полями, которые «никто не трогает». Это плохой признак. Непонятная неизменность дорого обходится: команда боится улучшать систему, потому что не знает, где сидит зависимость.
Полезно сделать контракт маленьким и ясным. Для события оплаты это может быть идентификатор заказа, сумма, валюта, момент подтверждения и ссылка на безопасный способ получить детали. Не обязательно отправлять весь объект заказа вместе со служебными заметками и историей редактирования.
Не скрывайте изменения — управляйте ими
Граница не означает, что контракт никогда не меняется. Она означает, что изменения происходят предсказуемо. Новое поле можно добавить, если старый клиент его проигнорирует. Смысл старого поля нельзя тихо заменить. Удаление требует срока, версии или альтернативного маршрута.
Мне близок подход: относиться к изменению API так, будто старый клиент появится завтра. Он может быть не внешним подрядчиком, а забытым скриптом внутри компании. Именно поэтому полезно заранее продумывать совместимость, а не проверять её после звонка о сбое. Об этом подробнее — в заметке о безопасном изменении API-контракта.
Кому принадлежит ошибка на границе
«Интеграция не сработала» — это ещё не диагноз. Нужно быстро понять, кто видит проблему первым, где сохранён исходный запрос, как повторить действие без двойного списания и куда передать контекст.
Поэтому контракт данных — лишь половина работы. Вторая половина — договорённость об ошибках. Какие ответы считаются временными? Какие требуют ручного решения? Какой идентификатор связывает попытки в обеих системах?
Без этого одна команда говорит «мы отправили», а другая — «мы не получили». В итоге сотрудник вручную вносит данные, а после восстановления связи получает дубль. Я уже писал, почему интеграцию нельзя считать надёжной, пока не получается проследить одну операцию целиком.
Повторная отправка — нормальная ситуация
Сеть может оборваться после того, как получатель уже обработал запрос. Очередь может доставить сообщение дважды. Оператор может нажать кнопку повторно, не увидев результата. Поэтому полезно сразу решить, что произойдёт при повторе.
Для этого нужен устойчивый идентификатор операции, одинаковый с обеих сторон. Он не обязан быть красивым для человека, но должен позволить ответить: это новая заявка или повтор прежней? Тогда получатель может безопасно вернуть уже известный результат вместо создания второго заказа или повторного списания.
Это не мелкая техническая деталь. Она определяет, можно ли доверять автоматизации в моменты сбоя. Если повтор невозможен без ручного поиска по логам, сотрудник всё равно будет вести резервную таблицу, а интеграция останется лишь ускорителем в хорошие дни.
Контракту нужен владелец
У каждого обмена должен быть человек или команда, которые отвечают не за «всю интеграцию», а за её понятность и развитие. Они знают, какие поля обязательны, как объявляется изменение, где смотреть ошибки и какой срок поддержки у старой версии.
Это не бюрократия ради документа. Без владельца любое изменение выглядит ничьим: одна команда добавила поле, другая не обновилась, а бизнес узнаёт о проблеме от клиента. Даже небольшая страница с версиями, примерами запросов и правилами ошибок может снять большую часть такой неопределённости.
Когда ошибка всё же появляется, важно не бросать её через стену словами «у нас всё работает». Владелец должен помочь собрать одну историю операции: момент создания, идентификатор, попытки отправки, ответ получателя и текущее состояние. Такой путь обычно быстрее приводит к причине, чем обмен скриншотами.
Признаки слишком широкой интеграции
- Партнёр читает таблицы или технические представления напрямую.
- В контракте есть поля, смысл которых никто не может объяснить бизнес-языком.
- Любое изменение требует общей ночной установки нескольких систем.
- Ошибку невозможно связать с конкретной бизнес-операцией.
- Команда боится удалить старый флаг, потому что «вдруг кто-то использует».
Это не повод переписывать всё за один раз. Чаще разумнее взять самый болезненный поток — заказы, оплаты, остатки — и постепенно вынести для него явный договор. Уже один такой контур показывает, где лежат неявные зависимости.
Практический первый шаг
Выберите одну операцию, которая проходит через две системы. Нарисуйте её простыми словами: где она начинается, какое событие передаётся, что получает вторая сторона, что происходит при повторной отправке и кто разбирает отклонение. Затем вычеркните из обмена всё, что не нужно для этого решения.
Иногда после такого упражнения становится видно, что интеграция тащит за собой не данные, а чужую внутреннюю логику. Вот её и стоит оставить владельцу. Партнёру нужен устойчивый договор, а не доступ к вашему черновику устройства системы.
Обсудим?