Форматы обмена
Мелочи, на которых горят реальные интеграции: часовые пояса, деньги, кодировки, отсутствующие значения. Спрашивают именно про них, потому что тут сразу видно, чинил ли человек прод или проектировал на бумаге.
Стержень: формат должен быть однозначным для машины и устойчивым к расширению. Три классические мины - дата, деньги и разница между «пусто» и «не передано».
// Формулировки: «в каком виде передашь дату?», «почему не 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, остальные разбираются в тренажёре.
- Почему денежные суммы не передают числом с плавающей точкой?A)Такие числа занимают больше местаB)Они не поддерживаются в JSONC)Двоичное представление даёт погрешностьD)Их труднее отсортировать на приёмнике
показать ответ и разбор
+C)Двоичное представление даёт погрешность// разбор: Дробные значения вроде 0.1 не имеют точного двоичного представления, поэтому суммирование накапливает ошибку — на больших объёмах итог расходится с бухгалтерией на копейки. Передают либо целое число минимальных единиц (копеек), либо строку с фиксированной точностью, а считают в десятичном типе.
- Чем отличается null от отсутствующего поля в JSON?A)null — известное пустое, отсутствие — неизвестноB)null запрещён стандартом форматаC)Отсутствие поля означает ошибку передачиD)Ничем, это одно и то же
показать ответ и разбор
+A)null — известное пустое, отсутствие — неизвестно// разбор: Различие критично для частичного обновления: при PATCH null обычно значит «очистить поле», а отсутствие ключа — «не трогать». Если контракт этого не проговаривает, каждая сторона трактует по-своему, и данные затираются молча. Правило трактовки надо фиксировать в спецификации явно.
- Партнёр присылает файл в кодировке windows-1251, а система ждёт UTF-8. Где это проявится?A)В размере файла на дискеB)В искажении русских буквC)В нарушении порядка строкD)В потере последней строки файла
показать ответ и разбор
+B)В искажении русских букв// разбор: Байты однобайтовой кодировки при чтении как UTF-8 дают либо нечитаемые последовательности, либо ошибку разбора. Латиница и цифры при этом выглядят нормально, поэтому проблему часто замечают поздно — на записях с русскими названиями. Кодировку обмена фиксируют в соглашении наравне с форматом.
- Зачем в контракте описывать схему сообщения, а не только пример?A)Схема задаёт обязательность и границы значенийB)Схема занимает меньше местаC)Схема выглядит профессиональнее примераD)Схема требуется стандартом обмена
показать ответ и разбор
+A)Схема задаёт обязательность и границы значений// разбор: Пример показывает один случай, схема задаёт правила для всех: какие поля обязательны, какого типа, какой длины, из какого перечня значений. По схеме работает автоматическая валидация на входе — сообщение отклоняется до бизнес-логики, и до неё не доезжают заведомо кривые данные.
- Партнёр добавил в JSON новое поле, не предупредив. Почему у одних потребителей всё работает, а у других падает?A)Зависит от версии протокола HTTPB)Зависит от строгости разбора клиентомC)Зависит от размера сообщенияD)Зависит от порядка полей в объекте
показать ответ и разбор
+B)Зависит от строгости разбора клиентом// разбор: Клиент, игнорирующий незнакомые поля, переживёт расширение спокойно. Клиент со строгой проверкой, запрещающей лишние поля, немедленно отклонит сообщение. Отсюда правило устойчивых интеграций: будь строг к тому, что отправляешь, и терпим к тому, что получаешь.
дальше
Теорию прочитали. Навык ставится повторением
В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.