Laravel Pennant で始めるフィーチャーフラグ管理

この記事は個人ブログと同じ内容です


はじめに

システム開発において、新機能のリリースは常にリスクを伴います。

  • まずは社内メンバーやベータテスター等の一部のユーザーで動作確認を行いたい
  • 機能を段階的に展開して、ユーザーからのフィードバックや負荷状況を見ながら本格公開したい
  • 長期間にわたる開発でも継続的に main ブランチにマージして、コードの乖離を防ぎたい
  • やむを得ず金曜日にリリースはするけど、週明けまで機能は無効にしておきたい

このような状況は、開発現場ではよくあることです。

しかし、従来のシンプルなリリースの仕組みでは「デプロイ=機能オン」になってしまい、いきなり全ユーザーに機能が公開されてしまうことも少なくありません。 そのような方法では、不安を抱えたまま、一か八かのお祈りリリースをすることになりがちです。 また、不具合があった場合に全ユーザーへ影響が及ぶリスクや、デプロイのタイミングと機能公開のタイミングを分離できない不自由さがつきまといます。

そこで役立つのがフィーチャーフラグ(Feature Flags)です。 フィーチャーフラグを利用することで、デプロイとリリースを分離したり、段階的な機能展開や特定のユーザーグループにのみ新機能を提供することが可能になります。

Laravel Pennant は、これらの課題を解決する Laravel 公式のフィーチャーフラグパッケージです。 この記事では、Laravel Pennant の基本的な使い方をご紹介していきます。

Laravel Pennant の概要

Laravel Pennant は、Laravel 10以降で利用できる公式のフィーチャーフラグパッケージです。 シンプルかつ軽量で、Laravel のエコシステムに統合されているため、開発者にとって利用しやすいツールとなっています。

インストール

Laravel Pennantのインストールは非常に簡単です。 Composer と Artisan コマンドを使って、数ステップで導入できます。

# Laravel Pennant をインストール
$ composer require laravel/pennant

# Pennant の設定ファイルとマイグレーションを公開
$ php artisan vendor:publish --provider="Laravel\Pennant\PennantServiceProvider"

# マイグレーションを実行してフィーチャーフラグを保存するテーブルを作成
$ php artisan migrate

基本的な使い方

フィーチャーフラグの定義

フィーチャーフラグは Feature ファサードを利用して定義します。 サービスプロバイダの boot メソッドに追加しましょう。(将来的にフラグが増えることを考慮し、FeatureServiceProvider のような専用のサービスプロバイダを作成するのがおすすめです) 今回は new-dashboard というフィーチャーフラグを定義し、ユーザーが管理者である場合に有効にします。

use Laravel\Pennant\Feature;
use App\Models\User;

public function boot()
{
    Feature::define('new-dashboard', fn (User $user) => $user->isAdmin());
}

コントローラーでの利用

コントローラー内では Feature::active() メソッドを利用します。

use Laravel\Pennant\Feature;

class DashboardController extends Controller
{
    public function index()
    {
        if (Feature::active('new-dashboard')) {
            return view('dashboard.new');
        }
        
        return view('dashboard.old');
    }
}

Blade テンプレートでの利用

Blade テンプレートでは @feature ディレクティブを利用できます。

@feature('new-dashboard')
    <div class="new-dashboard">
        <!-- 新しいダッシュボードUI -->
        <h1>新しいダッシュボードへようこそ!</h1>
    </div>
@else
    <div class="old-dashboard">
        <!-- 既存のダッシュボードUI -->
        <h1>ダッシュボード</h1>
    </div>
@endfeature

フィーチャーフラグをチェックした結果はストレージに保存され、次回同じユーザーの同じフィーチャーフラグをチェックする際は、ストレージから取得されます。 ストレージのドライバは、データベースへ永続的に保存する database ドライバと、メモリ内の配列へ格納する array ドライバが用意されており、デフォルトでは database ドライバが利用されます。

基本的な使い方は以上です。 複雑な設定などは必要なく、とても簡単にフィーチャーフラグを導入でき、Laravel の他の機能と同様の感覚で利用することができます。

実践的な活用例

段階的リリース

新機能を全ユーザーに一斉公開するのではなく、段階的にリリースする例を見てみましょう。

Feature::define('new-dashboard', function (User $user) {
    // 管理者とベータテスターは有効
    if ($user->isAdmin() || $user->isBetaTester) {
        return true;
    }
    
    // 一般ユーザーは10%の確率で有効
    return $user->id % 10 === 0;
});

