Module · 5 lessons

Data Quality & Logging

Make the job trustworthy when nobody is watching. Write validation rules that assert what the data must be, quarantine bad rows with reasons instead of dropping them, log what each run actually did in a form you can grep, and fail loudly with a nonzero exit rather than quietly publishing wrong numbers.

At a glance

Level
Intermediate
Lessons
5 lessons
Time to complete
1 week
Cost
Free forever · no sign-up

Welcome to Data Quality & Logging, the seventh module — the difference between a job that runs and a job you can trust. Module 6 built CityFlow’s quarterly ETL: an explicit schema, a clean read-clean-transform body, a partitioned write, and idempotent re-runs. Run it by hand and watch the numbers, and it is correct. But that job’s real life is at 2 a.m., unattended, against whatever the upstream feed dropped that night — and the feed will eventually drop something wrong. A month arrives with a tenth of its usual rows because an export failed halfway. A column’s units change. A batch of records lands with timestamps from 2002. The pipeline, as built, will process all of it perfectly and publish numbers that are perfectly wrong.

Three habits separate a pipeline that merely runs from one you can leave alone, and each is a lesson here. The first is validation: rules written as executable assertions about what the data must be — roughly this many rows, distances in a plausible range, every zone id resolvable against the dimension, these columns never null — evaluated every run and reported as a pass/fail table. The second is quarantine: when rows do violate a rule, they are not silently filtered away. They are written to their own table with the reason they failed, so good plus quarantined always reconciles back to the input, and so someone can look at what was rejected and decide whether the rule or the data was wrong. The third is logging: a structured run record — per-stage counts in and out, durations, a machine-readable summary — that lets you answer “what did last night’s run actually do?” without re-running anything.

Then the judgment the whole module builds toward: when to warn and when to abort. A handful of bad rows is a quarantine and a warning; a third of the batch failing means the upstream feed is broken and publishing anything would be worse than publishing nothing. The job needs a gate that stops before the write and exits nonzero, because a scheduler only knows a run failed if the run says so — and a job that swallows its errors and exits 0 is more dangerous than one that crashes. The guided project wires all four into the quarterly ETL and proves both paths for real: a clean run that publishes and exits 0, and a deliberately corrupted run that aborts before writing a single file, leaving the last good table untouched. Start with Lesson 1, where a rule that never fires turns out to be as suspicious as one that always does.

Lessons in this module

1 Validation Rules Write validation rules as executable assertions returning (name, passed, observed, expected, severity), and run 18 of them as one suite over the real 9,554,778-row taxi quarter — where 9 pass, 9 fire, and a referential rule passes at 0 orphans while 36,760 trips still sit on meaningless zone codes. 2 Quarantine Patterns Replace the silent filter with a split: tag every rejected taxi row with the rule it broke, write good and quarantined tables side by side, and prove the reconciliation identity 9,554,757 + 21 = 9,554,778 on the real quarter. 3 Structured Logging Replace scattered prints with a configured Python logger that emits key=value stage lines and one machine-readable JSON run summary — then measure the honest Spark cost of the counts those lines carry: logging them without a cache took 10.10 s versus 6.70 s with one, a 1.51x penalty for the identical log output. 4 Failing Loudly Give CityFlow's ETL a gate that decides between warning and aborting, and prove both paths for real: a good run writes 240,917 buckets and exits 0, while a truncated feed fails a critical rule, aborts before the write, exits 1, and leaves the published $256,692,373.14 table untouched. 5 Guided Project: A Guarded ETL Run Wrap Module 6's quarterly ETL in every guard this module taught — input validation, quarantine with reasons, reconciliation, a gate that fires before the write, a JSON run summary, and a real exit code — then prove both paths as actual subprocesses: the good run publishes 240,917 buckets and $256,692,373.14 and exits 0, while a truncated input aborts at stage 1 with exit code 2 and leaves all 91 published files byte-identical.
Achievement

Complete all 5 lessons to finish the Data Quality & Logging module.

Start module
Sponsor

Keep DATATWEETS free. Help fund practical data, AI, and engineering lessons for learners worldwide.

Buy Me a Coffee at ko-fi.com