Apa itu feature flag: panduan lengkap untuk developer
Summary
Feature flag adalah pernyataan if yang jawabannya dari config, bukan hardcoded. Mereka memungkinkan merge aman, rollout bertahap, dan kill switch cepat. Tapi 200 flag dalam satu repo menciptakan technical debt. Panduan ini mencakup tipe flag, rollout aman, pembersihan flag, dan kapan melewatinya.
Apa itu feature flag
Sebuah feature flag adalah kondisional dalam kode Anda yang memutuskan saat runtime apakah sepotong perilaku aktif atau tidak, tanpa deploy baru. Itu seluruh idenya. Dalam praktiknya? Sebuah pernyataan if yang jawabannya berasal dari konfigurasi, baris database, atau layanan flag alih-alih dikodekan secara langsung.
Konsepnya sederhana. Hidup dengan 200 dari mereka dalam satu repository tidak, dan bagian kedua itu yang benar-benar dibahas panduan ini. Semakin besar tim Anda, semakin kompleks situasinya menjadi. Itulah mengapa beberapa tim besar telah mengembangkan proses formal dan tools dedicated untuk mengelola flags secara efisien pada skala besar. Tanpa investasi dalam proses dan tooling yang tepat, repository dengan banyak flags menjadi tidak terkelola dan sulit dipelihara.
Bagaimana bentuk feature flag dalam kode?
Berikut adalah versi yang paling berguna sekalipun:
if (flags.isEnabled("new-checkout", { userId })) {
return renderNewCheckout();
}
return renderOldCheckout();Kedua jalur kode dikirim dalam build yang sama. Nilai flag tinggal di tempat yang dapat Anda ubah tanpa deploy ulang: variabel lingkungan, file JSON, tabel, atau layanan yang dihosting. Ubah nilainya, dan perilaku berubah pada evaluasi berikutnya.
Pemisahan itu adalah intinya. Deployment adalah menempatkan kode di server. Rilis adalah membiarkan pengguna melihatnya. Flag memisahkan kedua peristiwa tersebut, jadi merge ke main tidak lagi berarti "semua orang mendapatkan ini sekarang."

Mengapa tim menggunakan feature flag?
Tiga alasan muncul berulang kali dalam tim nyata yang terdiri dari 5 hingga 50 engineer.
Merge pekerjaan yang belum selesai dengan aman. Anda melakukan commit fitur setengah jadi di balik flag yang mati, dan branch Anda tidak pernah hidup selama tiga minggu. Inilah yang membuat trunk-based development dapat dikerjakan.
Rilis secara bertahap. Hidupkan perubahan untuk pengguna internal, lalu 5% traffic, lalu semua orang. Jika error rate naik, Anda membaliknya kembali dalam hitungan detik.
Matikan sesuatu dengan cepat. Ketika penyedia pembayaran misbehave pada jam 2 pagi, flag memungkinkan on-call mendegradasi satu fitur alih-alih me-rollback seluruh rilis.
Tidak ada dari ini yang memerlukan vendor. Flag dapat berupa boolean dalam tabel config. Lewati platform sampai Anda memerlukan percentage rollouts, audit trails, atau non-engineer yang mengubah-ubah hal.
Apa empat jenis feature flag?
Artikel feature toggles Pete Hodgson yang banyak dikutip di situs Martin Fowler mengurutkan flag berdasarkan berapa lama mereka hidup dan seberapa sering keputusan berubah. Kategorinya masih merupakan model mental yang paling jelas.
Release: hidup berhari-hari hingga berminggu-minggu, diubah oleh engineer. Contoh: sembunyikan redesain checkout yang belum selesai.
Experiment: hidup berminggu-minggu, diubah oleh product dan data. Contoh: A/B test dua halaman harga.
Ops: hidup berjam-jam hingga selamanya, diubah oleh on-call. Contoh: kill switch untuk layanan rekomendasi yang lambat.
Permission: hidup berbulan-bulan hingga bertahun-tahun, diubah oleh product dan support. Contoh: akses beta atau fitur hanya premium.
Kolom lifespan paling penting. Flag rilis yang melampaui rilinya adalah bug yang belum Anda temukan. Flag permission yang dihapus dalam sprint pembersihan adalah outage yang belum Anda alami.
Namai dan beri label tipenya saat membuat flag. Enam bulan kemudian, tidak ada yang ingat kategori apa "new-nav-v2". Ini adalah kesalahan umum dan menyebabkan confusion serius di kemudian hari bagi seluruh tim.