この設定により、管理者とベータテスターには新しいダッシュボードが表示され、一般ユーザーの10%にも段階的に公開されます。 より細かい制御を行いたい場合は、パーセンテージベースの段階的リリースも可能です。

Feature::define('new-dashboard', function (User $user) {
    // 2025年7月1日を基準に1日あたり2%ずつ段階的にロールアウト
    $startDate = Carbon::parse('2025-07-01');
    $passedDays = max(0, now()->diffInDays($startDate));
    $rolloutPercentage = min(100, $passedDays * 2);
    
    return ($user->id % 100) < $rolloutPercentage;
});

環境別の機能制御

開発・ステージング・本番環境で異なる機能を制御する例です。

Feature::define('new-dashboard', function () {
    return app()->environment(['local', 'staging']);
});

Feature::define('api-rate-limiting', function () {
    // 本番環境でのみレートリミットを有効化
    return app()->environment('production');
});

ミドルウェア

Pennant はミドルウェアも用意しています。

use Illuminate\Support\Facades\Route;
use Laravel\Pennant\Middleware\EnsureFeaturesAreActive;

Route::get('/api/servers', function () {
    // ...
})->middleware(EnsureFeaturesAreActive::using('new-api', 'servers-api'));

指定したフィーチャーフラグのいずれかが現在のユーザーに対して無効である場合、400 Bad Request レスポンスを返します。

カスタムスコープの作成

ユーザー以外のモデルでもフィーチャーフラグを利用できます。

use App\Models\Team;

Feature::define('team-analytics', function (Team $team) {
    // チームのメンバー数が5人以上の場合、チーム分析機能を有効化
    return $team->members()->count() >= 5;
});

フラグを呼び出す際は for の引数にモデルを渡します。

if (Feature::for($team)->active('team-analytics')) {
    // チーム分析機能を表示
}

デフォルトのスコープをカスタマイズすることも可能です。

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Auth;
use Illuminate\Support\ServiceProvider;
use Laravel\Pennant\Feature;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Feature::resolveScopeUsing(fn ($driver) => Auth::user()?->team);
    }
}

動的な値の管理

フィーチャーフラグには true/false の状態だけでなく、動的な値を設定することも可能です。

// ユーザーが premium プランに加入している場合、100名までチームメンバーを登録できる
Feature::define('team-member-limit', function (User $user) {
    return $user->isPremium() ? 100 : 10;
});

設定した値は value メソッドで取得できます。

$limit = Feature::value('team-member-limit');
if ($team->members()->count() < $limit) {
    // 新しいメンバーを追加できる
} else {
    // 上限に達しているので追加できない
}

フィーチャーフラグの削除

フィーチャーフラグを削除する Artisan コマンドも用意されています。

# 1つのフィーチャーフラグを削除
$ php artisan pennant:purge new-dashboard

# 複数のフィーチャーフラグを一度に削除
$ php artisan pennant:purge new-dashboard team-analytics

# 特定のフィーチャーフラグを除外して削除
# この例では new-dashboard と team-analytics を除いたすべてのフィーチャーフラグが削除される
$ php artisan pennant:purge --except=new-dashboard --except=team-analytics

まとめ

Laravel Pennant の主な利点

  • 簡単な導入: Composer でのインストールから定義まで、わずか数ステップで利用開始できる
  • Laravel との統合: ファサード、Blade ディレクティブ、ミドルウェアなど、Laravel らしい使い方が可能
  • 柔軟なスコープ: ユーザー、その他のモデル、環境など様々な単位での制御が可能
  • 動的な値の管理: フィーチャーフラグに動的な値を設定し、柔軟な機能制御が可能
  • 運用しやすさ: Artisan コマンドによる管理機能もサポート

新機能のリリースに不安を感じている開発チームや、段階的な機能展開を検討しているプロジェクトにとって、Laravel Pennant は非常に心強いツールとなるでしょう。 フィーチャーフラグを活用することで、開発チームは自信を持って新機能の開発・デプロイを進め、ユーザーへの価値提供を最大化することができます。

今後ますます複雑化・高速化する開発サイクルの中で、フィーチャーフラグは欠かせない要素となり得そうです。 Laravel Pennant を使って、より柔軟で安全な開発ライフサイクルを構築していきましょう。

📚 他の記事一覧はこちら
https:https://techblog.roxx.co.jp/