Trunk-based development dan feature flag adalah kombinasi yang membantu tim mengirim perubahan kecil ke branch utama setiap hari tanpa harus menunggu fitur selesai sepenuhnya. Dengan pola ini, branch hidup singkat, konflik merge berkurang, CI lebih relevan, dan rilis bisa dilakukan lebih sering karena fitur yang belum siap dapat disembunyikan di balik flag.

Masalah yang biasanya ingin diselesaikan pendekatan ini adalah long-lived branch, integrasi yang terlambat, dan rilis besar yang sulit diprediksi. Solusinya bukan sekadar “merge lebih cepat”, tetapi membangun alur kerja di mana kode yang belum aktif tetap aman masuk ke trunk, diuji otomatis, lalu diaktifkan bertahap saat siap.

Kapan trunk-based development dan feature flag cocok digunakan

Pendekatan ini paling cocok ketika tim ingin meningkatkan frekuensi integrasi dan mengurangi risiko rilis. Biasanya efektif untuk tim kecil sampai menengah yang sudah memiliki dasar CI/CD dan disiplin testing yang cukup baik.

Kondisi yang cocok

  • Tim sering mengalami konflik merge karena branch hidup berhari-hari atau berminggu-minggu.
  • Rilis jarang karena setiap rilis menggabungkan terlalu banyak perubahan sekaligus.
  • Tim ingin deploy sering tetapi belum semua fitur boleh terlihat oleh pengguna.
  • Aplikasi memiliki pipeline test otomatis minimal untuk unit test, integrasi dasar, dan pemeriksaan build.
  • Tim butuh rollback cepat tanpa selalu melakukan revert commit atau redeploy penuh.

Kondisi yang kurang cocok tanpa persiapan tambahan

  • Coverage test sangat rendah dan perubahan sering merusak alur utama.
  • Semua perubahan bergantung pada migrasi skema yang tidak kompatibel mundur.
  • Tim belum punya disiplin untuk membersihkan flag yang sudah tidak dipakai.
  • Review code masih lambat, sehingga trunk tetap menjadi bottleneck.

Catatan: Trunk-based development bukan berarti tanpa branch sama sekali. Yang dibatasi adalah umur branch dan ukuran perubahan, bukan larangan membuat branch.

Prinsip inti: branch pendek, merge kecil, rilis terpisah dari aktivasi fitur

Inti dari trunk-based development adalah developer bekerja sedekat mungkin dengan branch utama, sering sinkron, dan cepat merge. Feature flag melengkapi pola ini dengan memisahkan deploy dari release. Kode bisa sudah terpasang di production, tetapi perilaku baru belum aktif untuk semua pengguna.

Mengapa kombinasi ini bekerja

  • Integrasi lebih dini: bug integrasi muncul lebih cepat saat perubahan kecil segera digabungkan.
  • Konflik lebih kecil: branch singkat mengurangi drift terhadap trunk.
  • Rilis lebih aman: fitur baru bisa dimatikan tanpa revert besar.
  • Deploy lebih rutin: karena trunk selalu dijaga dalam kondisi bisa dibangun dan diuji.

Pemisahan istilah yang penting

  • Merge: perubahan masuk ke trunk.
  • Deploy: artefak baru dipasang ke environment tertentu.
  • Release: fitur benar-benar diaktifkan untuk pengguna.

Dengan feature flag, merge dan deploy bisa terjadi lebih awal, sedangkan release ditunda sampai validasi bisnis, QA, atau kesiapan operasional terpenuhi.

Aturan branch yang sederhana dan realistis

Tim kecil-menengah tidak membutuhkan aturan branch yang rumit. Justru terlalu banyak branch permanen biasanya menambah overhead koordinasi.

Aturan branch yang disarankan

  • Satu branch utama: biasanya main atau trunk.
  • Branch kerja berumur pendek: dipakai untuk perubahan kecil, idealnya selesai dalam hitungan jam hingga maksimal 1-2 hari.
  • Jangan membuat branch fitur jangka panjang untuk pekerjaan yang bisa dipotong menjadi beberapa perubahan inkremental.
  • Gunakan pull request kecil agar review cepat dan fokus.
  • Rebase atau merge dari trunk secara rutin jika PR belum selesai di hari yang sama.

Contoh workflow Git harian

git checkout main
git pull origin main

git checkout -b feat/checkout-button-flag
# lakukan perubahan kecil

git add .
git commit -m "Add checkout button behind feature flag"
git push origin feat/checkout-button-flag

Setelah review lolos dan pipeline hijau, perubahan di-merge ke main. Developer lalu kembali bekerja dari trunk terbaru.

