Pipeline (data engineering)
Il codice che prende tabelle in input e produce tabelle in output, lo strumento con cui il dato scorre dentro un data warehouse.
In data engineering una pipeline è, nella sua forma più elementare, un pezzo di codice che prende una o più tabelle in input, trasforma i dati e produce in output una tabella diversa. Sahar Massachi, nella Parte 1 della serie “Stop using Slowly-changing Dimensions!” su DataExpert.io, la definisce lo strumento numero uno del data engineering: in un data warehouse il dato scorre verso il basso attraverso catene di pipeline, dalla copia raw in cima fino alle tabelle user-facing in fondo.1
SQL come lingua franca del warehouse
Le pipeline interne al warehouse si scrivono in SQL, non in Python o Java, e la ragione che Massachi dà è strutturale, non di gusto. SQL è un linguaggio abbastanza vincolato da permettere ai motori di parallelizzarlo automaticamente: un breve snippet dichiarativo viene tradotto in meccanismi complessi che prelevano dati da macchine diverse, li trasformano e li incrociano. I linguaggi imperativi concedono troppa libertà perché esista la stessa garanzia: “the tools that invisibly translate your simple snippets into complex mechanisms (…) not only are literally set up with SQL in mind, they figuratively cannot do the same for python, java, etc.”.1
L’eccezione è l’ingestione dall’esterno: chiamare API o leggere stream può richiedere codice imperativo. La regola pratica di Massachi distingue i tre casi: “if you’re writing between tables in a warehouse — SQL. Into a warehouse — you probably need some glue code somewhere. Out of a warehouse — that’s on you”. Anche quando lo strumento di warehouse offre “backdoor” per codice non SQL, Massachi consiglia di pensarci due volte: spesso è più semplice importare il dataset esterno come tabella e ricreare con un join ciò che si sarebbe fatto in modo imperativo.1
ELT, non ETL
Il pattern moderno prescritto dalla serie è ELT (extract, load, transform): il dato si copia grezzo nel warehouse senza pulirlo durante il trasferimento, e la trasformazione avviene dentro il warehouse, in SQL. Nel pattern storico ETL la trasformazione avveniva invece prima del caricamento, in codice esterno. Ogni giorno, non appena l’upstream è pronto, le pipeline deduplicano l’ultimo giorno di dati, rinominano le colonne, e fanno scendere il dato verso le tabelle master più fidate.1
Pipeline ds-aware e idempotenti
La Parte 2 della serie aggiunge la prescrizione operativa che tiene insieme il resto del cluster. Per capirla conviene partire dal problema che risolve: nella scrittura ingenua, una pipeline giornaliera legge “i dati che ci sono adesso” e sovrascrive la tabella di output. La data è implicita, coincide con il momento dell’esecuzione. Questo ha due difetti: rieseguire oggi il run di due settimane fa è impossibile, perché l’input di allora non esiste più; e lo stesso codice, eseguito due volte, produce risultati diversi.2
La prescrizione di Massachi elimina la data implicita con due mosse simmetriche: la pipeline filtra l’input sul giorno che sta processando (WHERE ds={today}) e appende l’output marcandolo con lo stesso ds, senza toccare i giorni precedenti. In forma schematica:
-- La stessa query serve il run di oggi e qualsiasi backfill:
-- cambia solo il valore che l'orchestratore inietta in {{ ds }}.
INSERT INTO dim_users_enriched -- append nella partizione ds = '{{ ds }}'
SELECT u.user_id, u.followers, d.device, '{{ ds }}' AS ds
FROM raw_users u
JOIN raw_devices d ON u.user_id = d.user_id
WHERE u.ds = '{{ ds }}' -- legge solo lo snapshot di quel giorno
AND d.ds = '{{ ds }}'
Il giorno smette così di essere una circostanza dell’esecuzione e diventa un parametro esplicito, iniettato dall’orchestratore (in Airflow, la sintassi Jinja {{ ds }}, o @run_date con parameter binding). È il senso preciso in cui la pipeline diventa una funzione pura del proprio input, nel quadro del functional data engineering di Maxime Beauchemin: eseguita con ds='2024-11-15', legge sempre la stessa partizione di input e scrive sempre la stessa partizione di output, che la si lanci oggi o fra tre mesi. Stesso input, stesso output, nessuno stato nascosto: è la definizione operativa di pipeline idempotente. E poiché il 15 novembre ha bisogno solo dello snapshot del 15 novembre, non del risultato del 14, i giorni diventano indipendenti l’uno dall’altro.2
Da queste due proprietà, determinismo e indipendenza tra giorni, discendono le conseguenze pratiche che Massachi elenca:2
- il backfilling diventa un bottone: run giornaliero e backfill sono la stessa query con un parametro diverso, quindi una sola codebase; e i giorni, essendo indipendenti, girano in parallelo fino ai limiti di concorrenza del DAG, così un mese si riprocessa nel tempo di un giorno;
- i bug nei dati storici diventano correggibili: si corregge la logica una volta e si riesegue l’intervallo interessato; il dato corretto sovrascrive quello sbagliato, partizione per partizione;
- i cambiamenti upstream si propagano: una correzione in
dim_userssi riflette a valle backfillando in parallelo le date interessate di tutte le tabelle dipendenti, e il warehouse resta coerente; - una tabella nuova ottiene la storia gratis: creata oggi, si popola all’indietro backfillando ad esempio 365 giorni, perché gli snapshot raw dei giorni passati sono ancora lì ad aspettare.
L’anti-pattern che rompe tutto questo è la dipendenza dal giorno precedente della propria stessa tabella: se dim_users di oggi richiede dim_users di ieri, i giorni tornano una catena e il backfill torna sequenziale. In Airflow è il comportamento del flag depends_on_past=True, che Massachi prescrive di tenere False per la maggior parte delle dimension table: ogni giorno si ricalcola da raw, indipendente dagli altri. L’eccezione legittima sono le metriche cumulative (il totale storico dei post di un utente), dove la dipendenza dal giorno precedente è strutturale.2
L’orchestratore tipico di queste pipeline è Airflow, creato dallo stesso Beauchemin, che tratta i backfill come cittadini di prima classe: un comando come airflow dags backfill --start-date 2024-11-01 --end-date 2024-11-30 avvia le trenta esecuzioni parallele, ognuna con la propria ds. Le Common Table Expressions sono il costrutto che rende leggibili le query di queste pipeline.2
La commoditizzazione
Nel 2026, osserva Massachi nella Parte 3 della serie, gli LLM scrivono SQL più velocemente e meglio di un data engineer medio, fanno root cause analysis e debuggano errori di infrastruttura: il lavoro di pipeline si è commoditizzato. Ciò che resta di valore non è tecnico: capire cosa costruire, per chi, e con quali priorità. La tesi è sviluppata nella voce data engineer come product owner.3
Voci correlate
- Data warehouse — il sistema di cui le pipeline sono lo strumento principale
- Date stamping — la tecnica che rende le pipeline idempotenti
- Backfilling — l’operazione che le pipeline ds-aware rendono banale
- Functional data engineering — il paradigma teorico
- Common Table Expressions — il costrutto che rende il SQL componibile
- Dimension table e fact table — gli output tipici
- Portale: Data engineering
Bibliografia e sitografia
- Sahar Massachi, The data warehouse setup no one taught you (Stop using Slowly-changing Dimensions! Part 1), DataExpert.io, 24 ottobre 2025. blog.dataexpert.io
- Sahar Massachi, SCD-2 considered harmful! (Stop using Slowly-changing Dimensions! Part 2), DataExpert.io, 4 novembre 2025. blog.dataexpert.io
- Sahar Massachi, Junior data engineers build pipelines. Seniors build trust, DataExpert.io, 30 giugno 2026. blog.dataexpert.io