сеньорчикОткрыть в Telegram
← вся теориятеория к собесу · Интеграции

Форматы обмена

Форматы обмена

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

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

// Формулировки: «в каком виде передашь дату?», «почему не float для суммы?», «партнёр добавил поле - почему у нас упало?»

Дата и деньги

Дату передают в формате ISO 8601 с явным часовым поясом. У него два достоинства: он однозначен и сортируется как обычная строка, потому что старшие разряды идут первыми.

Что происходит без пояса, видно на одном примере. Клиент оформил заказ в 23:30 по Москве, в обмен ушла строка без зоны. Партнёр в другом часовом поясе прочитал её как своё местное время - и заказ уехал в отчёт другого дня. Расхождение всплывает не сразу, а на сверке дневных отчётов, и искать его будут неделю.

Деньги не передают числом с плавающей точкой, и причина не в педантизме, а в двоичной арифметике: 0.1 не имеет точного представления в двоичной системе, как 1/3 не имеет точного в десятичной. Поэтому 0.1 плюс 0.2 даёт не 0.3, а 0.30000000000000004. На одной операции незаметно, на потоке погрешность накапливается, итог расходится с бухгалтерией на копейки, и это худший вид дефекта - совершенно тихий.

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

Пустое значение против отсутствия поля

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

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

Правило трактовки фиксируют в спецификации явно, отдельным предложением, а не подразумевают. Одна строка текста экономит инцидент.

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

Устойчивость к изменениям

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

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

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

// Человекочитаемый номер при этом никуда не девается, но живёт отдельным атрибутом - для людей, для поиска в поддержке, для печати на документе. Машина связывает по уникальному идентификатору, человек ищет по номеру.

Как отвечать: «Почему сумму нельзя передавать числом с плавающей точкой?»

Потому что дробные значения вроде 0.1 не имеют точного двоичного представления, и арифметика перестаёт быть точной: 0.1 плюс 0.2 в таком типе даёт 0.30000000000000004, а не 0.3. На одной операции это незаметно, на потоке погрешность накапливается, и итог расходится с бухгалтерией на копейки. Дефект при этом самый неприятный из возможных - тихий, всплывающий на сверке через месяцы, когда концов уже не найти. Передаю либо целым числом минимальных единиц, то есть в копейках, либо строкой с фиксированной точностью, а считаю в десятичном типе, где такой проблемы нет. И обязательно рядом валюту: сумма без валюты - неполный факт, особенно если система однажды выйдет за пределы одной страны.

Кандидат объясняет механизм ошибки конкретным числом, называет момент её обнаружения и даёт два стандартных решения. Три слоя вместо привычного «так принято».

На чём валятся

  • − Передают деньги числом с плавающей точкой и получают тихое расхождение на сверке.
  • − Передают время без часового пояса: заказ уезжает в отчёт соседнего дня.
  • − Не описывают разницу между пустым значением и отсутствием поля при частичном обновлении.
  • − Забывают зафиксировать кодировку файлового обмена и портят кириллицу.
  • − Берут сквозную нумерацию как идентификатор обмена и ломают связи при объединении контуров.

Проверьте себя

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

  1. #ana_int_formats1 / 5
    Почему денежные суммы не передают числом с плавающей точкой?
    A)Такие числа занимают больше места
    B)Они не поддерживаются в JSON
    C)Двоичное представление даёт погрешность
    D)Их труднее отсортировать на приёмнике
    показать ответ и разбор
    +C)Двоичное представление даёт погрешность

    // разбор: Дробные значения вроде 0.1 не имеют точного двоичного представления, поэтому суммирование накапливает ошибку — на больших объёмах итог расходится с бухгалтерией на копейки. Передают либо целое число минимальных единиц (копеек), либо строку с фиксированной точностью, а считают в десятичном типе.

  2. #ana_int_formats2 / 5
    Чем отличается null от отсутствующего поля в JSON?
    A)null — известное пустое, отсутствие — неизвестно
    B)null запрещён стандартом формата
    C)Отсутствие поля означает ошибку передачи
    D)Ничем, это одно и то же
    показать ответ и разбор
    +A)null — известное пустое, отсутствие — неизвестно

    // разбор: Различие критично для частичного обновления: при PATCH null обычно значит «очистить поле», а отсутствие ключа — «не трогать». Если контракт этого не проговаривает, каждая сторона трактует по-своему, и данные затираются молча. Правило трактовки надо фиксировать в спецификации явно.

  3. #ana_int_formats3 / 5
    Партнёр присылает файл в кодировке windows-1251, а система ждёт UTF-8. Где это проявится?
    A)В размере файла на диске
    B)В искажении русских букв
    C)В нарушении порядка строк
    D)В потере последней строки файла
    показать ответ и разбор
    +B)В искажении русских букв

    // разбор: Байты однобайтовой кодировки при чтении как UTF-8 дают либо нечитаемые последовательности, либо ошибку разбора. Латиница и цифры при этом выглядят нормально, поэтому проблему часто замечают поздно — на записях с русскими названиями. Кодировку обмена фиксируют в соглашении наравне с форматом.

  4. #ana_int_formats4 / 5
    Зачем в контракте описывать схему сообщения, а не только пример?
    A)Схема задаёт обязательность и границы значений
    B)Схема занимает меньше места
    C)Схема выглядит профессиональнее примера
    D)Схема требуется стандартом обмена
    показать ответ и разбор
    +A)Схема задаёт обязательность и границы значений

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

  5. #ana_int_formats5 / 5
    Партнёр добавил в JSON новое поле, не предупредив. Почему у одних потребителей всё работает, а у других падает?
    A)Зависит от версии протокола HTTP
    B)Зависит от строгости разбора клиентом
    C)Зависит от размера сообщения
    D)Зависит от порядка полей в объекте
    показать ответ и разбор
    +B)Зависит от строгости разбора клиентом

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

дальше

Теорию прочитали. Навык ставится повторением

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