All Articles

consume contents

Github の feature flag について

Github blog より

コードの中に feature flag 入れている
これは、デプロイ完了時点で全員 or 一部のアクターのみに有効になる
feature flag を無効にすることで該当機能のロールバックを数秒で済むようにしている

既存機能の回収の他に新機能開発でも feature flag を取り入れている 小さい単位で開発していくことが可能。そのプロジェクトに関わっている人間のみで feature flag を有効にし確認できる

  • レビューコストの最小化
  • 変更が小さいほど本番導入で導入でバグを起こしにくい
  • 長期間有効な機能ブランチを使用しないことで、開発中の他の機能との潜在的なマージの競合や衝突を回避できる

データモデルやテーブル変更など長くブロックされそうなものはメインPRとして出し
そこへ小さいPRをマージする

早くPRをマージしていくために、レビューの第一人者としてレビューに注力する人物を置いている

テスト方法

  • 開発環境では CLI から機能フラグを切り替えできる
  • 自動テストではコードの中で機能フラグの有効/無効を切り替えられる
  • CI

    • すべての機能フラグ無効にして実行
    • すべての機能フラグ有効にして実行
  • 本番環境ではクエリストリングで機能フラグの有効/無効を切り替えている

デプロイ戦略

  • Individual actors

    • ある機能に取り組んでいる従業員にフラグを立てたり、ある機能を試している顧客にフラグを有効にする
  • Staff shipping

    • 社員に対して機能を開放する
  • Early access maintainers or other beta groups

    • OSS のメンテナやその他のユーザに影響を与えるような重要機能を先に試してもらってフィードバックを得る
  • Percentage of actors

    • 指定した割合のアクターに対して機能を開放する
  • Dark shipping

    • クエリのパフォーマンス向上などの内部的な変更のためのもの。一定割合で機能が呼ばれるようにする。

これらの戦略は、すべてUIで管理されている。 新規フラグの作成・feature flag の出荷状況などメタデータが一通り見れる。

Go の場合

build tag でコンパイルするファイル変えられる

package main

import (  
    "fmt"
    "github.com/smith-30/tagsample/entity"  
)
func main() {  
    fmt.Printf("%#v\n", 1)
    u := entity.User{}  
    u.Hello()  
}
// +build v2.0

package entity

import "fmt"

type User struct {
}

func (a User) Hello() {
    fmt.Printf("%#v\n", "v2.0")
}
// +build v2.1

package entity

import "fmt"

type User struct {
}

func (a User) Hello() {
    fmt.Printf("%#v\n", "v2.1")
}
$ go run -tags v2.0 ./main.go
1
"v2.0"

$ go run -tags v2.1 ./main.go
1
"v2.1"