Se hai mai gestito un cluster Kubernetes, configurato un workflow GitHub Actions, o scritto un file Docker Compose, hai già scritto YAML — probabilmente molto. YAML è il formato di configurazione che alimenta la maggior parte degli strumenti DevOps moderni. Ma nonostante sia ovunque, è un formato che continua a sorprendere. Ho passato più di qualche notte a debuggare errori di indentazione YAML con un deploy bloccato. Assicuriamoci che non ti capiti.

YAML sta per YAML Ain't Markup Language — sì, è un acronimo ricorsivo. In origine era "Yet Another Markup Language" ma è stato rinominato per sottolineare che è un formato di serializzazione dati, non un linguaggio di markup per documenti. La specifica YAML 1.2 è lo standard attuale, anche se molti strumenti implementano ancora YAML 1.1, che presenta alcune differenze genuinamente pericolose che affronteremo qui sotto.

Le basi: la sintassi YAML a colpo d'occhio

YAML usa l'indentazione (solo spazi — mai tabulazioni) per esprimere la struttura. Un documento YAML è una mapping (coppie chiave-valore), una sequence (una lista) o uno scalar (un singolo valore). Ecco un config in stile Kubernetes che copre tutti gli elementi essenziali:

yaml
# This is a comment — YAML supports them, JSON does not
app:
  name: payment-service
  version: "2.1.0"         # quoted to keep it a string
  port: 8080
  debug: false
  timeout: 30.5
  tags:
    - payments
    - backend
    - critical
  database:
    host: postgres.internal
    port: 5432
    ssl: true
    password: null          # explicitly no value

Niente parentesi graffe, niente virgolette sulla maggior parte delle stringhe, niente virgole. Per un file che gli umani modificano ogni giorno, quella chiarezza fa la differenza. Ma YAML paga quella leggibilità con la complessità — c'è molto che succede sotto la superficie.

Tipi scalari: stringhe, numeri, booleani, null

YAML deduce i tipi dall'aspetto del valore. È comodo nella maggior parte dei casi e silenziosamente catastrofico in alcuni casi specifici.

yaml
# Strings — quotes are optional unless value is ambiguous
name: Alice
greeting: "Hello, world"
message: 'single quotes work too'
path: /usr/local/bin           # unquoted — still a string

# Numbers
integer: 42
negative: -7
float: 3.14159
scientific: 6.022e23

# Booleans
ssl_enabled: true
verbose: false

# Null
api_key: null
legacy_field: ~               # tilde is also null in YAML
Il Problema della Norvegia: In YAML 1.1 (usato da PyYAML e molti strumenti meno recenti), i valori non quotati yes, no, on, off, true, false, y, n, Y, N — e le loro varianti in maiuscolo — vengono tutti interpretati come booleani. Questo significa che il codice ISO del paese NO (Norvegia) diventa false booleano. YAML 1.2 ha risolto questo. Cita sempre le stringhe che assomigliano a booleani. Vedi la voce Wikipedia sul Problema della Norvegia per la storia completa.
yaml
# YAML 1.1 implicit type coercion — these silently become booleans:
country: NO       # → false  (Norway Problem!)
enabled: yes      # → true
toggle: on        # → true

# The fix: always quote when there's any ambiguity
country: "NO"
enabled: "yes"
version: "1.0"    # also quote version numbers — 1.0 would be a float

Sequences: liste in YAML

Le liste usano un prefisso trattino-spazio. Ogni elemento può essere uno scalar, una mapping o un'altra sequence:

yaml
# Simple list
languages:
  - Python
  - Go
  - TypeScript

# List of objects (common in Kubernetes)
containers:
  - name: api
    image: my-api:latest
    port: 8080
  - name: sidecar
    image: envoy:v1.28
    port: 9901

# Inline flow style (valid YAML, less readable)
tags: [payments, backend, v2]

Stringhe multiriga: blocco letterale vs. ripiegato

Qui YAML supera JSON per i file di configurazione. Due operatori speciali gestiscono elegantemente le stringhe multiriga:

yaml
# Literal block scalar (|) — preserves newlines exactly
startup_script: |
  #!/bin/bash
  set -e
  echo "Starting service..."
  npm start

# Folded scalar (>) — folds newlines into spaces (good for long descriptions)
description: >
  This service handles payment processing
  for all regions. It connects to Stripe
  and falls back to PayPal.
