2019-04-27

Feature Toggleについて調べてみた

前から何回か興味を持ってるんだけど、ちょっとまとめて調べながら思ったことをザクザク吐き出しておくよ。

今のところ考えるちょうどいい使い方

いろんな使い方ができると思うんだけど、リリースサイクルの都合ではなく

  • どんな機能が現在のプロダクトで切り替え対象となっているのかの可視化 ( admin panel )
  • サーキットブレイカー

の意味で使うのを前提にしつつ、

  • カナリアリリース
  • A/Bテスト

にも導入していく、くらいの感じだとよさそう。

大げさな感じがするかもしれないけど、ちゃんと考えて入れないとややこしくなるだけだなと感じているので。

雑な言い方すると feature toggle って global な状態分けの if ブロックなわけで、実際、特別な記法なんかなくたって環境変数と if だけで実現可能なわけですよ。でもそれって実装側からもプロダクトオーナー側からも実態が見えにくくなるだけでいいことないので、なぜそれが有用なのか?を説明できる状態、機能を実現してなきゃダメだよな、と思うわけです。

基本的には避けられるものなら避けるべき

全体的に feature toggle でリリース管理していくのは危険な感じがする。クライアントサイドやアプリでは、時限リリースなど、マーケットが挟まることで uncontrollable になってしまう部分には使わざるを得ない場合があると思うけど。

普通は 追加するより消す方が怖い ので、消されないで放置されるフラグが増え続けることは容易に想像できる。リリースサイクルのコントロールよりも duration や user segmentation などのメリットを重視してやった方がよさそう。

また、サーキットブレイカーのような、消したらダメな機能もある。そういう違いが admin panel 上で可視化できるとよさそう。

※ 小さいプロダクトの立ち上げ期で次々 feature toggle で出し入れしなきゃいけない状況はあり得るっちゃああり得るけど、それは技術的に解決するものではなく WHY に立ち向かっていない状況のように見える。実装は同時並行で行なって短時間で検証をくり返す、言葉で言うとかっこいいけど、聞いただけで事故る可能性が高い(同時並行のくだりのあたり)し、本当にスモールな時って、そもそも多人数で同時並行開発できないので、feature toggle とか考えようがなくね?という気もする。まぁ、もしかしたら自分の知らない魔法の世界があるのかもしれない。

SaaS

https://launchdarkly.com/pricing/

75 USD/mo

ちょっと高いかなー。でも機能がすごい。これ全部実装するのは確かに大変。user の segmentation も webhook もみんなある。ユーザーベースの拡大がビジネスチャンスの拡大に繋がるプロダクトにはよさそう。

Admin Panelとスピードと履歴が重要

Admin Panel はかなり重要な要素になると思うんだけど、真面目に作るとそこそこ重たいので、複数のサービスをまたいで使えるとよさそう。というかイマドキはまたげないときつそう。サービスをまたいで feature toggle を実現するには CDN でスピードを稼ぎやすい仕組みが重要な気がする。例えばサーバが JP にあったり US にあったりするはず。1

そして admin panel 上の操作は履歴を残すことが重要。なんなら同時に通知を飛ばすなどがあってもよいかもしれない。(PubSub でいいか?)

feature の追加、削除はどこで?

  • admin panel で追加、削除すると実態(実装)と乖離する可能性がある
  • 各サービス(アプリ)側で追加、削除の order が出せるのが理想的?
    • 追加、削除の履歴はコードの VCS 側に残る形か

調べてみた

http://featureflags.io/ より。先の LaunchDarkly 提供。

気になっているのは、

  • backend storage はどうするのか?
  • admin panel はどうするのか?
  • frontend ではどうしているのか?

frontend で feature toggle はー、いるんだろうか? Node.js でバックエンドならまだしも。JSアプリケーションを初期化する cell をバックエンドで rendering するかしないかで切り替える方が素直な気がするなぁ。

flip gem

参考になる。

https://github.com/pda/flip

Admin Panel までコミで、ちょうどいい感じがする。

feature gem

DSL 部分の実装がよさげ。

https://github.com/mgsnova/feature

  • separeted repository
    • in-memory or redis or static YAML or ActiveRecord
  • cache されるし force refresh! もできる

Repository が分離しているのは非常によい。refresh! もできるので、例えば Central Repository を分離しておいて Central Repository に Admin Panel を設置、Central Repository から必要な情報を取得して Repository に保存しつつ、Central Repository が更新されたら PubSub で Repository を更新する、といったことが可能なはず。

Unleash npm

こりゃすごい。

