TOML против YAML против JSON — Форматы конфигурации, отсортированные по степени их раздражения

Обновлено

Каждый формат конфигурации в конечном итоге обманет вас. YAML с проблемами отступов и незаметным преобразованием логических значений, JSON с его политикой отсутствия комментариев, TOML с моментом «подождите, что за синтаксис?». Ниже приведена реальная оценка затрат, связанных с каждым из них — и в каких случаях следует выбирать каждый из них.

TOML против YAML против JSON — Форматы конфигурации, отсортированные по степени раздражения, 1
Реклама · УДАЛИТЬ?

Каждый проект в конечном итоге заставляет выбрать формат конфигурации. YAML присутствует повсюду. JSON старше некоторых из ваших коллег. TOML появился недавно, поднимая руку и говоря: «на самом деле, я был создан именно для этого». Все три формата в конечном итоге обманут вас. Обманы просто различаются.

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

Та же конфигурация, три способа

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

ТОМЛ

# App configuration
[app]
name = "my-app"
port = 3000
debug = false
version = "1.2.3"
allowed_origins = ["https://example.com", "https://api.example.com"]

[database]
host = "localhost"
port = 5432
name = "mydb"

ЯМЛ

# App configuration
app:
  name: my-app
  port: 3000
  debug: false
  version: "1.2.3"
  allowed_origins:
    - https://example.com
    - https://api.example.com

database:
  host: localhost
  port: 5432
  name: mydb

JSON

{
  "app": {
    "name": "my-app",
    "port": 3000,
    "debug": false,
    "version": "1.2.3",
    "allowed_origins": [
      "https://example.com",
      "https://api.example.com"
    ]
  },
  "database": {
    "host": "localhost",
    "port": 5432,
    "name": "mydb"
  }
}

На первый взгляд

ОсобенностьТОМЛЯМЛJSON
Комментарии✅ Да✅ Да❌ Нет
Автоматическое определение типаЯвное указаниеАгрессивное (часто ошибочное)Явное указание
Массивы= ["a", "b"]- item или встроенные["a", "b"]
Завершающие запятыеН/ДН/Д❌ Недопустимо
Глубоко вложенные конфигурацииБыстро становится громоздкимЧитаемо, хотя и не идеальноГромоздко, но однозначно
Стабильность спецификацииTOML 1.0 (2021, стабильная версия)Разногласия между версиями 1.1 и 1.2 парсеровСтабильная
Поддержка значения null❌ Нет типа null✅ Да (~ или null)✅ Да (null)
Общественное использованиеCargo.toml, pyproject.tomlGitHub Actions, k8s, Dockerpackage.json, tsconfig.json

YAML: Наиболее читаемый до тех пор, пока это не перестанет быть таковым

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

Проблема Норвегии

В YAML 1.1 — которая по-прежнему является стандартом большинства парсеров — эти значения являются логическими значениями: y, n, yes, no, on, off, true, false. Так country: NO парсится как country: false. Это и есть реальная причина, почему это называется проблемой Норвегии — международный код страны Норвегии — NO. PyYAML это исправил в версии 6.0 (выпущена в 2022 году). SnakeYAML (используется в большом количестве инструментов на языке Java) до сих пор не полностью решил эту проблему. Проверьте свой парсер перед использованием чистых значений в конфигурации. no или yes в значениях конфигурации.

Автоматическое определение типа, которое ошибается

Неуказанное значение в YAML подвергается преобразованию типов. port: 8080 становится целым числом. version: 1.10 становится вещественным числом 1.1 — математически равное, но семантически неверное. Забудьте обозначить строку версии в кавычках и вы потратите десять минут, размышляя, почему ваше приложение считает, что оно работает на версии v1.1 вместо v1.10. Решение скучное: обозначайте всё, что должно остаться строкой. Но YAML не заставляет вас это делать, поэтому он не делает этого.

Отступы имеют значимое значение

Табуляция запрещена в YAML — не рекомендуется, запрещена. Если в файле смешаны отступы из двух пробелов и четырёх пробелов, вы получите ошибку парсинга, которая часто указывает на неправильную строку. GitHub Actions здесь является наиболее острым примером: неверно отформатированный блок вызывает ошибку на уровне выполнения, а не на уровне парсинга, потому что запускающие среды проверяют только синтаксис, а не структуру шагов. Вы получите сообщение «непредвиденное значение» от задачи CI без указания на конкретный шаг, и вы потратите 20 минут на добавление отладочной информации, прежде чем осознать, что проблема была в двух пробелах, где требовалось четыре. run: Если ваш YAML стал хаотичным из-за непостоянства отступов, то

форматировщик YAML нормализует его перед тем, как вы начнёте отладку. TOML: Формат, который действительно продумал конфигурацию

Том Пренстон-Вернер (создатель GitHub) создал TOML, потому что он устал писать конфигурации в стиле INI с непредсказуемым поведением парсинга и конфигурации на YAML, которая его удивляла. TOML 1.0 был выпущен в январе 2021 года после длительных доработок. Сегодня он является стандартом для проектов на Rust (

), пакетной системы на Python (Cargo.toml) и сайтов Hugo. Спецификация стабильна, парсеры согласны, и система типов работает так, как вы ожидаете.pyproject.tomlЧто он делает правильно

Отсутствие неожиданных преобразований типов.

  • всегда является строкой. version = "1.10" всегда является целым числом. То, что вы пишете, — то, что вы получаете. port = 3000 Комментарии работают точно так, как вы ожидаете (
  • до конца строки), в отличие от JSON.# Простые и умеренно вложенные конфигурации действительно читаемы, в отличие от глубоко вложенных JSON.
  • Синтаксис массива таблиц

