Proyek pipeline yang mulai dari satu skrip cepat berubah menjadi belasan berkas dalam hitungan minggu: skrip ekstraksi, transformasi, konfigurasi, berkas data sementara, lalu skrip perbaikan bernama final_v2.py. Tanpa tata letak yang disepakati, setiap anggota tim menyimpan berkas di tempat berbeda dan tidak ada yang yakin kode mana yang sedang berjalan di production. Struktur folder standar menyelesaikan masalah tersebut sebelum mulai: setiap jenis berkas punya rumahnya, kode teruji dapat dijalankan ulang, dan pendatang baru langsung tahu ke mana harus melihat.
Peta Folder Standar #
Berikut struktur proyek pipeline yang kita pakai sebagai patokan sepanjang course ini, ditampilkan dengan perintah tree dari dalam folder proyek:
.
├── README.md
├── config
│ └── etl.toml
├── data
│ ├── processed
│ └── raw
├── scripts
│ └── jalankan_uji.sh
├── src
│ └── etl
│ ├── ekstrak.py
│ └── muat.py
└── tests
└── test_etl.py
9 directories, 6 filesPeran setiap bagian terpetakan sebagai berikut:
| Bagian | Isi | Peran |
|---|---|---|
README.md | cara instalasi dan menjalankan pipeline | pintu masuk bagi anggota tim baru |
config/ | etl.toml, berkas .env | pengaturan terpisah dari kode |
data/raw/ | data mentah hasil ingestion | area baca-saja, tidak diubah manual |
data/processed/ | hasil transformasi | keluaran pipeline |
src/ | kode Python proyek | modul yang diimpor pipeline |
tests/ | pengujian pytest | penjaga perilaku kode |
scripts/ | skrip pembantu | tugas sekali jalan seperti menjalankan uji |
Pemisahan data/raw/ dan data/processed/ bukan formalitas: prinsip immutable raw data menyatakan data mentah tidak pernah diubah di tempat. Setiap perbaikan menghasilkan berkas baru di data/processed/, sehingga kita selalu dapat menelusuri ulang proses dari titik awal yang sama.
Modularitas di Dalam src #
Folder src/etl memecah pipeline menjadi modul kecil dengan satu tanggung jawab: ekstrak.py mengambil data dari sumber, muat.py menuliskan hasil ke tujuan. Isi kedua modul tersebut masih pendek di tahap ini:
def ekstrak(sumber):
"""Ambil data mentah dari sumber."""
return []def muat(data, tujuan):
"""Muat data hasil transformasi ke tujuan."""
return len(data)Ketika transformasi bertambah, kita cukup menambah berkas transform.py di samping keduanya — bukan menumpuk logika dalam satu berkas raksasa. Pengujian lalu mengimpor modul tersebut secara langsung:
from src.etl.ekstrak import ekstrak
def test_ekstrak_mengembalikan_daftar():
hasil = ekstrak("contoh.csv")
assert isinstance(hasil, list)Perintah python3 -m pytest tests -v dijalankan dari akar proyek, dan Python menemukan paket src.etl karena eksekusi python3 -m memasukkan folder kerja ke jalur pencarian modul. Output yang Dihasilkan:
...
tests/test_etl.py::test_ekstrak_mengembalikan_daftar PASSED [100%]
============================== 1 passed in 0.13s ===============================Baris PASSED di atas disalin dari eksekusi nyata; baris ringkasan sesi di bagian awal keluaran dipangkas karena memuat detail lingkungan penulisan yang tidak relevan. Satu pengujian hijau tersebut membuktikan struktur folder sekaligus jalur impor bekerja.
Kapan Struktur Bertambah #
Struktur di atas tumbuh mengikuti kebutuhan, bukan sejak awal. Folder dags/ muncul ketika pipeline pindah ke Airflow; folder models/ muncul ketika transformasi pindah ke dbt; folder docker/ muncul ketika layanan dikemas ke container. Menahan diri dari struktur berlebih di awal sama pentingnya dengan menata ulang ketika proyek membesar — struktur terbaik adalah struktur yang seluruh timnya pahami.
Dokumentasi pytest untuk menulis pengujian yang baik tersedia di https://docs.pytest.org/
. Satu berkas masih menyimpan risiko besar di dalam struktur tersebut: .env yang berisi kredensial. Cara mengamankannya menjadi topik chapter Pengelolaan Secrets.