【Unleash】Feature Flagサービスを利用してみた話

# はじめに
とあるプロダクト開発をしていると、機能や処理単位において、
この人には表示させたいけどこの人には表示させたくない、、とか
ほぼ同じ画面だけど一部だけ文字が違うから新しい画面作らなきゃ、、とか
細かな表示/非表示の切り替えが生じますよね。
そんな時に見つけた機能Feature Flagについて、掘り下げて調べてみましたので共有したいと思います。

# Feature Flagとは？
Feature Flagと聞いて皆さんどんな機能かご存知でしょうか。
Feature Flagとは、簡潔にいうと、コード変更することなく動的にシステムを変更できる手法を示します。

最もシンプルな実装例でいえば、
```python
if (flag) {
  new_feature();
} else {
  old_feature();
}
```

こんな感じ。外部から`flag`が切り替えれば、機能が変更できる。と言うことです。
この考え方は多くのプロダクト開発に導入されています。

# Feature Flagのメリット/デメリット
Feature Flagを利用することのメリット/デメリットについて考えてみます。

### メリット
1. **デプロイとリリースの分離**  
   - コードのデプロイと機能のリリースタイミングを分けられる
   - リリース中に不具合が発生した場合でも、迅速にロールバックが可能

2. **環境間での変更を簡単に制御**  
   - 開発環境、ステージング、本番環境で異なる設定を適用しやすく、柔軟な運用が可能

3. **段階的リリースの容易化**  
   - 公開範囲を絞ることで、影響を最小限に抑えながら機能をリリース可能（カナリアリリースとも）
   - 本番環境での限定的なテストが実現できる
   - ユーザーセグメントごとのA/Bテストが容易に実施できる

### デメリット
1. **コード量の増加**  
   - 条件分岐やフラグ管理ロジックが増え、コードが複雑化する

2. **フラグの管理コスト**  
   - Feature Flagの設定やメンテナンスが運用負荷として増加する 
   - 使用が終了したフラグを適切に削除しないと、技術的負債として蓄積する恐れがある

3. **テストの複雑化**  
   - Feature Flagの組み合わせにより、テストケースが増加し、網羅的なテストの実施が難しくなる

これらデメリットへ対策として、フラグの管理方法のツールやルールが大切になるのがわかります


# Feature Flagの種類について
一言でFeature Flagといっても、その用途や目的によってさまざまな形で利用されます。
では、どのような目的で利用したいのか再度考え直してみましょう。

Feature Flagは大きく分けて4つに分類することができます。

<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1827273/560af05e-ae7a-b842-b802-3549110d925d.png">

### 1. **Release Toggles（リリース制御）**
**目的:** デプロイとリリースを分離するために使用
未完成の機能を公開されないようにしたりするために短期的に利用するフラグ
完成後はフラグを削除する。

### 2. **Experiment Toggles（実験制御）**
**目的:** A/Bテストや段階的なユーザー検証のために使用
機能をパフォーマンスを計測するため、中長期的に利用するフラグ
計測後はフラグを削除する。

### 3. **Ops Toggles（運用制御）**
**目的:** システムの運用を柔軟に管理するために使用
負荷を減らしたい時や影響度が不明な機能を提供する場合、すぐに無効化を可能とするために利用するフラグ
影響が明確になれば削除、長期利用が必要な場合のみ管理される。

### 4. **Permissioning Toggles（権限制御）**
**目的:** 特定のユーザーやグループにのみ機能を提供するために使用
管理者が特定ユーザーへ異なる機能を提供するために利用するフラグ
恒久的に利用される。