git checkout main
git pull origin main
git branch -d feat/checkout-button-flag

Batasan praktis untuk menjaga branch tetap pendek

  • Satu PR sebaiknya fokus pada satu langkah teknis yang jelas.
  • Jika fitur besar, pecah menjadi beberapa PR: misalnya schema prep, service layer, endpoint, UI tersembunyi, observability, lalu aktivasi.
  • Hindari mencampur refactor besar dengan fitur baru dalam satu PR.

Alur kerja harian developer

Alur kerja trunk-based development yang sehat biasanya terlihat sederhana, tetapi membutuhkan disiplin konsisten.

  1. Tarik trunk terbaru sebelum mulai bekerja.
  2. Buat branch pendek untuk perubahan kecil.
  3. Tambahkan atau ubah kode dalam langkah inkremental yang tetap aman di-merge.
  4. Lindungi perilaku baru dengan feature flag jika fitur belum siap dirilis.
  5. Jalankan test lokal secukupnya sebelum push.
  6. Buka PR kecil dengan konteks yang jelas.
  7. Perbaiki review dengan cepat agar branch tidak menua.
  8. Merge ke trunk segera setelah lolos.
  9. Biarkan CI/CD build, test, dan deploy otomatis sesuai environment.

Cara memotong fitur besar menjadi perubahan kecil

Misalnya tim ingin menambah alur checkout baru. Jangan menunggu semuanya selesai baru merge. Pecah menjadi langkah seperti:

  • Tambah struktur data atau endpoint yang kompatibel mundur.
  • Tambah logika backend baru tetapi belum dipakai default.
  • Tambah UI baru di balik flag.
  • Tambah metrik, logging, dan dashboard.
  • Aktifkan untuk internal user terlebih dahulu.
  • Naikkan exposure secara bertahap.

Pola ini membuat trunk tetap stabil walau pekerjaan sebenarnya belum selesai 100%.

Menerapkan feature flag dengan benar

Feature flag adalah mekanisme untuk menentukan apakah kode atau perilaku tertentu aktif. Implementasinya bisa sederhana pada awalnya, misalnya dari environment variable atau konfigurasi pusat, selama tim tahu bagaimana mengelolanya.

Jenis flag yang umum

  • Release flag: menyembunyikan fitur sampai siap dirilis.
  • Ops flag: mematikan fitur untuk mitigasi insiden.
  • Experiment flag: untuk uji bertahap atau segmentasi pengguna.
  • Permission flag: mengaktifkan fitur untuk tenant, role, atau user tertentu.

Contoh gating fitur di backend

function isFeatureEnabled(flagName, context) {
  const flags = {
    new_checkout: false
  };

  // contoh sederhana: bisa diganti dengan config service atau database
  return Boolean(flags[flagName]);
}

function getCheckoutPage(user) {
  if (isFeatureEnabled('new_checkout', { userId: user.id, role: user.role })) {
    return renderNewCheckout(user);
  }

  return renderCurrentCheckout(user);
}

Contoh di atas sengaja sederhana. Pada implementasi nyata, evaluasi flag sering perlu konteks seperti user ID, tenant, region, atau persentase rollout. Yang penting, jalur off harus tetap jelas dan aman.

Contoh gating di frontend

if (flags.newCheckout) {
  showNewCheckoutButton();
} else {
  showCurrentCheckoutButton();
}

Untuk frontend, jangan mengandalkan flag di UI saja bila fitur juga memengaruhi akses data atau aturan bisnis. Jika ada konsekuensi keamanan atau integritas data, validasi harus tetap dilakukan di backend.

Praktik baik saat memakai feature flag

  • Default aman: jika sistem flag gagal, tentukan perilaku default yang paling minim risiko.
  • Nama flag jelas: misalnya checkout_new_flow, bukan flag1.
  • Tambahkan pemilik dan tanggal evaluasi agar flag tidak terlupakan.
  • Test kedua jalur: kondisi on dan off.
  • Jangan menyimpan logika bisnis penting tersebar di banyak tempat tanpa abstraksi.

Strategi code review agar trunk tidak menjadi bottleneck

Pada trunk-based development, masalah utama bukan hanya coding, tetapi latensi review. Jika PR kecil tetap menunggu lama, branch akan menua dan drift kembali terjadi.

Prinsip review yang efektif

  • Utamakan PR kecil: lebih cepat dipahami dan lebih sedikit risiko tersembunyi.
  • Batasi ruang lingkup: satu PR, satu tujuan utama.
  • Gunakan checklist review singkat: correctness, test, backward compatibility, observability, dan cleanup plan untuk flag.
  • Otomatiskan hal yang mekanis: format, lint, test dasar, secret scanning, dependency checks bila tersedia.
  • Terapkan SLA internal review: misalnya review awal dalam jam kerja yang sama jika memungkinkan.

