Chapter Testing Model Data ditutup dengan satu pertanyaan yang tetap hidup meski seluruh test lulus: kolom gmv itu dihitung bagaimana? Orang baru yang membuka proyek dbt TokoKita membutuhkan jawaban tersebut tanpa harus membaca SQL setiap model satu per satu. dbt menempatkan dokumentasi di tempat yang sama dengan kode: deskripsi model dan kolom ditulis pada properties file, definisi yang dipakai berulang disimpan sebagai docs block, lalu dbt docs generate merender semuanya menjadi situs dokumentasi lengkap dengan lineage graph. Chapter ini membedah ketiga mekanisme tersebut satu per satu.
Dokumentasi yang Hidup di Dalam Proyek #
Chapter Dokumentasi Pipeline pada section Data Pipeline Engineering menuntaskan dokumentasi dari sudut operator: README, runbook kegagalan, dan data dictionary. Pembaca dokumentasi model berbeda — analis dan analytics engineer yang membuka tabel lewat alat BI — tetapi masalahnya sama: dokumentasi yang ditulis terpisah dari kode berhenti sesuai kenyataan setelah beberapa perubahan. dbt mengatasinya dengan struktur: deskripsi model ditulis pada schema.yml, berkas yang juga menampung data_tests dari Chapter Testing Model Data, sehingga penambahan kolom dan pembaruan deskripsi muncul berdampingan dalam satu review.
Perbandingan dua pendekatan perawatan dokumentasi terlihat seperti ini:
| Aspek | Dokumentasi lepas (wiki) | Dokumentasi pada properties file |
|---|---|---|
| Letak | terpisah dari kode | satu berkas dengan test dan konfigurasi model |
| Saat diperbarui | saat ingat, sering terlambat | ikut direview bersama perubahan model |
| Cakupan | manual per tabel | digenerate untuk seluruh proyek |
Deskripsi Model dan Kolom pada Properties File #
Berkas properties untuk mart_penjualan_harian — mart agregat harian yang dibangun mengikuti pola Chapter Model Staging, Intermediate, dan Marts — memuat deskripsi di dua tingkat:
# Properti model dbt TokoKita dengan dokumentasi lengkap.
version: 2
models:
- name: mart_penjualan_harian
description: >
Agregat penjualan harian per kota dan per kategori. Sumber:
fact_pesanan + dim_pelanggan + dim_produk.
columns:
- name: tanggal
description: "Tanggal transaksi (grain harian), tipe DATE."
- name: kota
description: "Kota pengiriman dari dim_pelanggan, bukan kota seller."
- name: kategori
description: "Kategori produk level 1 dari dim_produk."
- name: gmv
description: "{{ doc('gmv') }}"
- name: jumlah_pesanan
description: "Jumlah pesanan unik berstatus selesai pada tanggal dan kota tersebut."Deskripsi level model menjelaskan grain tabel dan tabel sumber; deskripsi level kolom menjelaskan arti tiap kolom. Perhatikan kolom kota: deskripsinya menjelaskan keputusan bisnis — kota pengiriman pelanggan, bukan kota penjual — yang tidak bisa ditebak dari nama kolom saja. Satu kolom masih memakai rujukan misterius {{ doc('gmv') }} yang kita bedah berikutnya.
Docs Block untuk Definisi yang Dipakai Ulang #
Definisi gmv panjang: status mana yang dihitung, dihitung sebelum atau sesudah ongkos kirim, retur dihitung atau tidak. Menyalin definisi sepanjang itu ke setiap kolom gmv di banyak mart adalah resep dokumentasi usang: satu definisi berubah, lima salinan tertinggal. dbt menyediakan docs block — definisi ditulis sekali pada berkas .md atau .sql, lalu dirujuk berdasarkan nama:
{% docs gmv %}
Gross Merchandise Value: total nilai pesanan berstatus `selesai`,
dihitung sebagai SUM(total_item) setelah diskon dan sebelum ongkos
kirim. Pesanan `dibatalkan` dan `dikembalikan` tidak dihitung.
{% enddocs %}
{% docs status_pesanan %}
Status akhir pesanan TokoKita: `selesai`, `dibatalkan`, `dikembalikan`.
Transisi status diatur oleh aplikasi kasir, bukan oleh pipeline.
{% enddocs %}Tag {% docs nama %} ... {% enddocs %} membungkus definisi; isi di dalamnya bebas berformat markdown. Rujukan {{ doc('gmv') }} pada properties file di atas kemudian diganti isi blok tersebut saat dokumentasi dirender.
Merender Halaman Dokumentasi #
Pada proyek nyata, perintah dbt docs generate menghimpun seluruh properties file dan docs block menjadi manifest, menarik statistik warehouse (jumlah baris, tipe kolom) ke catalog, lalu dbt docs serve menjalankan situs dokumentasi lokal — lengkap dengan lineage graph yang tersusun dari relasi ref(), materi yang dibahas lebih luas di Chapter Data Lineage dan Provenance. dbt tidak terpasang di lingkungan bab ini, jadi kita jalankan mini renderer yang mengerjakan inti prosesnya: membaca properties file, memanen docs block, lalu me-resolve setiap rujukan {{ doc('...') }}:
"""Mini docs renderer: meniru apa yang dbt docs tampilkan.
dbt tidak terpasang; skrip ini membaca properti model (schema.yml) dan
docs block (berkas .md berisi {% docs %}), lalu merender halaman
dokumentasi seperti situs dbt docs: deskripsi model + deskripsi kolom,
termasuk me-resolve rujukan {{ doc('...') }}.
"""
import re
import yaml
with open("ch2_schema.yml", encoding="utf-8") as f:
doc = yaml.safe_load(f)
model = doc["models"][0]
# panen docs block: {% docs nama %} isi {% enddocs %}
teks_blocks = open("ch2_docs_blocks.md", encoding="utf-8").read()
blok = dict(re.findall(r"{% docs (\w+) %}(.*?){% enddocs %}", teks_blocks, re.S))
blok = {nama: " ".join(isi.split()) for nama, isi in blok.items()}
print(f"docs block ditemukan : {sorted(blok)}")
print()
def resolve(deskripsi):
"""Ganti {{ doc('nama') }} dengan isi docs block."""
return re.sub(r"{{ doc\('(\w+)'\) }}", lambda m: blok[m.group(1)], deskripsi)
print(f"=== {model['name']} ===")
print(resolve(" ".join(model["description"].split())))
print()
print(f"{'Kolom':<17}Deskripsi")
for kolom in model["columns"]:
print(f"{kolom['name']:<17}{resolve(kolom['description'])}")Output yang Dihasilkan:
docs block ditemukan : ['gmv', 'status_pesanan']
=== mart_penjualan_harian ===
Agregat penjualan harian per kota dan per kategori. Sumber: fact_pesanan + dim_pelanggan + dim_produk.
Kolom Deskripsi
tanggal Tanggal transaksi (grain harian), tipe DATE.
kota Kota pengiriman dari dim_pelanggan, bukan kota seller.
kategori Kategori produk level 1 dari dim_produk.
gmv Gross Merchandise Value: total nilai pesanan berstatus `selesai`, dihitung sebagai SUM(total_item) setelah diskon dan sebelum ongkos kirim. Pesanan `dibatalkan` dan `dikembalikan` tidak dihitung.
jumlah_pesanan Jumlah pesanan unik berstatus selesai pada tanggal dan kota tersebut.Mari kita telaah baris-baris kode di atas:
- Baris 11-14 (memuat properties):
yaml.safe_loadmengubahschema.ymlmenjadi struktur Python — parser yang sama dengan yang dbt pakai untuk membaca properties file. - Baris 17-19 (memanen docs block): ekspresi reguler menangkap pasangan nama-isi dari setiap
{% docs %} ... {% enddocs %}; comprehension berikut meratakan whitespace agar definisi tampil sebagai satu paragraf. - Baris 23-25 (
resolve): setiap kemunculan{{ doc('nama') }}diganti isi blok yang sesuai — persis pekerjaan yang dbt lakukan sebelum menampilkan deskripsi di situs dokumentasi. - Baris 27-32 (merender): deskripsi model dicetak lebih dulu, lalu tabel kolom; kolom
gmvkini menampilkan definisi lengkap, bukan rujukan mentahnya.
Situs dbt docs sungguhan melangkah lebih jauh dari hasil render ini dengan tiga tambahan: lineage graph yang menampilkan seluruh DAG proyek, statistik warehouse per tabel, dan SQL hasil kompilasi tiap model — semuanya dari satu perintah. Panduan penulisan deskripsi dan docs block tersedia di dokumentasi dbt
, sedangkan dbt docs generate dan dbt docs serve dirinci di referensi perintah dbt
.
Dokumentasi menjawab pertanyaan tentang arti kolom. Pertanyaan yang tersisa berada di angka: berapa GMV bulan lalu? — dan jawabannya harus sama di setiap dashboard yang menampilkannya. Pekerjaan menjamin hal tersebut adalah materi Chapter Semantic Layer.