Saat Men-deploy Kode Tidak Berarti Merilis Fitur

Tim Anda baru saja menyelesaikan refaktor besar pada algoritma pencarian. Kode sudah diuji, direview, dan di-deploy ke produksi. Tapi begini masalahnya: belum ada yang menggunakannya. Algoritma baru sudah ada di server, sudah dikompilasi dan siap, tetapi setiap pengguna masih mendapatkan hasil dari algoritma lama. Itu disengaja.

Skenario ini mungkin terdengar aneh jika Anda terbiasa dengan deployment di mana setiap perubahan langsung memengaruhi pengguna. Tapi ini sebenarnya pola yang sangat kuat yang memisahkan dua hal yang sering dianggap sama oleh banyak tim: men-deploy kode dan merilis fitur.

Masalah yang Tidak Bisa Diselesaikan oleh Deployment Saja

Canary deployment dan staged rollout menyelesaikan satu masalah dengan baik: mereka mengontrol seberapa banyak traffic yang mencapai versi baru aplikasi Anda. Anda mengirim 5% pengguna ke versi baru, pantau error-nya, lalu naikkan ke 100%. Itu berfungsi ketika Anda ingin merilis seluruh versi secara bertahap.

Tapi bagaimana jika Anda ingin mengaktifkan fitur tertentu hanya untuk pengguna tertentu, tanpa men-deploy versi kode yang berbeda? Mungkin Anda ingin penguji internal melihat hasil pencarian baru sementara yang lain tetap menggunakan algoritma lama. Mungkin Anda ingin mengaktifkan fitur untuk pengguna di satu region terlebih dahulu. Mungkin Anda ingin menguji alur checkout baru dengan 10% pengguna, tetapi hanya jika mereka menggunakan aplikasi mobile.

Canary dan staged rollout tidak menyelesaikan ini. Mereka bekerja di level versi, bukan level fitur. Anda membutuhkan sesuatu yang hidup di dalam kode Anda dan membuat keputusan per request, per pengguna, per sesi.

Feature Flags: Lapisan Kontrol di Dalam Kode Anda

Feature flags adalah pengecekan kondisional dalam kode Anda yang menentukan apakah suatu fitur harus aktif untuk pengguna tertentu. Intinya adalah bahwa kondisi tersebut tidak didasarkan pada versi kode yang sedang berjalan. Ini didasarkan pada konfigurasi yang bisa berubah kapan saja, tanpa perlu redeploy.

Berikut ini tampilannya dalam praktik. Tim Anda menyelesaikan algoritma pencarian baru. Kode di-deploy ke produksi sebagai bagian dari versi terbaru. Tapi di dalam fungsi pencarian, ada pengecekan:

Berikut contoh JavaScript dari pola yang sama:

const featureFlags = require('./feature-flags');

function search(query, user) {
  if (featureFlags.isEnabled('new-search', user)) {
    return newSearchAlgorithm(query);
  } else {
    return oldSearchAlgorithm(query);
  }
}

// Flag mati secara default, jadi semua pengguna menggunakan jalur lama.
// Saat siap, aktifkan flag untuk penguji melalui dashboard.
if feature_flag.is_active("new_search_algorithm", user):
    return new_search_algorithm(query)
else:
    return old_search_algorithm(query)

Flag mati secara default. Setiap pengguna masih mendapatkan algoritma lama, meskipun kode baru ada di server yang sama. Saat Anda siap, Anda mengaktifkan flag untuk penguji internal. Mereka mulai melihat hasil baru. Anda memantau perilaku mereka. Jika ada yang salah, Anda matikan flag kembali. Tidak perlu rollback. Tidak perlu redeploy. Hanya perubahan konfigurasi yang berlaku dalam hitungan detik.

Mengapa Memisahkan Deploy dari Rilis?

Manfaat pertama bersifat psikologis sekaligus praktis: deployment tidak lagi menjadi peristiwa berisiko tinggi. Ketika setiap deploy langsung mengaktifkan semua perubahan, Anda menumpuk pekerjaan, menguji secara intensif, dan menahan napas selama jendela rilis. Ketika deploy dan rilis dipisahkan, Anda bisa deploy setiap hari atau bahkan beberapa kali sehari, karena tahu bahwa kode baru akan diam sampai Anda mengaktifkannya secara eksplisit.