Apa yang perlu diperiksa reviewer

  • Apakah perubahan aman di-merge walau fitur belum aktif?
  • Apakah jalur flag off tetap benar?
  • Apakah migrasi data kompatibel dengan deployment bertahap?
  • Apakah ada logging atau metrik untuk mendeteksi masalah saat rollout?
  • Apakah ada rencana menghapus flag setelah stabil?

Integrasi ke CI/CD untuk build, test, dan deploy otomatis

Trunk-based development hampir selalu membutuhkan CI/CD yang disiplin. Tujuannya bukan sekadar otomatisasi, tetapi menjaga trunk selalu dalam kondisi yang dapat dipercaya.

Pipeline minimal yang disarankan

  1. Build: pastikan aplikasi dapat dibangun secara konsisten.
  2. Static checks: lint, format, dan pemeriksaan dasar kualitas kode.
  3. Unit test: validasi logika inti dengan cepat.
  4. Integration test penting: terutama area kritis seperti auth, pembayaran, atau API utama.
  5. Artifact publishing: hasil build disimpan agar deployment reproducible.
  6. Deploy otomatis ke environment target setelah syarat terpenuhi.

Alur deploy yang umum

  • Setiap PR menjalankan build dan test.
  • Setiap merge ke main memicu build artefak resmi.
  • Artefak yang sama dipromosikan ke staging lalu production.
  • Fitur baru tetap tidak aktif secara default jika masih di balik flag.

Contoh urutan yang aman

Urutan yang lebih aman biasanya:

  1. Deploy kode baru dengan flag dalam posisi off.
  2. Verifikasi health check, error rate, log, dan metrik dasar.
  3. Aktifkan untuk internal user atau persentase kecil trafik.
  4. Pantau dampak.
  5. Naikkan rollout bertahap.

Pendekatan ini mengurangi risiko karena deployment tidak langsung berarti semua pengguna menerima perilaku baru.

Perhatian untuk perubahan database

Kesalahan umum adalah menerapkan perubahan skema yang hanya cocok untuk kode baru. Dalam trunk-based development, lebih aman memakai pola perubahan yang kompatibel bertahap, misalnya:

  • Tambahkan kolom baru terlebih dahulu, jangan langsung hapus kolom lama.
  • Buat kode mampu membaca format lama dan baru sementara waktu.
  • Lakukan backfill jika perlu.
  • Alihkan pembacaan/penulisan secara bertahap.
  • Hapus struktur lama setelah tidak dipakai dan flag dibersihkan.

Rollback non-destruktif dengan feature flag

Salah satu manfaat terbesar feature flag adalah rollback non-destruktif. Jika masalah ada pada perilaku fitur, tim bisa mematikan flag tanpa langsung revert commit atau membatalkan deployment seluruh aplikasi.

Kapan rollback dengan flag efektif

  • Bug terlokalisasi pada fitur yang dibungkus flag.
  • Infrastruktur dan deployment aplikasi secara umum sehat.
  • Skema data masih kompatibel dengan jalur lama.

Kapan flag saja tidak cukup

  • Migrasi database sudah merusak kompatibilitas mundur.
  • Bug ada pada kode inti yang tidak berada di balik flag.
  • Perubahan menyebabkan beban sistem meningkat walau fitur tampak nonaktif.

Artinya, feature flag bukan pengganti desain deployment yang aman. Ia efektif jika sejak awal fitur dirancang agar dapat dimatikan tanpa meninggalkan sistem dalam keadaan setengah rusak.

Risiko umum dan cara menghindarinya

1. Flag menumpuk dan menjadi utang teknis

Flag yang dibiarkan terlalu lama membuat kode bercabang, sulit dibaca, dan rawan bug. Solusinya:

  • Setiap flag punya pemilik.
  • Tentukan tanggal review atau target penghapusan.
  • Buat tiket cleanup saat fitur sudah stabil.
  • Audit flag secara berkala.

2. Branch drift tetap terjadi

Ini biasanya bukan karena metode gagal, tetapi karena PR masih terlalu besar atau review terlalu lambat. Solusinya:

  • Kecilkan ukuran perubahan.
  • Tingkatkan frekuensi merge.
  • Kurangi dependensi silang antarpekerjaan.
  • Pastikan reviewer tersedia.

3. Fitur tersembunyi tetapi belum benar-benar aman