https://unleash.github.io/

  • Admin Panel ( Server ) と Client SDK を持つ
    • Java / Node.js / Go / Ruby / Python / .NET
  • Heroku-ready
  • storage は PostgreSQL 固定?
  • userId とカナリアリリースっぽいものに対応

これすごいな。 LaunchDarkly の OSS 版ぽい感じ。ただ、都度アクセスが必要になりそうなので、cache がないとサーバの位置によってはちょっとつらそう。

bandiera gem

監視体制が参考になる。

https://github.com/springernature/bandiera

  • サーバサイドは Ruby
  • Client SDK は Ruby / PHP / Node.js / Scala

これ自体が中央のサーバになるので監視ものがいろいろ最初から考慮されている。

chanko

https://github.com/cookpad/chanko

Rails アプリの中で toggle する機能に関するコードの置き場所を安全に分離する DSL. user segmentation 対応。

確かにねぇ、View 以外も分けたいとなった時にコードの置き場所に困るのは事実。

rollout gem

https://github.com/FetLife/rollout

API サーバも Dashboard も作ってあって真面目にやってる感じがする反面、DSL や Redis 固定の部分はイマイチかなぁ。

flagship gem

https://github.com/yuya-takeyama/flagship

  • dependency free
  • flagset を DSL で定義できる
    • この中でもさらに条件分岐できる
    • ちょっと難し過ぎる気がする
  • no storage

admin panel を別立てにできなさそうに見える。

少なくとも DSL での定義を通過する必要があるので、deploy / restart は必要な気がする。環境変数を参照する部分は反映し直しやすいけど、それでも restart は必要? でもそれだと目的を達成できないような気がするので何かを見落としているかも。

feature-toggles gem

https://github.com/LouisSayers/feature-toggles

YAML storage 固定

まぁ YAML dump する script があれば admin panel を別立てにすることもできるけど、YAML storage ってことは deploy し直さないといけないので、そこはイマイチ。feature gem でいいかな。

参考

  1. 主に Heroku の利用が視野に入っているため。 

About

例によって個人のなんちゃらです

Recent Posts

Categories

Tool 日々 Web Biz Net Apple MS ことば News Unix howto Food PHP Movie Edu Community Book Security Text TV Perl Ruby Music Pdoc 生き方 RDoc ViewCVS CVS Rsync Disk Mail FreeBSD Cygwin PDF Photo Zebedee Debian OSX Comic Cron Sysadmin Font Analog iCal Sunbird DNS Linux Wiki Emacs Thunderbird Sitecopy Terminal Drawing tDiary AppleScript Life Money Omni PukiWiki Xen XREA Zsh Screen CASL Firefox Fink zsh haXe Ecmascript PATH_INFO SQLite PEAR Lighttpd FastCGI Subversion au prototype.js jsUnit Apache Trac Template Java Rhino Mochikit Feed Bloglines CSS del.icio.us SBS qwikWeb gettext Ajax JSDoc Rails HTML CHM EPWING NDTP EB IE CLI ck ThinkPad Toy WSH RFC readline rlwrap ImageMagick epeg Frenzy sysprep Ubuntu MeCab DTP ERD DBMS eclipse Eclipse Awk RD Diigo XAMPP RubyGems PHPDoc iCab DOM YAML Camino Geekmonkey w3m Scheme Gauche Lisp JSAN Google VMware DSL SLAX Safari Markdown Textile IRC Jabber Fastladder MacPorts LLSpirit CPAN Mozilla Twitter OpenFL Rswatch ITS NTP GUI Pragger Yapra XML Mobile Git Study JSON VirtualBox Samba Pear Growl Mercurial Rack Capistrano Rake Win RSS Mechanize Sitemaps Android JavaScript Python RTM OOo iPod Yahoo Unicode Github iTunes God SBM friendfeed Friendfeed HokuUn Sinatra TDD Test Project Evernote iPad Geohash Location Map Search Simplenote Image WebKit RSpec Phone CSV WiMAX USB Chrome RubyKaigi RubyKaigi2011 Space CoffeeScript Nokogiri Hpricot Rubygems jQuery Node GTD CI UX Design VCS Kanazawa.rb Kindle Amazon Agile Vagrant Chef Windows Composer Dotenv PaaS Itamae SaaS Docker Swagger Grape WebAPI Microservices OmniAuth HTTP 分析基盤 CDN Terraform IaaS HCL Webpack Vue.js BigQuery Middleman CMS AWS PNG Laravel Selenium OAuth OpenAPI GitHub UML GCP TypeScript SQL Hanami Document SVG AsciiDoc Pandoc DocBook Develop Jekyll macOS Node.js Vite Heroku Transformer AI Data Cloud Wasm