Fastway
Voltar ao blog

JSON ou YAML: quando cada um faz sentido de verdade

Rodrigo Krohling
·7 min de leitura

Discussões sobre JSON e YAML costumam terminar onde deveriam começar: na constatação de que os dois codificam a mesma coisa. Objetos, arrays, strings, números, booleanos, null. Tudo que você expressa em um, expressa no outro, e a conversão é mecânica o bastante para um conversor numa aba do navegador resolver sem te fazer uma única pergunta.

Então a escolha não é sobre capacidade. É sobre quem vai digitar no arquivo, quem vai lê-lo sob pressão e o que acontece quando um dos dois erra.

A mesma configuração, dos dois jeitos

Uma definição de serviço em JSON:

{
  "name": "billing-worker",
  "replicas": 3,
  "env": [
    { "name": "QUEUE_URL", "value": "https://queue.internal/billing" },
    { "name": "LOG_LEVEL", "value": "info" }
  ],
  "retry": { "attempts": 5, "backoff": "exponential" }
}

E em YAML:

name: billing-worker
replicas: 3
env:
  - name: QUEUE_URL
    value: https://queue.internal/billing
  - name: LOG_LEVEL
    value: info
retry:
  attempts: 5
  backoff: exponential

O YAML é mais curto e o aninhamento é carregado pela indentação em vez da pontuação. Para um arquivo que um humano edita toda semana, isso é um ganho ergonômico real. E é exatamente de onde vêm os modos de falha do YAML.

O que o YAML te dá

Comentários. Esse é o grande, e não está nem perto. JSON não tem sintaxe de comentário, e é por isso que todo formato de configuração baseado em JSON acaba ganhando uma extensão fora do padrão ou a convenção de despejar explicações numa chave _note. Se um humano mantém o arquivo, ele precisa de algum lugar para anotar por que replicas é 3 e não 5.

Strings de várias linhas. Um script de shell ou um certificado embutido em JSON vira uma linha só, cravejada de \n. Os blocos escalares do YAML mantêm legível:

startup: |
  set -euo pipefail
  ./migrate --wait
  exec ./server

Menos ruído visual. Sem chaves, sem aspas na maioria dos valores, sem o campo minado da vírgula sobrando. Para configuração muito aninhada, isso reduz o esforço de leitura de verdade.

O que o YAML te custa

A especificação é enorme. A gramática do JSON cabe num cartão de visita. O YAML 1.2 é um documento com âncoras, aliases, tags, múltiplos documentos por stream e vários modos de citação de string com regras de escape diferentes. Quase ninguém usa mais que um décimo disso — o que significa que quase ninguém reconhece os outros nove décimos quando aparecem num arquivo.

A inferência de tipo surpreende. O clássico é o problema da Noruega: NO é interpretado como o booleano falso por parsers YAML 1.1, então uma lista de códigos de país silenciosamente ganha um false. Números de versão são o outro clássico — version: 1.10 vira o número 1.1, porque zero à direita não existe em float.

A indentação é estrutural. Um tab onde se esperava espaços, ou dois espaços onde se esperavam quatro, muda o formato dos seus dados em vez de falhar alto. As chaves do JSON são feias precisamente porque são explícitas.

Âncoras são uma arma apontada para o pé em escala. &defaults e <<: *defaults parecem elegantes num tutorial e ficam muito difíceis de rastrear num arquivo de 400 linhas onde a âncora está definida lá embaixo.

O que o JSON te dá

Uma única leitura óbvia. Não há inferência. "1.10" é string, 1.10 é número, no é inválido a menos que entre aspas. Quando algo está errado, o parser para e diz onde — e é por isso que um formatador que valida enquanto indenta é ferramenta suficiente para a maioria dos problemas com JSON.

É o formato de transporte. Toda API HTTP, todo fetch de navegador, todo pipeline de log já fala JSON. Serializar para YAML para mandar pela rede é trabalho que você faz sem benefício para ninguém.

Máquinas escrevem bem. Arquivo gerado é o território natural do JSON. Ninguém precisa de comentário num lockfile.

A regra que se sustenta

Pergunte quem digita no arquivo.

  • Humanos escrevem, máquinas leem → YAML. Manifestos do Kubernetes, pipelines de CI, configuração de aplicação. Os comentários e as strings multilinha pagam pelas manias do parser.
  • Máquinas escrevem, máquinas leem → JSON. Payloads de API, lockfiles, artefatos de build. Ninguém lê à mão, então concisão e comentários não compram nada e previsibilidade compra tudo.
  • Máquinas escrevem, humanos leem → JSON, formatado. Uma resposta de API minificada é ilegível, mas isso é problema de exibição, não de formato.
  • Humanos escrevem, humanos leem, e não pode quebrar → JSON com schema, ou uma linguagem de programação de verdade. Se um arquivo de configuração é crítico a ponto de uma coerção silenciosa de tipo virar incidente, não o entregue a um formato que adivinha.

Dois hábitos que valem a pena

Coloque entre aspas qualquer coisa que possa ser mal lida. Códigos de país, strings de versão, portas que você quer como texto, qualquer coisa começando com zero. version: "1.10" custa dois caracteres e elimina uma classe de bug.

Valide antes do commit, não depois do deploy. O modo de falha é o mesmo nos dois formatos: o arquivo parece certo, o parser discorda, e você descobre num pipeline. Passe o arquivo por um validador — se ele faz a ida e volta para JSON com os valores que você espera, os tipos são o que você pensa. É uma checagem de cinco segundos que pega o problema da Noruega e o do número de versão de uma vez.

Os formatos não são rivais. São os mesmos dados vestidos para ocasiões diferentes, e o único erro real é escolher a roupa errada para a ocasião.