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"