learn-data-engineering-with-phoebe / Builder session 9 of 10
Learn Data Engineering with Phoebe · Builder track · Session 9 of 10

Reliability seams

Pipelines do not break in the middle - they break at the seams, where your code meets a source you do not control. A column gets renamed. A feed arrives with nulls where numbers should be. A run dies halfway. This session teaches the defensive patterns you build into the pipe so bad data is quarantined, not fatal - and marks the exact handoff line where data engineering ends and DataOps takes over.

🔴 Builder track Practitioners: DE · analysts · DS · PMs Runs in your browser · DuckDB 45 min
0-3 · Recap 3-20 · Seams, defenses, handoff 20-42 · Build-along: defensive ingest 42-45 · Q&A
Part 0

Where the pipeline stands

Daybreak's pipeline now extracts, moves, stores, transforms, and processes data at any scale it will realistically see (b2-b8). It works - on good days. This session is about the bad days: the pipeline running unattended when a source silently changes shape, or a batch arrives half-corrupt. Building a pipeline that survives those moments is the last engineering skill before the capstone, and it is where you hand the running system to the operations world.

Live - presented in session Self-study - read after class ▶ Live pipeline - editable & runnable Official sources covered
★ What you walk out with today A map of the three seams where pipelines break (schema drift, bad data, partial failure); the defensive patterns you build in - schema checks, data contracts, idempotency, and quarantining instead of crashing; and a clear line between what data engineering builds and what the DataOps course operates.
Part 1 · covers Fundamentals of DE undercurrents, DLAI Source Systems M3

Where pipelines break: the three seams 7 min live

A pipeline is a chain of handoffs, and every handoff is a seam under tension. The stages themselves rarely fail - your GROUP BY does not spontaneously break. What breaks is the assumption at a seam: that the source still has the columns you expect, that the data is the type it claims, that a run either fully finishes or fully rolls back. Name the seams and you know exactly where to build your defenses.

The seams are where the tension lives Source Ingest Transform Serve seam: schema drift seam: bad data seam: partial failure schema drift: a column is added, renamed, or dropped upstream without warning bad data: nulls, duplicates, wrong types slipping through the feed partial failure: a run dies halfway, leaving the target half-written DE builds resilient seams; DataOps operates and monitors them (the sibling course).
🔍 Click to zoom - the three seams where pipelines break, and the handoff to DataOps
LiveSchema drift, bad data, partial failure4 min

Three failure modes cover most 3am pages:

  • Schema drift: the source team adds, renames, or drops a column and tells no one. Your pipeline either crashes or, worse, keeps running against the wrong shape and produces silently wrong numbers.
  • Bad data: nulls in a key, duplicate rows from a re-delivered batch, a date stored as unparseable text. The data arrives but violates what downstream assumes.
  • Partial failure: a run dies after writing half its output. Re-run it and you double-count; leave it and the target is corrupt. This is why idempotency matters.
Real world

The silent rename. An upstream team renamed customer_id to cust_id in a release. The pipeline did not crash - it read the missing column as all nulls, joined nothing, and served a dashboard showing revenue had collapsed to zero. Finance panicked for a day. A one-line schema check at the seam would have failed the run loudly instead.

Part 2 · patterns you build in

Defend the seams: quarantine, do not crash 6 min live

Good pipelines expect bad input. Instead of trusting the feed and crashing when it lies, you build checks into the pipe: assert the shape is what you agreed, cast defensively so bad values become nulls rather than exceptions, route unparseable rows to a quarantine table, and make every run safe to repeat. The goal is a pipeline that degrades gracefully - it flags the problem and keeps the good data flowing.

-- simulate a messy feed: real orders plus two malformed rows
CREATE OR REPLACE TABLE raw_feed AS
SELECT order_id, order_date FROM orders
UNION ALL
VALUES (9001, 'not-a-date'), (9002, '2026-13-40');

-- TRY_CAST returns NULL on failure instead of throwing - the good rows survive
SELECT count(*)                                       AS total_rows,
       count(TRY_CAST(order_date AS DATE))            AS good_dates,
       count(*) - count(TRY_CAST(order_date AS DATE)) AS quarantined
FROM raw_feed;
Self-studyThe data contract, in concept3 min read

