Bagian-bagian sebelumnya membangun jalur yang andal, tetapi keandalan tanpa pemeriksaan hanyalah asumsi. Validasi adalah tahap yang membaca kembali hasil pekerjaan sendiri dan berani menyatakan “ini tidak sama” bila memang berbeda. Kita memasang tiga pemeriksaan: rekonsiliasi baris sumber terhadap warehouse, kesamaan agregat antara fact dan summary, dan kesamaan berkas gold dengan tabel summary. Ketiganya dijalankan sebelum transaksi di-commit, sehingga kegagalan validasi tidak menyisakan perubahan apa pun pada warehouse.
Rekonsiliasi Sumber-Target #
Rekonsiliasi membandingkan jumlah baris per kota antara sumber yang baru dibersihkan dan tabel fact, dikelompokkan berdasarkan source_partition:
SELECT
city,
count(*) AS jumlah,
sum(total_price) AS total
FROM fact_pesanan
WHERE source_partition = ?
GROUP BY city
ORDER BY citydef reconcile_source_target(con, fact_df, partition) -> list[CheckResult]:
"""Bandingkan baris sumber dan fact per kota untuk satu partisi."""
sumber = _kota_sumber(fact_df)
target = _kota_target(con, partition)
selisih = [
f"{kota}: sumber={sumber.get(kota, 0)} target={target.get(kota, 0)}"
for kota in sorted(set(sumber) | set(target))
if sumber.get(kota, 0) != target.get(kota, 0)
]
ok = not selisih
detail = f"{sum(sumber.values())} baris di {len(sumber)} kota" if ok else "; ".join(selisih)
return [CheckResult("reconcile kota", ok, detail)]_kota_sumber menghitung dari DataFrame sumber dengan groupby, _kota_target menjalankan berkas SQL di atas. Hasil disatukan menjadi satu CheckResult yang mencetak OK atau GAGAL beserta perbedaannya.
Cek Agregat dan Gold #
check_aggregates menjumlahkan fact dan summary untuk tanggal yang sama, lalu membandingkannya sebagai Decimal sehingga perbedaan satu sen pun terdeteksi. check_gold membaca berkas CSV di zona gold lalu membandingkan isinya baris demi baris dengan tabel summary. Pada proyek ini ketiga pemeriksaan berjalan pada setiap eksekusi normal:
Output yang Dihasilkan:
== validate_run pada warehouse asli (2026-11-02) ==
OK reconcile kota: 8 baris di 4 kota (total sumber 8 = total target 8)
OK agregat harian: fact: 8 baris, Rp3,542,000.00 bruto, Rp3,092,000.00 bersih; summary: 8 baris, Rp3,542,000.00 bruto, Rp3,092,000.00 bersih
OK gold csv: 4 baris gold vs 4 baris summaryUntuk membuktikan bahwa pemeriksaan ini tidak sekadar formalitas, kita salin warehouse lalu menghapus satu baris fact di luar pipeline, tepat seperti kecurangan yang ingin dideteksi:
Output yang Dihasilkan:
== salinan warehouse setelah satu baris dihapus di luar pipeline ==
GAGAL reconcile kota: Jakarta: sumber=3 target=2; total sumber 8 vs target 7
GAGAL agregat harian: fact: 7 baris, Rp2,643,000.00 bruto, Rp2,193,000.00 bersih; summary: 8 baris, Rp3,542,000.00 bruto, Rp3,092,000.00 bersih
OK gold csv: 4 baris gold vs 4 baris summaryDua pemeriksaan pertama langsung menunjuk Jakarta: sumber tiga baris, target dua. Pemeriksaan gold tetap OK karena berkas gold memang masih sesuai summary-nya; kombinasi ketiganya memberi petunjuk bahwa yang berubah adalah fact, bukan summary. Pola baca seperti ini dibahas pada chapter Data Reconciliation dan Data Validation.
Pengujian Otomatis #
Seluruh perilaku di atas dikunci dengan tests/ yang berjalan dari direktori proyek:
python3 -m pytest tests/ -qOutput yang Dihasilkan:
...................................................................... [100%]
70 passed in 2.56sCakupan pengujian tersebut:
| Berkas | Yang dikunci |
|---|---|
test_extract.py | Pola partisi, penolakan berkas dan kolom, nilai mentah utuh |
test_transform.py | Aturan karantina, duplikat terakhir menang, build_fact |
test_load.py | MERGE menyisip lalu memperbarui, summary tidak berganda, checksum stabil |
test_idempotency.py | StateStore simpan-muat, percobaan terakumulasi, checksum identik |
test_scheduler.py | Cron valid dan invalid, next_run, due_runs, run_loop jam palsu |
test_failures.py | Exit code, karantina, alert nonaktif dan stub |
test_monitoring.py | Checksum, manifest, laporan status |
test_validate.py | Rekonsiliasi dan agregat pada warehouse yang dirusak |
test_pipeline_e2e.py | Tiga tanggal penuh, lewati, --force, exit code 1/2/3/6 |
Penutup Proyek #
Sembilan bagian kita kini menjadi satu kesatuan: zona data yang jelas, ekstraksi yang setia pada bentuk aslinya, pembersihan yang berani menolak, pemuatan yang aman diulang, penjadwalan yang mengejar yang terlewat, kegagalan yang tercatat, monitoring yang terbaca, dan validasi yang berani gagal. Pola raw-state-gold-quarantine pada proyek ini dapat dipindahkan ke skala yang jauh lebih besar: ganti DuckDB dengan warehouse lain, ganti cron dengan orchestrator, dan kontraknya tetap sama.
Langkah berikutnya adalah memperluas sisi konsumsi: warehouse ini masih menyimpan dua tabel tanpa dimensi lengkap. Proyek Proyek: Data Warehouse Penjualan membangun pemodelan dimensional yang utuh di atas beban serupa, dari star schema hingga tabel agregat yang siap melayani dashboard. Semua berkas proyek ini dapat diunduh dari bagian Berkas Sumber, dan python3 -m pytest tests/ -q harus tetap menjadi gerbang sebelum Anda mengubah apa pun.
Bacaan lanjut: dokumentasi pytest .