โ† Semua pembelajaran / Laravel Nol โ†’ Enterprise
Fase 10 ยท Enterprise & Capstone

Feature flag dengan Pennant

Feature flag mengubah rilis dari peristiwa besar jadi sakelar yang bisa dibalik dalam sedetik. Untuk aplikasi yang tidak boleh mati, itu perbedaan antara rollback dua puluh menit dan pemulihan seketika.

Sumber asli laravel.com Resmi Rangkuman ~5 menit baca

Intisari

  • Fitur didefinisikan sekali, lalu dicek dengan Feature::active('nama') di mana pun.
  • Nilainya bisa bergantung pengguna โ€” cocok untuk peluncuran bertahap dan uji A/B.
  • Hasilnya disimpan (database atau cache), jadi seorang pengguna selalu mendapat pengalaman yang konsisten.
  • Mematikan fitur bermasalah tidak butuh deploy.
  • Flag punya umur; yang tidak dibersihkan berubah jadi percabangan kode yang tidak ada yang berani hapus.

Mendefinisikan dan memakai

composer require laravel/pennant
php artisan vendor:publish --provider="Laravel\Pennant\PennantServiceProvider"
php artisan migrate
// AppServiceProvider::boot()
use Laravel\Pennant\Feature;

Feature::define('editor-baru', fn (User $user) => match (true) {
    $user->is_staf              => true,           // staf lebih dulu
    $user->created_at->isToday() => true,          // pengguna baru
    default                     => Lottery::odds(1, 100),   // 1% sisanya
});

Feature::define('paywall', fn () => config('toko.paywall_aktif'));
if (Feature::active('editor-baru')) {
    return view('artikel.editor-baru');
}

Feature::when('editor-baru',
    whenActive: fn () => view('artikel.editor-baru'),
    whenInactive: fn () => view('artikel.editor-lama'),
);

// Untuk pengguna tertentu
Feature::for($user)->active('editor-baru');
@feature('editor-baru')
    <x-editor-baru />
@else
    <x-editor-lama />
@endfeature
Route::get('/editor', ...)->middleware(EnsureFeaturesAreActive::using('editor-baru'));

Lottery::odds(1, 100) dievaluasi sekali per pengguna, lalu disimpan. Ini penting: tanpa penyimpanan, seorang pengguna bisa mendapat editor baru pada satu permintaan dan editor lama pada permintaan berikutnya โ€” pengalaman yang membingungkan dan bug yang mustahil direproduksi. Pennant menyimpan hasilnya, jadi keputusannya stabil.

Kenapa ini penting untuk aplikasi yang tidak boleh mati

Tanpa flagDengan flag
Rilis fitur = deployRilis fitur = balik sakelar
Fitur bermasalah = rollback penuhMatikan satu fitur; sisanya tetap jalan
Semua pengguna sekaligus1% dulu, amati, lalu naikkan
Cabang panjang yang sulit digabungKode masuk main lebih awal, dalam keadaan mati
Pemulihan hitungan puluhan menitPemulihan hitungan detik

Manfaat yang paling kurang disadari: cabang git jadi pendek. Tanpa flag, fitur besar hidup di cabang selama berminggu-minggu dan penggabungannya jadi peristiwa yang menakutkan. Dengan flag, kode digabung ke main setiap hari dalam keadaan mati โ€” konfliknya kecil, dan risikonya tersebar.

Mengelola

php artisan pennant:purge                 # bersihkan semua nilai tersimpan
php artisan pennant:purge editor-baru     # satu fitur saja
Feature::for($user)->activate('editor-baru');
Feature::for($user)->deactivate('editor-baru');
Feature::activateForEveryone('editor-baru');
Feature::deactivateForEveryone('editor-baru');       // โ† tombol darurat

// Muat sekaligus supaya tidak satu query per pemeriksaan
Feature::for($user)->loadMissing(['editor-baru', 'paywall']);

loadMissing() mencegah N+1 versi feature flag. Memeriksa lima flag di dalam loop yang berjalan untuk lima puluh pengguna berarti dua ratus lima puluh pemeriksaan. Muat semuanya di awal permintaan, dan biayanya jadi satu query.

Menguji

it('menampilkan editor baru saat fitur aktif', function () {
    Feature::define('editor-baru', true);

    actingAs($editor)->get('/editor')->assertSee('Editor Baru');
});

it('tetap menampilkan editor lama saat fitur mati', function () {
    Feature::define('editor-baru', false);

    actingAs($editor)->get('/editor')->assertSee('Editor Lama');
});

Uji kedua cabangnya. Flag yang hanya diuji dalam keadaan menyala berarti jalur mati tidak pernah diperiksa โ€” dan justru jalur itulah yang akan kamu andalkan saat terjadi masalah pukul dua pagi.

Kebersihan flag

Jenis flagUmurSetelahnya
Peluncuran fiturHari sampai mingguHapus flag dan kode lamanya
Uji A/BSampai eksperimennya selesaiHapus, pilih pemenangnya
Sakelar operasional (mis. matikan pencarian)PermanenSimpan, dokumentasikan
Fitur khusus pelangganPermanenIni sebenarnya izin, bukan flag

Flag yang tidak dibersihkan adalah utang teknis yang berbunga. Setiap flag menggandakan jumlah kemungkinan jalur kode; sepuluh flag berarti secara teori ada ribuan kombinasi yang tidak pernah ada yang menguji. Beri setiap flag peluncuran tanggal kedaluwarsa saat kamu membuatnya, dan perlakukan penghapusannya sebagai bagian dari pekerjaan fitur itu โ€” bukan sebagai pekerjaan terpisah yang tidak pernah dijadwalkan.

Latihan: bungkus satu fitur nyata dengan flag yang aktif untuk 10% pengguna, tulis tes untuk kedua cabangnya, lalu jalankan Feature::deactivateForEveryone() dan pastikan aplikasi kembali ke perilaku lama tanpa deploy apa pun.

Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.