Beberapa tim menganggap “sudah di balik flag” berarti otomatis aman. Padahal bisa saja migrasi, job background, endpoint, atau cache baru tetap aktif. Solusinya adalah memeriksa seluruh jalur eksekusi, bukan hanya komponen UI.

4. Test hanya menutupi satu kondisi flag

Jika hanya jalur on yang diuji, rollback bisa gagal. Jika hanya jalur off yang diuji, fitur baru bisa rusak saat dirilis. Minimal test area penting untuk dua kondisi tersebut.

5. Flag dipakai untuk semua hal

Feature flag berguna, tetapi tidak semua perubahan perlu flag. Refactor internal kecil, perbaikan typo, atau perubahan yang aman dan langsung aktif tidak selalu membutuhkan gating. Gunakan saat benar-benar membantu memisahkan deploy dari release.

Contoh workflow end-to-end yang praktis

Skenario

Tim ingin meluncurkan alur checkout baru tanpa menunggu seluruh pengembangan selesai sempurna.

  1. Developer membuat branch pendek dari main.
  2. Backend untuk checkout baru ditambahkan, tetapi aksesnya dibungkus flag checkout_new_flow.
  3. Frontend menampilkan tombol atau halaman baru hanya jika flag aktif.
  4. PR dibuka dengan ukuran kecil dan fokus.
  5. CI menjalankan build, lint, unit test, dan integration test penting.
  6. PR di-merge ke main.
  7. Pipeline deploy otomatis mendorong artefak ke staging dan production.
  8. Flag tetap off di production.
  9. Tim QA atau internal user menguji dengan flag on untuk akun tertentu.
  10. Jika stabil, rollout dinaikkan bertahap.
  11. Jika ada masalah, flag dimatikan tanpa redeploy.
  12. Setelah stabil penuh, kode lama dihapus dan flag dibersihkan.

Checklist implementasi bertahap untuk tim kecil-menengah

Tahap 1: sederhanakan aturan kerja Git

  • Tetapkan satu branch utama: main.
  • Batasi umur branch kerja.
  • Sepakati bahwa PR harus kecil dan fokus.
  • Hindari branch rilis jangka panjang kecuali benar-benar diperlukan.

Tahap 2: pastikan trunk selalu sehat

  • Setiap PR wajib menjalankan build dan test dasar.
  • Merge hanya jika pipeline hijau.
  • Perbaiki trunk yang rusak sebagai prioritas utama.

Tahap 3: mulai gunakan feature flag untuk fitur yang belum siap rilis

  • Pilih satu atau dua fitur kandidat.
  • Tentukan naming convention flag.
  • Simpan metadata: pemilik, tujuan, tanggal review.
  • Pastikan ada jalur default yang aman.

Tahap 4: hubungkan ke deployment otomatis

  • Setiap merge ke main menghasilkan artefak deployable.
  • Deploy ke staging lalu production secara konsisten.
  • Pisahkan deployment dari aktivasi fitur.

Tahap 5: tambahkan observability untuk rollout

  • Log error per fitur atau area layanan.
  • Pantau metrik dasar setelah deploy dan setelah flag diaktifkan.
  • Siapkan prosedur mematikan flag saat insiden.

Tahap 6: disiplin cleanup

  • Audit flag yang sudah 100% aktif atau tidak terpakai.
  • Hapus kode lama sesegera mungkin setelah rollout stabil.
  • Evaluasi PR yang terlalu besar dan perbaiki proses pemotongan pekerjaan.

Kesalahan implementasi yang sering terjadi

  • Mengadopsi trunk-based development tetapi tetap mempertahankan branch fitur berminggu-minggu.
  • Memakai feature flag tanpa observability, sehingga sulit tahu apakah rollout aman.
  • Mengaktifkan fitur untuk semua user sekaligus padahal tujuan flag adalah kontrol bertahap.
  • Tidak memikirkan kompatibilitas database saat beberapa versi kode bisa berjalan bersamaan.
  • Menganggap CI cukup dengan unit test saja untuk area sistem yang sangat integratif.

Penutup

Trunk-based development dan feature flag bukan sekadar pola branching, tetapi cara kerja untuk mempercepat integrasi dan menurunkan risiko rilis. Kuncinya ada pada perubahan kecil, branch singkat, review cepat, trunk yang selalu sehat, serta pemisahan yang jelas antara merge, deploy, dan release.

Untuk tim kecil-menengah, implementasi terbaik biasanya dimulai dari aturan sederhana: satu trunk, PR kecil, CI wajib, lalu feature flag untuk fitur yang belum siap. Jika dijalankan konsisten dan disertai cleanup yang disiplin, tim bisa merge lebih sering, mengurangi branch drift, dan merilis dengan kontrol yang jauh lebih baik.