A data contract is a written, agreed-upon promise between the team that produces data and you, the team that consumes it. It pins down the shape (which columns, which types), the meaning (what status = 'completed' actually implies), and the service level (how fresh, how often, who to page when it breaks). It turns "the source changed and broke us" into "the source violated the contract" - a conversation with an owner, not a mystery.

  • Schema + semantics + SLA: the three parts of a useful contract. Shape alone is not enough; you need agreed meaning and freshness too.
  • It makes drift someone's job. With a contract, a breaking change has an owner and a process, not just a downstream victim.
  • Enforce it at the seam. A schema check at ingestion is a contract test. It fails the run loudly the moment reality drifts from the promise.
Idempotency, plainly A step is idempotent if running it twice produces the same result as running it once. Use CREATE OR REPLACE TABLE or delete-then-insert for a partition rather than blind appends, so a retry after a partial failure is always safe.
Part 3 · where DE ends

The handoff to DataOps 4 min live

This seam is also the boundary of the course. Data engineering builds the resilient pipeline and emits the signals (row counts, quarantine counts, a clear pass or fail). DataOps operates it: schedules the runs, monitors the signals, alerts a human when something drifts, and tests changes in CI before they ship. Build versus operate - two crafts meeting at one line.

DE builds (this course) - schema checks at the seam - defensive casts + quarantine tables - idempotent, safe-to-retry steps - emits row counts + pass/fail signals the resilient pipeline itself DataOps operates (learn-dataops) - schedules the runs (orchestration) - monitors the emitted signals - alerts a human on drift or failure - tests changes in CI before shipping keeping it running in production
🔍 Click to zoom - the build-versus-operate line where data engineering hands off to DataOps
Self-studyWhat lives in the sibling course, not here2 min read

You will not write orchestration code in this track - no DAG definitions, no CI configuration, no alerting rules. That is deliberate: those belong to learn-dataops, which operates the pipeline you build here. What you owe the operators is a pipeline that is easy to run on a schedule (idempotent), easy to watch (it emits counts and a clear pass or fail), and easy to reason about when it breaks (bad data is quarantined and logged, not silently dropped).

The clean handoff When your pipeline can be re-run safely, reports what it did, and fails loudly on drift, it is ready for DataOps to schedule and monitor. That readiness is the deliverable of this session.
Demo 1 of 2

Build a defensive ingest ★ 12 min · everyone builds

One script, one seam defended. A messy feed arrives with two malformed rows. You will cast defensively, filter the unparseable rows into a clean table, and count what was quarantined - proving a bad row does not kill the run, it just gets set aside.

Simulate the feed: union the real orders with two rows carrying broken dates - the reality a source can hand you.

Defend: TRY_CAST the date and keep only rows that parse, building a clean table the rest of the pipeline can trust.

Prove it: count rows in, rows kept, and rows quarantined. The run survives; the bad data is accounted for.

-- 1) a messy incoming feed: real orders + two malformed rows
CREATE OR REPLACE TABLE raw_feed AS
SELECT order_id, customer_id, order_date, status, channel FROM orders
UNION ALL
VALUES (9001, 99, 'not-a-date',  'completed', 'web'),
       (9002,  3, '2026-13-40',  'completed', 'app');

-- 2) defensive transform: keep only rows whose date parses
CREATE OR REPLACE TABLE clean_orders AS
SELECT order_id, customer_id,
       TRY_CAST(order_date AS DATE) AS order_date,
       status, channel
FROM raw_feed
WHERE TRY_CAST(order_date AS DATE) IS NOT NULL;

-- 3) prove the bad rows were quarantined, not fatal
SELECT (SELECT count(*) FROM raw_feed)      AS rows_in,
       (SELECT count(*) FROM clean_orders)  AS rows_kept,
       (SELECT count(*) FROM raw_feed)
         - (SELECT count(*) FROM clean_orders) AS quarantined;
Real world

Quarantine beats crash, every time. A pipeline that dies on the first bad row blocks all the good data behind it and pages you at 3am. A pipeline that sets aside the bad rows, keeps the good ones flowing, and reports the count lets you fix the source in the morning while the business keeps running on clean data. Graceful degradation is the whole game.

Demo 2 of 2

Your turn: harden the seam ★ 10 min · build your own