# Result: "This service handles payment processing for all regions. It connects to Stripe and falls back to PayPal."

# Chomp modifiers
keep_trailing: |+
  line one
  line two

strip_trailing: |-
  line one
  line two

L'operatore | è quello che rende leggibili gli script run: multiriga di GitHub Actions. Il cheat sheet yaml-multiline.info è il modo più rapido per ricordare quale modificatore chomp fa cosa. Senza questi blocchi scalari, dovresti scrivere newline escaped in una singola stringa — esattamente quello che JSON ti costringe a fare.

Tabulazioni vs spazi — la regola fondamentale

YAML vieta le tabulazioni per l'indentazione. Completamente. Se il tuo editor inserisce un carattere tabulazione nell'indentazione di un file YAML, il file o non verrà analizzato o — peggio — verrà analizzato in modo errato. Configura il tuo editor per usare gli spazi per i file .yml e .yaml. Due spazi è la convenzione quasi universale.

Questa è la causa numero 1 degli errori YAML criptici. Una tabulazione sembra identica agli spazi nella maggior parte degli editor. Abilita "mostra caratteri di spazio" nel tuo editor quando fai debug di YAML, oppure incolla il tuo file nel YAML Validator per ottenere un messaggio di errore chiaro che indica la riga esatta.

Esempio reale: workflow GitHub Actions

Ecco un frammento reale di workflow GitHub Actions. Nota come il blocco run: multiriga usa il blocco scalare letterale e come l'indentazione determina la struttura:

yaml
name: CI

on:
  push:
    branches: [main, develop]
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "20"
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: |
          npm run lint
          npm run test -- --coverage
          npm run build

Esempio reale: manifest Kubernetes Deployment

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: payment-api
  namespace: production
  labels:
    app: payment-api
    version: "2.1.0"
spec:
  replicas: 3
  selector:
    matchLabels:
      app: payment-api
  template:
    metadata:
      labels:
        app: payment-api
    spec:
      containers:
        - name: api
          image: payment-api:2.1.0
          ports:
            - containerPort: 8080
          env:
            - name: NODE_ENV
              value: production
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: db-secret
                  key: password
          resources:
            requests:
              memory: "128Mi"
              cpu: "100m"
            limits:
              memory: "512Mi"
              cpu: "500m"

Analizzare YAML in Python e JavaScript

In Python, la libreria PyYAML è la scelta standard. Usa sempre safe_load(), non load() — la versione non sicura può eseguire codice Python arbitrario da un file YAML:

python
import yaml

# Reading a YAML config file
with open('config.yaml', 'r') as f:
    config = yaml.safe_load(f)

print(config['app']['name'])        # payment-service
print(config['app']['port'])        # 8080 (integer, not string)
print(config['app']['tags'])        # ['payments', 'backend', 'critical']

# Writing Python data to YAML
data = {
    'service': 'auth-api',
    'replicas': 2,
    'endpoints': ['/login', '/logout', '/refresh']
}
with open('output.yaml', 'w') as f:
    yaml.dump(data, f, default_flow_style=False)

In JavaScript/Node.js, js-yaml è la libreria più utilizzata:

js
import yaml from 'js-yaml';
import fs from 'fs';

// Parse YAML string
const raw = fs.readFileSync('config.yaml', 'utf8');
const config = yaml.load(raw);

console.log(config.app.name);     // payment-service
console.log(config.app.tags);     // ['payments', 'backend', 'critical']

// Dump an object to YAML string
const output = yaml.dump({
  name: 'my-service',
  port: 3000,
  tags: ['api', 'public']
});
console.log(output);

Conclusione

La sintassi basata sull'indentazione di YAML, il supporto ai commenti e le leggibili stringhe multiriga lo rendono la scelta giusta per i file di configurazione che gli umani scrivono e mantengono. Ma porta con sé alcune trappole reali: il Problema della Norvegia, la confusione tabulazioni/spazi e la coercizione implicita dei tipi dei parser YAML 1.1. Conosci le regole, cita tutto ciò che è ambiguo, configura il tuo editor per mostrare gli spazi, e usa un YAML Formatter per mantenere i file coerenti. YAML è uno strumento potente una volta che capisci dove morde.