Основная проблема TOML — это синтаксис массива таблиц. Если вы хотите массив объектов — например, несколько баз данных — запись выглядит так:

секция — это один элемент в

[[databases]]
name = "primary"
host = "db1.example.com"

[[databases]]
name = "replica"
host = "db2.example.com"

Каждая [[double bracket]] массиве. Это работает. Оно однозначно. Но каждый раз, когда кто-то открывает TOML-файл впервые, он спрашивает: «это INI?» — потому что это выглядит как INI. Эта неизвестность имеет реальные последствия, когда вы привлекаете новых участников, которые никогда не видели TOML. databases TOML также не имеет типа — намеренно. Если ваша схема использует null для обозначения «ключ присутствует, но явно не установлен», вам нужно моделировать это иначе (удалить ключ полностью или использовать специальный значимый элемент). И глубоко вложенные конфигурации быстро становятся громоздкими: TOML не имеет системы анонимных ссылок YAML для повторного использования поддеревьев, поэтому при наличии повторяющейся структуры приходится много копировать.

Форматировщик TOML null полезен, когда вы пытаетесь улучшить TOML-файл, который рос органически со временем.

The JSON: Один из тех, кого вы знаете JSON был разработан для обмена данными между машинами — машины говорят друг с другом — а не для людей, которые пишут конфигурационные файлы. Он стал форматом конфигурации, потому что в каждой языковой среде уже существовали парсеры JSON, и эта удобность победила. Теперь у нас есть package.json, tsconfig.json, .eslintrc.json и примерно 40 других JSON-конфигураций в каждом проекте на JavaScript, которые вы редактируете вручную.

Отсутствие комментариев. Продолжает.

Дуглас Крокафорд удалил комментарии из JSON намеренно в 2012 году — он опасался, что разработчики будут использовать их как директивы парсинга (похоже на условные комментарии в IE). Интернет каждый день жалуется на это. Используемые обходные пути:

JSONC

— JSON с комментариями. VS Code использует его для

  • . Не поддерживается стандартными парсерами JSON. Нестандартный. JSON5 settings.json и launch.json— добавляет комментарии, конечные запятые, неуказанные ключи, многострочные строки. Имеет спецификацию и отдельный парсер. Babel использует его для конфигураций. Продолжает не быть стандартным JSON.
  • ключ — строковое поле, которое хранит текст комментария. Работает. Выглядит странно. Входит в вашу модель данных.
  • А "_comment" Также запрещено. Добавьте запятую после последнего элемента в массиве или объекте и вызовет

Запятые в конце строк

— сообщит вам о проблеме, но не укажет, где находится лишняя запятая. Это является самым распространённым ошибкой парсинга в ручно созданных конфигурационных файлах, и она возникает потому, что все современные языки (массивы на JavaScript, списки на Python, перечисления на Rust) позволяют завершать массивы и объекты запятой, а люди пишут JSON вручную с такими же привычками. JSON.parse Что JSON делает правильно SyntaxError: Unexpected token } Система типов однозначна и универсальна. Все парсеры JSON в каждом языке согласны в том, что

означает. JSON Schema является наиболее зрелым вариантом проверки конфигурации среди трёх — VS Code использует его для проверки tsconfig.json и package.json в режиме редактирования с подсветкой ошибок. Когда инструменты создают ваш JSON (webpack, tsc, npm), вы не беспокоитесь о читаемости — это и есть задача

. true, 1, "1"и null Вывод: выбирайте в зависимости от контекста, а не по предпочтению Форматировщик JSON Используйте JSON

при генерации или использовании инструментами (package.json, tsconfig, конфигурации AWS, ответы GitHub API), или когда вам нужно проверка с помощью JSON Schema. Не боритесь с этим, не пишите его вручную больше, чем необходимо. Отсутствие комментариев неприятно, но универсальность и поддержка инструментов трудно оспорить.

Используйте YAML при том, что конфигурация в основном создается людьми и является относительно плоской — GitHub Actions, файлы Docker Compose, манифесты Kubernetes. Обозначайте всё, что может быть ошибочно интерпретировано как логическое значение (строки версий, коды стран, что начинается с цифры). Запускайте линтер. Никогда не используйте табуляцию. Рассматривайте автоматическое определение типов как баг, а не как функцию.

при том, что вы контролируете выбор формата и хотите избежать неожиданных преобразований типов. Это самый честный из трёх форматов относительно того, что он представляет собой. Если вы начинаете новый проект и ни один из инструментов не требует определённого формата, TOML — это наименее вероятный вариант, который вас удивит через шесть месяцев. Непонимание — это временная стоимость; чёткость — это постоянная. когда настройка в основном создается человеком и имеет относительно плоскую структуру — файлы GitHub Actions, файлы Docker Compose, манифесты Kubernetes. Цитируйте любые значения, которые могут быть ошибочно интерпретированы как логическое значение или число (строки версий, коды стран, любые значения, начинающиеся с цифры). Запустите линтер. Никогда не используйте табуляции. Рассматривайте инференс типов как баг, а не как функцию.

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

Хотите убрать рекламу? Откажитесь от рекламы сегодня

Установите наши расширения

Добавьте инструменты ввода-вывода в свой любимый браузер для мгновенного доступа и более быстрого поиска

в Расширение Chrome в Расширение края в Расширение Firefox в Расширение Opera

Табло результатов прибыло!

Табло результатов — это интересный способ следить за вашими играми, все данные хранятся в вашем браузере. Скоро появятся новые функции!

Реклама · УДАЛИТЬ?
Реклама · УДАЛИТЬ?
Реклама · УДАЛИТЬ?

новости с техническими моментами

Примите участие

Помогите нам продолжать предоставлять ценные бесплатные инструменты

Купи мне кофе
Реклама · УДАЛИТЬ?