Bagaimana cara merilis flag tanpa melukai pengguna?
Urutan yang membosankan paling berhasil.
Kirim kode dengan flag mati. Verifikasi tidak ada yang berubah.
Aktifkan untuk tim Anda sendiri dalam production. Gunakan selama satu hari.
Aktifkan untuk 1% hingga 5% pengguna, sticky berdasarkan user ID jadi tidak ada yang beralih antar varian tengah-sesi.
Perhatikan error rate, latency, dan satu metrik bisnis. Putuskan ambang batas sebelum Anda mulai, bukan saat menatap dashboard.
Ramp ke 100%, tunggu periode yang ditentukan, lalu hapus flag.
Langkah lima adalah yang dilewati tim. Kami akan melihat mengapa itu lebih mahal daripada yang Anda pikirkan.
Catatan praktis tentang evaluasi: buat flag reads murah dan failure-safe. Jika layanan flag sedang down, kode Anda memerlukan default. Pilih default per flag, dengan tujuan. Kill switch harus gagal ke "safe," sementara fitur baru harus gagal ke "off."
Mengapa feature flag menjadi technical debt?
Setiap flag adalah fork dalam kode Anda. Dua flag membuat empat jalur yang mungkin, sepuluh flag membuat 1.024, dan Anda hampir pasti menguji segelintir dari mereka. Panduan teknis GrowthBook tentang flag debt mengutip penelitian menunjukkan bahwa sekitar 75% komponen toggle masih ada di codebase hingga 49 minggu setelah diperkenalkan, meskipun sebagian besar developer mengatakan mereka berencana menghapusnya.
Hodgson mengatakannya dengan baik dalam artikel Fowler yang sama: tim yang cerdik memperlakukan toggle sebagai inventory dengan carrying cost, dan bekerja untuk menjaga inventory itu tetap rendah.
Kisah horror klasik adalah Knight Capital pada 2012. Flag fitur yang pensiun digunakan kembali untuk perilaku baru sementara kode lama masih duduk di satu server. Ketidaksesuaian itu berkontribusi pada sekitar $460 juta kerugian dalam kurang dari satu jam. Flag basi Anda mungkin tidak akan melakukan itu. Ini akan melakukan sesuatu yang lebih senyap: refactor yang memecahkan branch yang tidak ada orang ketahui ada, atau hire baru menghabiskan sore mencari tahu jalur checkout mana yang real.