それぞれの目的に合わせ、フラグのライフサイクルを考慮するのが重要となります。
参考: [Feature Toggles - Martin Fowler](https://martinfowler.com/articles/feature-toggles.html)


# Feature Flagを管理するサービスについて

先ほどFeature Flagのデメリットに述べたようにFeature Flagを運用するには少し手間がかかります。
もちろん自作で管理画面等を作成し管理することもできますが、便利な管理ツールも存在しています。

今回は詳細な調査や各ツールの比較は省略しますが、代表的なツールには以下があります：
- **LaunchDarkly**  
  商用サービスで高機能。大規模なプロジェクト向け

- **Flagsmith**  
  オープンソースと商用プランを提供。柔軟な拡張性が魅力

- **Unleash**  
  完全オープンソースで無料利用が可能。シンプルで導入しやすい

参考: [Feature Flagの管理ツール比較](https://codezine.jp/article/detail/14662)

今回は、オープンソースで展開されており、無料で利用できる**Unleash**を採用してみます。

## Unleashについて
Unleashはオープンソースのフィーチャーフラグ管理ツールです。
具体的なUnleashの仕組みについてはここでは省略します。
参考:[公式ドキュメントUnleash introductory overview](https://docs.getunleash.io/understanding-unleash/unleash-overview)

ここでは、Unleashが提供している機能について、大きく分けて4つに分けてご紹介します。

1. すべてのユーザーへリリースする
2. 指定ユーザーへリリースする
3. 段階的にリリースする
4. 複数値を定義し、リリースする

それぞれの機能をデモ版で確認しながら紹介していきます。

https://www.getunleash.io/interactive-demo

Email入力のみで簡単にunleashのデモ環境へアクセスできます。
アクセスするとダッシュボード上で様々な情報が確認できます。
（さまざまな人がアクセスし、プロジェクトやフラグを作成可能となっているためごった返しではありますが）

まずはunleashより[プロジェクト名：Demo Application](https://app.unleash-hosted.com/demo/projects/demo-app?limit=25&favoritesFirst=true&sortBy=createdAt&sortOrder=desc)を表示してみます。

<img width="100%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1827273/d21d8f78-3b32-3d9f-7411-e7ec880f9c8b.png">

unleashはProjectという単位でアプリケーションのFeatureFlagを管理します。
実際にダッシュボードで確認してみると、Feature flagsがあることを確認できます。
すでダッシュボードより作成されているフラグ（＋組み込まれているサイト）がありますね。切り替えてみましょう。

unleashのDemoページから操作できるサイトがあるので、実際の変化を見ながら操作してみましょう。

https://hello.unleash.run/?utm_source=Demo_instance&utm_medium=OpenLink&utm_campaign=Unleash

---

### 1. すべてのユーザーへリリースする
ダッシュボートの一覧より、dev列にあるスイッチをONにしてみましょう。

<img width="100%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1827273/e032589c-9bad-cf60-b56b-1edf698f8280.png">

すると、、？

<img width="100%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1827273/9cf455eb-2ea9-4877-6ff9-72a99d6248df.png">

Demoページがｽｯと切り替わり、コンポーネントが追加されているではありませんか！
ボタン1つで簡単にリリースされることが確認できました。

参照：[公式ドキュメントActivation Strategies](https://docs.getunleash.io/reference/activation-strategies#standard)

### 2. 指定ユーザーへリリースする
ターゲットを絞った切り替えも可能です。
ダッシュボードの一覧より、Feature flag詳細画面へ遷移してみましょう。

<img width="100%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1827273/15d9fdc1-4d08-965e-548a-17517b896916.png">

StrategyがFeature flagの反映条件を指します。
dev環境配下のAdd strategyから条件追加としてID設定を行います。

<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1827273/fbaad4e5-b72b-805c-4bd6-e05677a39f52.png">

条件は複数IDを追加したり、完全一致や大小などの設定も可能です。
今回は自身のIDを指定してみましょう。

すると、、？

<img width="100%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1827273/631353a5-94e6-394c-8e07-7f8d4de9b3f5.png">

色が変化しているのがわかります、、！
他タブで再度Webサイトを開き、異なるIDを持つ画面では変化していないのも確認できました。

参照：[公式ドキュメントActivation Strategies](https://docs.getunleash.io/reference/activation-strategies#userids)

### 3. 段階的にリリースする
ターゲットをIDなど固定ユーザーではなく、全体のパーセンテージを指定することで反映範囲を設定することもできます。
一覧より、Feature flag詳細画面へ遷移してみましょう。
<img width="100%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1827273/570ce68e-a0a9-b6e7-86d4-f06117fd6151.png">

同様にdev環境配下のAdd strategyから条件追加として展開条件設定を行います。

<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1827273/17f4a65b-3abc-1cb3-3a97-e908c5c91660.png">

指定した範囲内であると表示され、範囲外であると表示されません。
今回はこの範囲内に含まれたとします。

すると、、？

<img width="100%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1827273/3f75ee93-10ea-d65e-8244-da2ef6da32a2.png">

チャット用アイコンが表示されました、、！
設定するパーセンテージを変更することで、表示/非表示が変わることが確認できました。

参照：[公式ドキュメントActivation Strategies](https://docs.getunleash.io/reference/activation-strategies#gradual-rollout)


### 4. 複数値を定義し、リリースする
ここまではFeature flagによるON/OFFの切り替えでした。他にも、複数変数を渡し、リリースすることもできます。

<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1827273/fb39db23-c594-2021-b196-2422cf124319.png">

今回はVariants Nameを`color`、Valueを`orange`とします。
すると、、？

<img width="100%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1827273/03adb51f-3544-8cbc-8156-336020db9862.png">

指定したValue値に基づいて色が変化しました、、！
他にも`red`や`black`など値の変化でボタンの色が、変わることが確認できました。

参照；[公式ドキュメントStrategy Variants](https://docs.getunleash.io/reference/strategy-variants)


## ローカル環境構築
デモ環境にてunleashダッシボード上での操作でFeature Flagの管理を確認することができました。
続いて、ローカル環境でのUnleash、および自身のWebアプリへのFeature Flagの組み込みについて実装してみます。

### Unleash環境構築
**前提条件**
- Gitがインストール済み  
- Docker環境が構築済み（ここではRancherDesktopを利用しています）

参考：[公式ドキュメントQuickstart - Unleash Documentation](https://docs.getunleash.io/quickstart)

---
1. Gitリポジトリをクローンする
    ```bash
    git clone https://github.com/Unleash/unleash-docker.git
    ```
    <img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1827273/2fc56e7f-b37a-aa44-0ac1-5ff144054a9f.png">

2. クローンしたフォルダへ移動
    ```bash
    cd unleash
    ```
3. コンテナ起動
    ```bash
    docker compose up -d
    ```
    ※`-d`オプションを付けることで、コンテナがバックグラウンドで実行されます
    <img width="100%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1827273/2d3eb83d-f04c-aa54-fdf7-5c5ebe50e60f.png">

4. 起動！！
    以下URLへアクセスします。ポート番号は`4242`です。
    http://localhost:4242

    <img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1827273/e3b1ed35-02b9-7558-7f14-4733ec4125cc.png">

5. Unleashダッシュボードへログイン
    ログイン画面が表示されるので、以下認証情報でログインします。
    username: `admin`
    password: `unleash4all`


### アプリケーションへのUnleash組み込み
Unleashのダッシュボートより、Feature Flagを作成し、SDK接続してみましょう。

ご自身の接続したいアプリケーション先を確認ください。
参照：[公式ドキュメント SDK概要](https://docs.getunleash.io/reference/sdks#server-side-sdk-compatibility-table)

**前提条件**
- Reactアプリにて実装

:::note info
最近はCRAは非推奨なのですよね。今回Viteを利用して作成しました。
共有いただいた参考先：[【React】CRAとVite比較まとめ【初学者】](https://qiita.com/rummy_p/items/35ac70fbbe854749a195)
:::

1. Feature Flagを作成する
    Unleashのダッシュボードからデフォルトプロジェクトに移動し、Feature Flagを作成してます。
    
    <img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1827273/616137ca-028a-b7d3-c155-3dae451264f6.png">
    
    任意のフラグ名と、詳細を記載し作成します。

    <img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1827273/e120ab63-649e-b96d-29a1-4243dccdf2a5.png">

2. SDK接続する
    接続する先を選択します。今回はReactを選択します。
    
    <img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1827273/2839c5b0-b09c-aed9-ca24-f88fe20df4f7.png">
    
    こちらで接続例が出てくるので、そちらを元に実装していきます。

3. フロントエンドへ組み込む
    3.1　初期処理
    ```typescript:main.tsx
    import { FlagProvider } from "@unleash/proxy-client-react";
    import React from "react";
    import { createRoot } from "react-dom/client";
    import App from "./App";
    
    const config = {
      url: "http://localhost:4242/api/frontend/",
      clientKey: "default:development.unleash-insecure-frontend-api-token",
      refreshInterval: 5,
      appName: "default",
    };
    
    createRoot(document.getElementById("root")!).render(
      <React.StrictMode>
        <FlagProvider config={config}>
          <App />
        </FlagProvider>
      </React.StrictMode>
    );
    ```
    3.2 アプリケーションにFeature Flagを実装
    今回は簡潔な実装であり、ページングをしないので、直接Appに記載していきます。
    ```typescript:App.tsx
    import { useFlag } from "@unleash/proxy-client-react";
    import "./App.css";
    
    function App() {
      const enabled = useFlag("Feature1");
      return <>{enabled && "Flag is enabled"}</>;
    }
    
    export default App;
    ```
    作成したフラグ名から情報を取得します。
    ここではフラグONの場合は、メッセージを表示。OFFの場合は表示されないような実装をしています。
    
    動作イメージはこんな感じ。チェックの切り替えだけでリアルタイムに動作を確認できます。
    ![2024-12-1210.13.11-ezgif.com-video-to-gif-converter.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1827273/e644c668-5f6d-356e-9e98-c70e71ba4668.gif)
    
    組み込みはとってもシンプルで簡単ですね。
    Variantの組み込み方法や他の実装方法は以下を参照ください。
    参照：[公式ドキュメント](https://docs.getunleash.io/reference/sdks/react)

---
初期処理内では、Unleashへ接続に必要な情報を設定します。
configの設定は接続する環境に応じて変更します。

- url(必須)
UnleashインスタンスへのAPIURLです。
サーバサイドの場合`http://localhost:4242/api/`
クライアントの場合`http://localhost:4242/api/frontend`
localhost部分は実際にデプロイ先のドメインやIPアドレスに置き換えてください。

- clientKey(必須)
UnleashのAPIキーとなります。
APIキーは以下の形式で設定します
`{プロダクト名}:{接続環境}.{APIトークン}`
ローカル環境からのアクセスの場合例：
`default:development.unleash-insecure-frontend-api-token`

    本番環境などのデプロイ先から接続する場合、別途APIトークンを取得する必要があります。
    ダッシュボートのAdmin＞API accessへ遷移し、新規APIトークンを発行します。
    任意のトークン名を設定します。
    接続SDKと環境先を選択し、トークンを発行してください。
    <img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1827273/bb86866e-129c-c2ab-694a-0baec047c49d.png">
    
- appName(必須)
接続したいアプリケーション名となります。
接続先を認識するためのみで利用されます。

- refreshInterval(任意)
フラグ状態を再取得する間隔時間です。
秒単位で設定できます。


このようにUnleashは柔軟なFeature Flag管理が可能で、簡単にアプリケーションに組み込むことができるとがわかりました。

## まとめ
今回はFeature Flagについて学び、その中の管理サービスUnleashの機能と環境構築を行いました。組み込みも簡単ですし、リアルタイムで変更が確認できるのはとっても良いなと思います。
実装方法についてあまり深掘りできませんでしたが、UnleashのDemoアプリから機能について触りながら理解できたので、自分の開発にてこういうのができそう、こういう管理ができそう、など実運用できそうだなと思いました。
ぜひみなさんの開発にてお役立てください。これからも様々な分野で勉強、発信していきます〜！