Two hands-on checks and one boundary question. Each editor starts from Daybreak's raw source. Write the guard, run it, read the result - this is the defensive loop you will use for every pipeline.

LiveQ1 · A schema and null check on the keys3 min
-- naming the columns asserts they exist, and the counts check for null keys
SELECT count(*)                                    AS total,
       count(*) FILTER (WHERE order_id IS NULL)    AS null_order_id,
       count(*) FILTER (WHERE customer_id IS NULL) AS null_customer_id,
       count(*) FILTER (WHERE order_date IS NULL)  AS null_order_date
FROM orders;
LiveQ2 · Dedupe a re-delivered batch, keep the latest4 min
-- simulate a re-delivered batch: two duplicate order_ids with a newer date
CREATE OR REPLACE TABLE dup_feed AS
SELECT order_id, order_date, status FROM orders
UNION ALL
SELECT order_id, '2026-06-30', 'refunded' FROM orders WHERE order_id IN (1001, 1002);

-- keep only the latest row per order_id
WITH ranked AS (
  SELECT order_id, order_date, status,
         row_number() OVER (PARTITION BY order_id
                            ORDER BY order_date DESC) AS rn
  FROM dup_feed
)
SELECT order_id, order_date, status
FROM ranked
WHERE rn = 1
ORDER BY order_id
LIMIT 10;
Self-studyQ3 · What belongs to DE, what belongs to DataOps3 min

No SQL - a boundary exercise. At this seam, sort each responsibility into build (DE) or operate (DataOps):

  • DE builds: the TRY_CAST guard, the quarantine table, the schema assertion, the idempotent write, and the counts the pipeline emits. The resilience is in the code.
  • DataOps operates: running the pipeline nightly, watching the quarantine count, paging someone when it spikes, and gating a change through CI before it reaches production.

The test: if it is a property of the pipeline itself, it is DE. If it is about running and watching the pipeline over time, it is DataOps. Build the seam here; operate it in learn-dataops.

Homework

Try it yourself - this week ◐ 20-30 min total

Source material

Official sources covered

This session teaches the reliability undercurrent of Reis & Housley's Fundamentals of Data Engineering and the source-reliability material from the DeepLearning.AI Data Engineering Professional Certificate, run on a live engine. Certificates, cloud labs, and videos stay on the official platforms. This page covers:

Fundamentals of Data Engineering (Reis & Housley) - reliability undercurrentsParts 1-2 · schema drift, bad data, idempotency, data contracts
DLAI Source Systems - M3: reliability & the DataOps handoffParts 1, 3 · seams touched; scheduling, monitoring, and CI are ceded to learn-dataops
Check yourself

Three questions before you go 🎯 ◐ 90 seconds

1 · What is schema drift?

Schema drift is an unannounced change to the shape of the source - a column added, renamed, or dropped. It either crashes the pipeline or, worse, produces silently wrong results. A schema check at the seam catches it loudly.

2 · What is a data contract?

A data contract pins down the shape (columns and types), the semantics (what values mean), and the SLA (freshness, ownership). It turns a breaking change from a downstream mystery into a producer's responsibility.

3 · At this seam, which task belongs to DataOps rather than data engineering?

DE builds the resilient pipeline (guards, quarantine, idempotency). DataOps operates it - scheduling, monitoring the emitted signals, and alerting. If it is about running and watching over time, it is DataOps.

Builder session 9 cheat sheet · pin this

The three seamsSource to ingest, ingest to transform, transform to serve. Pipelines break at the handoffs, not the stages.
Schema driftA column added, renamed, or dropped upstream without warning. Catch it with a schema check that fails loudly.
Bad dataNulls in keys, duplicate rows, unparseable types. Expect it; defend against it at ingestion.
TRY_CAST + quarantineCast defensively so bad values become NULL, route unparseable rows aside, keep the good data flowing.
Data contractAgreed schema + semantics + SLA between producer and consumer. Makes drift someone's job, not your mystery.
IdempotencyRunning a step twice equals running it once. CREATE OR REPLACE or delete-then-insert, not blind appends.
DE vs DataOpsDE builds the resilient pipeline and emits signals. DataOps schedules, monitors, alerts, and tests in CI.
Running projectDaybreak's ingest now quarantines bad rows instead of crashing. Next: b10, the whole pipeline end to end.