Bagaimana cara menemukan setiap flag dalam codebase yang ada?
Ini adalah pertanyaan yang vendor docs lewatkan, dan ini di mana sebagian besar tim terjebak. Dashboard flag memberi tahu Anda apa yang dikonfigurasi. Itu tidak memberitahu Anda di mana setiap flag dibaca dalam kode, atau apakah jalur kode di balik flag "off" masih dapat dijangkau.
Mulai dengan pendekatan murah:
# setiap kunci flag literal dibaca melalui wrapper Anda
rg -n 'isEnabled\("' src/ | sort
# flag didefinisikan tetapi tidak pernah direferensikan
comm -23 <(jq -r 'keys[]' flags.json | sort) \\
<(rg -o 'isEnabled\("([^\"]+)\"' -r '$1' src/ | sort -u)Ini rusak dengan cepat. Kunci flag yang dibangun dari string concatenation tidak muncul dalam grep. Flag yang dilewatkan melalui helper functions menyembunyikan call sites mereka. Monorepos dan pengaturan multi-repo mengalikan masalah, karena kunci yang sama dapat dibaca oleh tiga layanan.
Di sinilah membaca kode dengan tooling membantu. Tools code search yang memahami repo Anda dapat menjawab "di mana new-checkout dievaluasi, dan apa yang bergantung pada hasilnya?" dalam satu query alih-alih sore grep. Cursor dan GitHub Copilot menangani ini secara wajar dalam satu repo. Di seluruh beberapa repo, Anda memerlukan index yang mencakup semua repo, yang merupakan kasus yang kami bangun codebasechat untuk.
Seperti apa proses pembersihan flag yang wajar?
Perlakukan penghapusan sebagai bagian dari pekerjaan, bukan tugas untuk nanti. Ini membutuhkan disiplin dan proses yang jelas dari awal bagi tim Anda untuk mencegah akumulasi flags lama.
Buat ticket penghapusan dengan flag. Tautannya dalam deskripsi flag. Jika ticket tidak ada, flag tidak ship.
Tetapkan pemilik dan tanggal kedaluwarsa untuk setiap flag non-permanen. Sekitar 90 hari tanpa perubahan adalah trigger review yang masuk akal.
Hapus dalam dua pull request. Pertama hapus pemeriksaan flag dan pertahankan jalur pemenang. Lalu hapus cabang mati dan tesnya. Diff kecil adalah diff yang dapat direview.
Tambahkan time bomb test. Test yang gagal ketika flag rilis melewati tanggal kedaluwarsa mengubah niat baik menjadi red build.
Batas totalnya. Jika Anda memiliki 40 flag aktif dan batasnya adalah 40, menambahkan satu berarti menghapus satu.
Static analysis membantu di sini juga. Tools seperti CodeScene dapat menunjukkan file mana yang membawa logika kondisional yang paling kusut, yang biasanya di mana flag lama berkumpul. SonarQube menandai kode yang tidak dapat dijangkau dan mati setelah Anda menghapus pemeriksaan.
Bagaimana cara menguji kode yang duduk di belakang flag?
Testing adalah bagian yang tidak ada yang menganggarkan. Dengan dua jalur per flag, suite test Anda harus menutupi keduanya, setidaknya untuk flag yang menjaga perilaku berisiko.
Pertahankan praktis. Test on dan off states dari setiap release flag dalam unit tests, dengan inject nilai flag alih-alih membaca layanan live. Jalankan satu suite end-to-end terhadap konfigurasi production default, karena itu yang didapat pengguna hari ini. Kemudian jalankan pass kedua dengan flag on untuk fitur yang akan Anda rilis.
Jangan coba test setiap kombinasi. Dengan sepuluh flag Anda tidak dapat. Sebagai gantinya, jaga flag independen: flag yang mengubah perilaku hanya ketika flag lain juga on adalah design smell, dan itu adalah hal pertama untuk dilepas.
Apa yang salah dipahami junior tentang flag?
Junior cenderung membuat tiga kesalahan yang sama, dan masing-masing murah untuk dicegah dalam review.
Nesting flags. Satu flag di dalam yang lain menciptakan jalur yang hanya ada ketika keduanya on. Minta satu flag dengan nama yang jelas alih-alih.
Menempatkan logika dalam nama flag. Kunci seperti "show-new-nav-to-premium-users-in-eu" mengkodekan targeting rule yang milik layanan flag, bukan dalam string.
Lupa default. Jika lookup flag gagal, apa yang terjadi? Buat penulis menulis jawaban dalam deskripsi pull request.
Dua minggu pertama hire baru adalah tepat ketika mereka menjalankan flag lama tanpa pemilik. Registry flag pendek, dengan tipe, pemilik, dan tanggal penghapusan untuk setiap entri, menghemat beberapa jam bertanya-tanya.
Kapan Anda harus melewati feature flag?
Flag tidak gratis, jadi lewatkan mereka ketika:
Perubahan kecil, dapat dibalik, dan deploy jauh dari rollback. Flag menambahkan jalur kode tanpa keuntungan.
Perubahan menyentuh schema database dengan cara flag tidak dapat menyembunyikan. Gunakan expand-and-contract migrations sebagai gantinya.
Tim Anda tidak memiliki proses penghapusan flag. Perbaiki itu terlebih dahulu, atau Anda meminjam melawan readability masa depan.
Dan gunakan tanpa ragu ketika perubahan berisiko, user-facing, dan sulit dibalik dengan deploy ulang. Payment flows, auth changes, dan apa pun dengan data migration di belakangnya semua memenuhi syarat.
Apa yang benar-benar kami lakukan pada tim sepuluh orang
Mulai dengan boolean dalam config dan satu wrapper function, sehingga setiap pembacaan flag melewati satu tempat. Titik choke point tunggal itu membuat daftar flag greppable, auditable, dan mudah untuk migrate ke layanan yang dihosting nanti.
Beri label setiap flag berdasarkan tipe, beri pemilik, dan buat ticket penghapusan pada hari pertama. Review daftar bulanan selama sepuluh menit. Hapus flag yang telah 100% selama dua minggu.
Sebuah feature flag adalah pinjaman. Ambil ketika itu menyelamatkan Anda dari rilis yang berisiko, dan bayar kembali sebelum bunga muncul dalam refactor berikutnya.