独自実装したFeature Flagによるシステム移行

TVerでバックエンドエンジニアをしている水野といいます。

この記事はTVer アドベントカレンダー 2024の9日目の記事です。

8日目の昨日は @pikopiko_hammer さんによる 「Webディレクター目線でダークモード対応の思い出を振り返る」 でした。

今日は、睡眠時や仕事中以外はTVerで動画を見ているTVer大好きな私が、最近アサインされたプロジェクトについてお話しします。

はじめに

現在、私はTVerの一部システムの移行作業を行っています。短期間で移行できる規模ではなく、半年規模でいくつかのリリース日に分けた移行計画で対応しています。

移行計画の課題

いくつかのリリース日に分かれているため、次のリリース日までmainブランチへのマージができず、プルリクエストの残存期間が長くなってしまいます。その結果、コンフリクトが発生しやすくなるのと、大量の変更を一気にリリースしなければならないという課題がありました。これを避けるために、段階的なリリースができる仕組みが必要でした。

Feature Flagの導入

高機能なFeature Flagは必要なく、段階的なリリースができれば良かったので、簡易的なFeature Flagを独自実装しました。今回TVerにとって初めての試みだったので、その話を紹介したいと思います。

独自実装したFeature Flag

今回実装したFeature Flagは、機能単位でフラグを設定し、柔軟に管理できるようにすることを目的としています。

サンプルコード

まず、Feature Flagの機能を定義するためのenumを作成します。ここでは、ユーザー管理サービス(UserManagementService)のユーザー作成機能とユーザー更新機能を例にサンプルコードを書いてます。

type UserManagementServiceFeature int

// UserManagementService切り替えで動作に影響がある機能リスト
const (
    // UserManagementServiceのユーザー作成機能
    UserManagementServiceFeatureCreateUser UserManagementServiceFeature = iota
    // UserManagementServiceのユーザー更新機能
    UserManagementServiceFeatureUpdateUser
)

次に、Feature Flagの構造体を定義し、各機能がどの環境で有効かをリストで管理します。

type featureFlag struct {
    // Feature Flag対象機能のenum
    feature UserManagementServiceFeature

    // Feature Flag対象機能を有効にしたい環境のリスト
    enabledIn []string
}

// Feature Flagのリスト
var features = []featureFlag{
    {
        feature:   UserManagementServiceFeatureCreateUser,
        enabledIn: []string{"local", "development"},
    },
    {
        feature:   UserManagementServiceFeatureUpdateUser,
        enabledIn: []string{"local", "development", "production"},
    },
}

最後に、指定された機能が現在の環境で有効かどうかを判定する関数を実装します。

// Feature Flagのenumを受け取って、その機能が有効かどうかを返す
func IsEnabled(feature UserManagementServiceFeature, currentEnv string) bool {
    for _, f := range features {
        if f.feature == feature {
            for _, env := range f.enabledIn {
                if env == currentEnv {
                    return true
                }
            }
        }
    }
    return false
}

使用例

// アプリケーションコード
if IsEnabled(UserManagementServiceFeatureCreateUser, "development") {
    // ここにやりたい処理を書く
}

このコードでは、UserManagementServiceFeatureというenumを使って、ユーザー管理サービスの各機能を定義しています。featureFlag構造体は、各機能がどの環境で有効かをリストで管理します。IsEnabled関数は、指定された機能が現在の環境で有効かどうかを判定します。

できること

  • 機能 x 環境単位の細かい制御が可能

できないこと

  • デプロイなしでのFeatureFlagの切り替え

このようにして、機能ごとに細かい制御が可能となり、段階的なリリースや環境ごとの設定が容易になります。

最後に

TVerではこのように、運用保守のための開発だけでなく、ユーザーファーストでより良い視聴体験が得られるようにシステム移行を始め、さまざまなプロジェクトが進行しています。 現在進行中のプロジェクトの詳細を知りたい方は、ぜひカジュアル面談でお待ちしております。

recruit.tver.co.jp

明日は、 @datahaikuninja さんによる 「TVer広告プロダクト開発タスクのSREになってからの1年を振り返る」 です。明日もお楽しみに!