Test, contracts e fiducia nei modelli
Test, contracts e fiducia nei modelli. Lezione su come garantire la qualità dei dati con dbt.
Cosa imparerai
- Comprendere il problema analitico e il contesto decisionale
- Applicare esempi, metriche e controlli a casi reali
Collegamenti
Test, contracts e fiducia nei modelli
Una metrica cambia perché una sorgente ha rinominato un campo, non perché il business è cambiato. Test, contracts e fiducia nei modelli mostra come proteggere il warehouse con test, aspettative e contratti che rendono visibili rotture e assunzioni.
Una scena da cui partire
Leggi la lezione come costruzione della fiducia tecnica. Un test utile non dimostra che tutto va bene: intercetta il tipo di errore che danneggerebbe una decisione o romperebbe un contratto a valle.
- Contesto: Quale vincolo tecnico decide il disegno?
- Metodo: Quale controllo ti direbbe che il risultato è affidabile?
- Applicazione: Quale trade-off racconteresti prima di mettere in produzione?
La piramide dei test in dbt
dbt nativamente supporta test generici, test singolari, e test custom. La strategia è stratificata:
| Livello | Tipo di test | Copertura | Impatto del fallimento |
|---|---|---|---|
| 1 — Fondamentali | unique, not_null su primary key | Ogni modello | Blocca la PR |
| 2 — Business | accepted_values, relationships | Ogni colonna critica | Blocca la PR |
| 3 — Volume | Range di row count atteso | Modelli chiave | Warning |
| 4 — Qualità statistica | Media, deviazione standard, distribuzione | Metriche core | Alert |
I test generici (built-in)
I quattro test generici di dbt coprono il 90% dei casi:
models:
- name: mrt_finance__monthly_revenue
columns:
- name: revenue_date
tests:
- not_null
- unique
- name: country
tests:
- not_null
- accepted_values:
values: ['IT', 'FR', 'DE', 'ES', 'UK', 'US']
- name: total_revenue
tests:
- not_null
- name: currency
tests:
- not_null
- relationships:
to: ref('stg_reference__currencies')
field: currency_code
Questi quattro test, applicati automaticamente a ogni modello, bloccano l’80% degli errori di produzione. not_null e unique sulla primary key sono il minimo non negoziabile. accepted_values blocca gli errori di enum (es. un nuovo status non previsto). relationships blocca le violazioni di integrità referenziale.
I test singolari (SQL custom)
Quando la logica è troppo specifica per un test generico, scrivi un test singolare: un file SQL che deve restituire zero righe per passare.
-- tests/assert_positive_revenue.sql
SELECT revenue_date, total_revenue
FROM {{ ref('mrt_finance__monthly_revenue') }}
WHERE total_revenue < 0
Se la query restituisce righe, il test fallisce e blocca il build. I test singolari sono potenti perché permettono qualsiasi logica SQL.
I test custom (generic tests riusabili)
Quando un pattern di test si ripete, si crea un test custom in Jinja:
-- tests/generic/test_greater_than.sql
{% test greater_than(model, column_name, threshold) %}
SELECT {{ column_name }}
FROM {{ model }}
WHERE {{ column_name }} <= {{ threshold }}
{% endtest %}
Utilizzo nel file YAML:
columns:
- name: total_revenue
tests:
- greater_than:
threshold: 0
I test custom sono il ponte verso una strategia di testing matura. Il team di dati di HubSpot ha oltre 40 test custom pubblici nel loro repository open source dbt.
Data contracts: il livello successivo
Un data contract è un accordo formale tra il produttore del dato (es. il team di engineering che gestisce l’API di Stripe) e il consumatore (es. il modello dbt che importa i dati Stripe). Definisce:
- Schema (quali colonne, quali tipi)
- Semantica (cosa significa ogni colonna)
- Garanzie di qualità (quali test devono passare)
- SLA di freschezza (entro quanto tempo il dato è disponibile)
dbt supporta i contratti nativamente dalla versione 1.5 con i model contracts:
models:
- name: stg_stripe__payments
config:
contract:
enforced: true
columns:
- name: payment_id
data_type: string
constraints:
- type: not_null
- type: primary_key
- name: amount_eur
data_type: numeric(10,2)
constraints:
- type: not_null
- name: payment_date
data_type: date
- name: status
data_type: string
constraints:
- type: not_null
Con contract.enforced = true, dbt verifica che ogni riga prodotta dal modello rispetti i tipi e i vincoli dichiarati. Se una colonna è definita come not_null e il modello produce NULL, il build fallisce. Questo sposta la validazione dal “speriamo che il dato sia corretto” al “il dato è garantito corretto o il build fallisce”.
Caso reale: il disastro dei dati senza contratti
Nel 2021, un e-commerce europeo usava dbt senza contratti. Un giorno, l’API di un payment provider cambiò il tipo di amount da stringa (“99.99”) a numero (99.99) in un aggiornamento minore. Il modello staging faceva CAST(amount AS NUMERIC), che funzionava con le stringhe ma troncava i decimali del numero. Il revenue mostrato in dashboard calò del 31%.
Il team finance passò 3 giorni a cercare l’errore. La causa fu trovata solo quando qualcuno confrontò manualmente i log del payment provider con i dati del warehouse. Dopo l’incidente, implementarono model contracts su tutti i modelli staging di fonte esterna. Un anno dopo, un cambiamento simile avvenne con un altro provider — il contratto bloccò il build, il team fu avvisato in 5 minuti, e il fix richiese 10 minuti.
Strategia di implementazione progressiva
Non serve testare tutto dal giorno 1. La strategia consigliata (dbt Labs, 2024) è:
-
Settimana 1:
not_null+uniquesu ogni primary key di ogni modello. È il 20% dello sforzo per l’80% del valore. -
Settimana 2:
accepted_valuessu tutte le colonne di status, tipo, categoria.relationshipssu tutte le foreign key dei modelli marts. -
Mese 2: Test singolari per le regole di business critiche (es. “revenue non negativo”, “order_date > customer_signup_date”).
-
Mese 3: Model contracts su tutti i modelli staging di fonti esterne (API, file, database terzi).
-
Quarter 2+: Test custom riusabili per pattern ricorrenti. Test di qualità statistica su metriche core.
A ogni passo, la configurazione CI/CD deve eseguire i test automaticamente e bloccare la PR se falliscono. Senza enforcement CI, i test sono documentazione inutile.
Riferimenti:
- dbt Labs. (2024). “Testing.” dbt Documentation.
- McConaghy, T. & Satterfield, E. (2023). “Model Contracts: Enforcing Data Quality at Build Time.” dbt Developer Blog.
- HubSpot. (2023). “Open Source dbt Packages.” GitHub: HubSpot/dbt-utils.
Controllo di qualità
Prima di usare test, contracts e fiducia nei modelli in una decisione, controlla sempre completezza, duplicati, timezone, definizioni cambiate e segmenti esclusi. Molte analisi apparentemente sofisticate falliscono perché il dato di partenza misura un comportamento diverso da quello che il team crede di osservare.
Interpretazione per segmenti
La media aggregata è solo il punto di partenza. Segmenta per canale, coorte, piano, paese, device e maturità dell’utente. Se due segmenti si muovono in direzioni opposte, la media non rappresenta nessuno dei due e può portare a una decisione sbagliata.
Decisione operativa
Ogni analisi deve terminare con una scelta possibile: continuare, fermare, iterare, investire, rimuovere o approfondire. Se test, contracts e fiducia nei modelli non cambia una decisione, probabilmente manca ancora il collegamento tra metrica e azione.
Problema reale
Nel dominio di analytics engineering, Test, contracts e fiducia nei modelli serve a risolvere questo problema: trasformare dati grezzi in modelli testati, documentati e riusabili dal business. La lezione non va trattata come teoria isolata, ma come un modo per migliorare una scelta concreta con dati, assunzioni esplicite e controlli minimi.
Obiettivo operativo: Comprendere il problema analitico e il contesto decisionale; Applicare esempi, metriche e controlli a casi reali. Se alla fine non sai indicare quale decisione cambia, quale dato osservi e quale errore vuoi evitare, la lezione non è ancora diventata competenza applicata.
Modello concettuale
| Fase | Cosa chiarire | Output |
|---|---|---|
| Domanda | Quale scelta reale deve migliorare? | Decisione da prendere |
| Misura | Quale segnale osservabile rappresenta il problema? | Metrica o dato sorgente |
| Controllo | Quale baseline rende il risultato interpretabile? | Confronto credibile |
| Azione | Che cosa cambia dopo l’analisi? | Prossimo passo operativo |
Il modello concettuale è intenzionalmente semplice: decisione, dato, controllo, azione. Ogni approfondimento tecnico deve rafforzare almeno uno di questi quattro punti.
Formalizzazione rigorosa
Per rendere Test, contracts e fiducia nei modelli analizzabile, definisci prima l’unità di lavoro: source, model, test, mart, metrica o esposizione. Poi collega questa unità a una metrica osservabile: freshness, lineage, test coverage, costo modello e fiducia stakeholder. Infine dichiara la decisione attesa: modello dbt, semantic layer, contratto, test o pipeline di release.
| Elemento | Specifica richiesta |
|---|---|
| Unità di analisi | source, model, test, mart, metrica o esposizione |
| Segnale principale | freshness, lineage, test coverage, costo modello e fiducia stakeholder |
| Baseline | Periodo precedente, gruppo comparabile, benchmark o scenario controfattuale |
| Decisione | modello dbt, semantic layer, contratto, test o pipeline di release |
| Rischio | Scambiare un numero disponibile per una prova sufficiente |
La formalizzazione e solida quando un altro analista può riprodurre la logica, criticare le assunzioni e ottenere la stessa decisione partendo dagli stessi dati.
Esempio o caso studio
Una source marketing smette di inviare campaign_id per una parte delle righe e il mart attribution continua a produrre numeri plausibili. Il caso mostra perché un contract e test di not-null, accepted values e relationship devono fallire presto, prima del dashboard.
| Evidenza osservata | Lettura prudente | Azione consigliata |
|---|---|---|
| Il numero migliora | Potrebbe essere effetto reale o variazione normale | Cercare confronto e segmento |
| Un segmento cambia più degli altri | La media aggregata nasconde una differenza | Separare coorti o casi d’uso |
| Il costo cresce insieme al risultato | L’impatto va letto sul margine | Stimare trade-off e sostenibilità |
Lab / esercizio
Livello base
Scrivi una scheda di una pagina per Test, contracts e fiducia nei modelli: decisione da supportare, metrica primaria, baseline, rischio principale e azione se il segnale e confermato.
Livello intermedio
Costruisci una tabella con tre segmenti, periodi o scenari. Per ciascuno indica cosa cambia, quale spiegazione alternativa e plausibile e quale controllo useresti prima di raccomandare un azione.
Livello research-grade
Prepara un decision memo: ipotesi, dati richiesti, criteri di esclusione, controlli di qualità, soglia decisionale, rischio residuo e piano di monitoraggio dopo la decisione.
Dataset e materiali consigliati
Usa dbt, warehouse, sorgenti CRM, eventi, marts, semantic layer e lineage. Se non hai accesso a dati reali, crea un dataset sintetico con almeno 200 righe, una dimensione temporale, una dimensione segmento e una metrica di outcome.
Errore tipico da evitare
L’errore più comune e usare Test, contracts e fiducia nei modelli come etichetta invece che come processo. Succede quando il team mostra un grafico senza decisione, una metrica senza baseline, o una conclusione senza indicare quale assunzione potrebbe invalidarla.
La domanda di controllo è: se questo risultato fosse instabile, quale scelta sbaglierei? Se la risposta non è concreta, manca ancora il collegamento tra analisi e azione.
Quiz o checkpoint
- Quale decisione concreta dovrebbe migliorare questa lezione?
- Quale unità di analisi rende il problema misurabile?
- Quale baseline useresti per evitare una lettura ingenua?
- Quale errore tipico potrebbe cambiare la conclusione?
- Quale output consegneresti a uno stakeholder non tecnico?
Riepilogo operativo
Test, contracts e fiducia nei modelli diventa utile quando produce una decisione più chiara, non quando aggiunge terminologia. Usa il framework problema, modello, formalizzazione, esempio, lab e checkpoint per trasformare la lezione in pratica verificabile. Categoria: Tecnico. Difficoltà: advanced. Tempo stimato: 18 min.
Percorso collegato
Lezioni da leggere insieme
Questi collegamenti portano la lezione dentro il resto del corso: basi da riprendere, passaggi successivi e connessioni tematiche tra moduli.