Modul 03Term 1 · Fondasi8 item poster
Fondasi Data
Masuk untuk menyimpan progres Anda di semua perangkat. Sampai saat itu, progres disimpan di browser ini.
Mengapa ini penting
Kode bisa di-deploy ulang. Data yang sudah korup tidak bisa dikembalikan. Database adalah bagian sistem yang paling tidak boleh salah, dan justru bagian yang paling sembarangan diperlakukan oleh tool AI.
Capaian pembelajaran
- Memodelkan data dengan key, constraint, dan multi-tenancy sejak hari pertama.
- Menemukan dan memperbaiki query lambat dengan EXPLAIN dan index.
- Menghilangkan N+1 query.
- Mengonfigurasi connection pooling untuk serverless.
- Menggunakan transaksi dan locking agar data tetap benar di bawah konkurensi.
- Merilis perubahan skema tanpa downtime.
Materi
3.1 Pemodelan untuk kebenaran data
- Biarkan database yang menegakkan aturan:
NOT NULL,UNIQUE,CHECK, foreign key. Pengecekan di aplikasi bisa kena race condition; constraint tidak. - Uang: integer dalam satuan terkecil (sen) atau
numeric, jangan pernah float. - Waktu: simpan dalam UTC (
timestamptz), konversi saat ditampilkan. - ID: UUIDv7 atau sejenisnya untuk ID publik; jangan pernah mengekspos ID berurutan yang memungkinkan penyerang mengenumerasi record.
- Multi-tenancy: setiap baris milik sebuah
org_id/user_id, dan setiap query dibatasi olehnya. Tegakkan di database dengan Row-Level Security (Postgres RLS), bukan hanya di kode aplikasi.
3.2 Indexing dan optimasi query (25, 26)
- Index adalah struktur lookup yang terurut; tanpa index, DB memindai setiap baris.
- Beri index pada kolom yang Anda pakai untuk filter, join, dan sort. Urutan pada composite index itu penting (kolom equality dulu, baru range).
- Setiap index memperlambat penulisan dan memakan storage; jangan index semuanya.
- Baca
EXPLAIN ANALYZE: cari sequential scan pada tabel besar, estimasi jumlah baris yang tinggi, dan sort yang tumpah ke disk. - Aktifkan slow-query logging (
pg_stat_statements) dan review setiap minggu.
3.3 N+1 query (27)
// N+1: 1 query for orders + 1 per order for its customer
const orders = await db.order.findMany();
for (const o of orders) o.customer = await db.customer.findUnique({ where: { id: o.customerId } });
// Fixed: 2 queries total (or a join)
const orders = await db.order.findMany({ include: { customer: true } });
Deteksi dengan query logging di test: assert jumlah query per request.
3.4 Connection pooling (28)
Setiap koneksi Postgres memakai memori; database membatasi jumlah koneksi (sering sekitar 100). Fungsi serverless membuka satu koneksi per invocation dan menghabiskannya saat beban tinggi. Gunakan pooler (PgBouncer, Supavisor, Neon pooler, Prisma Accelerate) dalam transaction mode untuk serverless.
3.5 Transaksi dan locking (36, 37)
- Bungkus penulisan multi-langkah dalam transaksi: semua berhasil atau tidak sama sekali.
- Optimistic locking: kolom
version;UPDATE ... SET version = version + 1 WHERE id = $1 AND version = $2; nol baris ter-update berarti ada pihak lain yang sudah mengubahnya, jadi retry atau laporkan. - Pessimistic locking:
SELECT ... FOR UPDATEmengunci baris di dalam transaksi. Gunakan untuk resource yang diperebutkan seperti saldo dan inventaris. - Contoh bug: dua klik "setujui pinjaman" yang bersamaan sama-sama membaca
status = pendingdan sama-sama mencairkan dana. Perbaiki dengan conditional update (WHERE status = 'pending') dan cek jumlah baris yang terpengaruh.
3.6 Migrasi dan schema versioning (81, 82)
- Setiap perubahan skema adalah file migrasi berversi di git, diterapkan oleh CI, tidak pernah manual lewat dashboard.
- Expand and contract untuk zero downtime: (1) tambah kolom baru yang nullable, (2) deploy kode yang menulis ke keduanya, (3) backfill secara bertahap per batch, (4) alihkan pembacaan, (5) hapus kolom lama di rilis berikutnya.
- Operasi berbahaya: menambah
NOT NULLtanpa default pada tabel besar, mengganti nama kolom yang sedang dipakai, membuat index tanpaCONCURRENTLY. - Jangan pernah biarkan agent AI menjalankan migrasi langsung ke produksi.
Lab 3: Rusak lalu perbaiki lapisan data Anda
- Seed 1 juta baris. Temukan tiga query paling lambat; perbaiki dengan index; tunjukkan EXPLAIN sebelum/sesudah.
- Tambahkan assertion jumlah query pada test API; temukan dan perbaiki sebuah N+1.
- Tulis test yang mengirim 20 request "tukarkan voucher" secara bersamaan; buktikan voucher hanya ditukarkan tepat satu kali.
- Aktifkan RLS di setiap tabel; tulis test bahwa pengguna A tidak bisa membaca baris milik pengguna B dengan public anon key.
- Lakukan rename kolom dengan expand-and-contract tanpa downtime.
Definition of Done
Paket prompt AI
- "Daftarkan setiap query yang dijalankan endpoint ini dan tandai yang berada di dalam loop."
- "Tulis policy RLS untuk tabel-tabel ini supaya pengguna hanya bisa mengakses baris milik org tempat mereka bergabung. Lalu tulis test yang mencoba menembusnya."
- "Rencanakan perubahan skema ini sebagai migrasi expand-and-contract di beberapa deploy terpisah."