Manfaat kedua adalah kontrol granular. Feature flags tidak hanya on atau off untuk semua orang. Anda bisa mendefinisikan aturan penargetan:

  • Aktif untuk pengguna dengan ID tertentu
  • Aktif untuk pengguna di region tertentu
  • Aktif untuk penguji internal atau pengguna beta
  • Aktif untuk persentase dari total pengguna

Aturan-aturan ini bisa ditumpuk. Anda bisa mulai dengan 5% pengguna, amati selama sehari, naikkan ke 25%, lalu ke 50%, lalu ke 100%. Setiap perubahan dilakukan melalui dashboard atau panggilan API. Tidak ada perubahan kode. Tidak ada deployment.

Manfaat ketiga adalah kill switch. Ketika sebuah fitur menyebabkan masalah setelah diaktifkan, Anda bisa menonaktifkannya dari satu tempat. Ini jauh lebih cepat daripada menunggu pipeline rollback selesai. Dalam hitungan detik, fitur yang bermasalah mati, dan pengguna kembali ke perilaku lama. Untuk insiden produksi, detik-detik itu sangat berarti.

Biaya Tersembunyi: Flag Debt

Feature flags menambah kompleksitas pada codebase Anda. Setiap flag memperkenalkan cabang kondisional yang harus dipelihara. Jika tim Anda membuat flag dan tidak pernah menghapusnya, kode Anda akan dipenuhi dengan kondisi mati yang tidak diingat siapa pun.

Skenario umum: sebuah feature flag dibuat untuk alur checkout baru. Alur tersebut berhasil diluncurkan ke 100% pengguna. Kode checkout lama masih ada, dijaga oleh flag yang selalu mati. Berbulan-bulan kemudian, seorang developer baru melihat flag tersebut dan bertanya-tanya apakah masih relevan. Tidak ada yang tahu. Flag tetap ada karena menghapusnya terasa berisiko.

Ini adalah flag debt, dan ini adalah biaya operasional utama dari feature flags. Flag membutuhkan siklus hidup: buat, aktifkan, pantau, bersihkan. Ketika sebuah fitur sudah sepenuhnya diluncurkan ke semua pengguna, jalur kode lama dan flag harus dihapus. Flag sudah menjalankan tugasnya. Membiarkannya hanya menambah beban kognitif dan meningkatkan permukaan area untuk bug.

Memilih Pendekatan Manajemen Flag Anda

Untuk tim kecil atau kasus penggunaan sederhana, feature flags bisa dimulai sebagai environment variable atau file konfigurasi yang dibaca aplikasi saat startup. Ini berfungsi tetapi memiliki keterbatasan: mengubah flag memerlukan restart atau reload konfigurasi.

Untuk tim yang lebih besar atau aturan penargetan yang lebih kompleks, platform manajemen flag khusus seperti LaunchDarkly, Split, atau Flagr menyediakan evaluasi flag real-time, penargetan pengguna, dan log audit. Platform ini memungkinkan Anda mengubah flag dari dashboard dan melihat efeknya secara instan di semua instance yang berjalan.

Pilihan yang tepat tergantung pada skala Anda. Mulailah dengan yang sederhana. Tambahkan kompleksitas hanya saat Anda membutuhkannya.

Checklist Praktis untuk Menggunakan Feature Flags

  • Setiap flag memiliki pemilik dan tujuan yang jelas, didokumentasikan di tempat yang terlihat
  • Flag memiliki tanggal penghapusan yang direncanakan atau kondisi pemicu (misalnya, "hapus ketika rollout mencapai 100%")
  • Jalur kode lama dihapus ketika flag tidak lagi diperlukan
  • Perubahan flag dicatat dengan siapa yang mengubah apa dan kapan
  • Flag kritis memiliki dashboard monitoring yang menunjukkan siapa yang melihat varian mana
  • Tim memiliki ritme pembersihan rutin untuk flag yang sudah basi

Kesimpulan

Feature flags memberi Anda lapisan kontrol yang beroperasi secara independen dari pipeline deployment Anda. Canary dan staged rollout mengontrol seberapa banyak traffic yang mencapai versi baru. Feature flags mengontrol pengguna mana yang melihat fitur mana dalam versi yang sama. Gunakan keduanya bersama-sama, dan Anda mendapatkan kontrol granular atas bagaimana perubahan mencapai pengguna Anda. Ingatlah bahwa setiap flag yang Anda buat adalah sepotong utang teknis yang perlu dibersihkan ketika tugasnya selesai.