Remote ConfigはFirebaseファミリーの1つ

red_fat_daruma氏:よろしくお願いします。今日のアジェンダは、まず「Remote Configって何なの?」っていうところをサラッとやります。それから、「どうやって使えばいいんだっけ?」「そもそもREST APIが公開されたんですけど、それで何ができるようになるんだっけ?」っていうところと、あと、僕がGemを作ったので、それについて話そうと思います。

イントロダクションについては、先月末まで無職だったこともあって、話すことがないので省略します。

Remote ConfigはFirebaseファミリーの1つですね。

ストアとかを経由しないでアプリのアップデートを配信して、外観や挙動を変えることができます。今のところ、これだけ使うのであればフリープランでいけます。

どういう時に使うのかというと、季節柄のプロモーションとか、コンポーネントコントロールとかに使えます。ただ、デバイスの時間に依存しないので……。みなさんエンジニアなのでやったことあると思うんですけど、時間を勝手にいじって、がんばってなんか変な機能を出すみたいな、そういうところはできなくなったりします。

あとはABテストに使ったり、ユーザーセグメントに切ってその値をどんどん配信していったり、という用途があります。

もちろんオフィシャルでクライアントライブラリが用意されているんですが、AndroidとiOSで、Webアプリにはありません。3つの機能からなっています。

1つ目はサーバーからconfigを取ってきて、それをキャッシュするという機能。2つ目はキーがなかった時に、デフォルトバリューを使うという機能。3つ目は、そのキーに関連づけられた値を返すという機能ですね。

なので、GET-onlyのKVSクライアントにキャッシュシステムが入ったようなものが、オフィシャルのクライアントライブラリの役割になります。

Web UI editorの課題

クライアントの設計外観はどうやるかというと、デベロッパーは「Remote Config Object」っていうところしか触らないです。

その裏側に「Active Config」っていうRemote Configがサーバーから取ってきたデータがあります。そのActive Configと、デベロッパーが設定した「Default Config」をうまく見ていって、一層手前にあるデータレイヤーが返してくれます。それをRemote Config Objectが取っていくようなかたちになっています。

これはすごくいいです。フェッチするタイミングとかは自分たちでやるんですけど、キャッシュとかも全部やってくれるし、基本的にはデータの一貫性も保持してくれる。だから面倒くさいことはやってくれるんですよね。ただ、ただのReaderだから、要は書き込みとかそういう機能はないので、Remote Configをマネジメントしようと思った時には、残念ながら使えません。

では、「今まで書き込みたい時ってどうしてたんだっけ?」というと、WebのUI editorがあります。今もなくなってないです。編集した後に「PUBLISH CHANGES」というボタンを押すと、ユーザーに対して変更が直ちにパブリッシュされます。正確には、各デバイス上にキャッシュタイムがあるので、「直ちに」っていうのはちょっと語弊があるかもしれませんが、動作上、速攻で配信されます。

今はけっこうリッチなUIになったんですけれども、ただ、バリューに対するバリデーションがない。例えば、僕はもともとQuipperにいまして、Remote Configで広告っぽいものを作ってたんですよね。JSONを入れて、それをフェッチしてきて、スライドショーっぽくするみたいな。なので、そういうJSONを入れる時にバリデーションがないと、「そもそもValidなJSONだっけ?」みたいなところをがんばらなきゃいけなくて、ちょっとだるいですね。

あと、Seleniumとかを使えばできるのかもしれないんですが、WebのUI editorなので自動でアップデートができません。

あとは編集した後に「PUBLISH CHANGES」っていうボタンを押さなきゃいけないんですけど、時々忘れて……。 俺、かなり忘れるんですよね。1個の値だけを変える時に、だいぶ忘れて。マネージャーから「この機能をリリースするからtrueにしてくれ」って言われて、trueにした後、満足してそのままタブを閉じるみたいなことをよくやってたので、これが僕は一番嫌いなところなんです。

それと、編集差分が本当にないので、誰がアップデートしたのか、そもそも何が前回と変わったのかっていうことが誰も追えなくて、編集者しかわかりません。

あと、開発者じゃない人にちょっとフレンドリーじゃないっていうところもあります。開発者だったらJSONのValidateをかけるということをやるんですけど、正直、「marketerの人たちは、そこまで求めていいんだっけ?」「そういう人たちにFirebaseのやつを全部見せていいんだっけ?」みたいなところもあるんですね。

Remote Config REST APIとは?

この3月13日に、Remote ConfigのREST APIが公開されましたよっていう記事が出たんです。(スライドを指して)もう僕は、完全にこうなったわけですね。

あと隣にいたhotchemiさんもこうなってたはずなんですけど……はずなんですよ(笑)。

Remote Config REST APIは何かというと、単一のJSONオブジェクトストアっぽいんですね。ほぼFirestoreと変わらないような感じになっています。なので、キーベースドのマネジメントのインターフェースは生えてないです。例えば、Delete APIで、あるキーを指定する、みたいな動作ではないです。

Get APIは何を提供しているかっていうと、Configを拾ってくるだけ。それで、JSONとして返してくれます。Updateは何かというと、対象後となるJSONのファイルを直接アップロードして行うようなかたちになっています。

どうやって使うかというと、アクセストークンアプローチなので、当然、最初にアクセストークンを発行しなきゃいけないんです。Firebaseプロジェクトからサービスアカウントキーをダウンロードしてきて、これは制限付きで、何分かは計ってないんですが、エクスパイアするトークンが発行されます。

それで、「Google API Clientを使え」と公式に書いてあるんですね。それだけしか書いてなくて、ほかのFirebaseファミリーは、Firebase Admin SDKをけっこう使ってるんですけど、ここは使わないので、そこだけ注意が必要です。

Remote Config REST APIで何ができるか?

サービスアカウントキーのダウンロードの方法は、プロジェクトのSettingsのところにいくと、(スライドを指して)こういう、いっぱいある中に「SERVICE ACCOUNTS」というタブがあります。

そこを選択して、一番下に「GENERATE NEW PRIVATE KEY」っていうボタンがあるんですね。ちなみにこれは本当にAdmin権限なので、絶対に公開しないでください。それをクリックすると、「ダウンロードしますか?」と聞かれて、めっちゃ注意されるんですけど、します。

次に、スクリプトを使ってアクセストークンを発行します。これはPython2系のやつですね。

easy_installでoauth2clientを拾ってきます。好きなデータを使ってください。EmacsでもVimでもなんでもいいです。それで、Pythonファイルを作って発行するだけです。

後でスライドはもちろん公開するんですが、この例は、単純にアクセストークンを標準出力するだけのやつになっています。

そのアクセストークンを使ってAPIを叩いていくんですが、エンドポイントはこの長ったらしいやつで、途中にプロジェクトIDを挟むような感じです。サポートされているメソッドは、GETとPUTのみです。PUTは正確にはファイルをアップロードするのを伴います。

ヘッダでAccept-Encodingを指定しないとEtagが返ってこない仕様になっているようで、それがREST APIの説明のところに、書いてあるようなないような感じでサラッと書いてあるので、気をつけてください。

(スライドを指して)GETのほうは、オフィシャルサンプルをほぼパクってきたのですが、curlコマンドで書いてありました。

compressedが、さっき言ったAccept-Encodingのところですね。ヘッダにEtagが入っているので、ヘッダーダンプもします。トークンがベアラートークンなので、ベアラーのヘッダを指して、GETでエンドポイントを叩いて、レスポンスボディがConfigファイルですね。それを保存するっていう感じです。

PUTのほうは、last-returned-etagになってるところを変数に置き換えて、最新のEtagを載せます。

JSONを単純にアップロードするような感じですね。もちろんこれにもOAuthが要ります。

PUTに関しては、compressedはあってもなくてもいいかなと思います。この時、アップロードしてあったらもちろんEtagが返ってくるんですけど、それを使うか使わないかは自由なので、特に問題ないかなと思います。

(WebのUI editorについてのスライドを)もう1回出します。バリューに対するバリデーターがないとかいっぱい言ったんですけど、それができるって、さっきの(REST APIの)アナウンシングの記事に書いてあるんですよ。

そのREST APIで何ができるかというと、「バリューのバリデーションがある、お前のコードでだ」っていう感じになってます。残念ながら、NestedなJSONは置けないんですね。なので、JSONバリデーターはどうしても自分でやらなきゃいけません。あとは、Update automaticallyは、もちろんAPIを叩くので、自分のコードでならできます。

それで僕が一番気にしている、パブリッシュが本当にすぐできるのかっていうところは、アップロードし終わったらすぐパブリッシュされます。

それと、DiffはVCSを使えばビジブルになる、リーダブルになるっていうところです。

うまく組み込むことによって、ノンデベロッパーでもコンソールをいじらずにFirebase Config、Remote Configを変えられますよっていうことが書いてあります。

daruma氏が作ったGem「Remocon」とは?

そもそも、例えばさっき言った、値としてJSONを使いたい場合に「バリューJSONが2つあった時、単純にVCSのDiffでリーダブルなんだっけ?」ということについてです。(スライドを指して)こういう感じです。

めっちゃ小さくて申し訳ないんですが、人間が読んでいいものじゃないんですね。もしこれがわかるんだったら、その人はたぶん毎回毎回CIを見に行くほうが早いです。だいたいできません。

なので、もうやるしかないので、SDKを探したら、SDKがないんですよ。だから、作るしかなくて、作りました。「Remocon」っていうネームスペースが運良く空いてたので、Remoconっていう名前にしちゃいました。Ruby Gemで作っています。

JSONでやると、バリッドJSONを作ることがちょっとだるいなと思ったので、YAMLを使ってマネージングするやつです。それにバリデーションシステムと、File contentをロードする、要はStringではなくファイルパスを指定してロードできるようにするという機能を足しました。

使い方は、とりあえずインストールしてもらって、アクセストークンはさっき僕が言った方法とかで用意してもらいます。

環境変数でFirebaseのプロジェクトIDとアクセストークンを渡して、次から紹介するコマンド群を叩くっていう感じです。

Configを取るのは、pullコマンドです。

アウトプットにdestを設定すると、ファイルになります。まだプロトタイプなので、ここではとりあえず、4ファイルを作ってます。サーバー上にあるrawJSONファイルをそのまま吐き出すconfig.jsonというファイルと、Etagを記述してるファイル。それと、コンディションとパラメータでそれぞれYAMLを分けて、定義を分けています。

基本的に、まだコンディションのエクスプレッション式のところが、どういう値を使えるかが取れないので、コンディションズを手で編集するっていうのは、まだ非現実的かなと思っています。なので、パラメータのYAMLを編集してアップロードしていくっていうかたちになるかと思います。

「Remocon」の使い方

Update Configする時のコマンドは、2つのステップがあります。まず、アップロードする対象のJSONファイルを作ります。もちろんこの時にもバリデーションは走ります。次に、できあがったConfigのJSONをEtagとともにプッシュする、という設計をとっています。

バリデーションだけ走らせたい時は、バリデーションコマンドを用意しているので、それを走らせればちゃんとやってくれるはずです。

(スライドを指して)パラメータYAMLという編集するファイルですが、形としてはkey_nameがおおもとのキーになっていて、デフォルトバリューとしてvalueです。

normalizerって書いてあるのが、バリデーションっぽく働くところで「この形は最後何で吐き出すのか」というところを書いてます。conditional valuesがその条件で変動するところを新しいセクションとして持たせたり、一番下のcondition2の中は、ファイルパスを指定すると、それが最終的にエクスパンドされるようになっています。 

CIだったらどうやるかっていうと、例えばフィーチャーブランチだったらバリデートするだけです。マスターブランチでは、実際にサービスアカウントJSONをロードして、アクセストークンをその時パブリッシュして、プッシュしましょう、という感じです。Terraformっていうインフラで使うやつがあって、それにplanとapplyというコマンドがあり、それの思想のようなものに近いように作ろうとしています。

僕は別にメルカリの人じゃないので宣伝でもなんでもないんですが、数日前の4月9日に、ちょうどTerraformのブランチモデルの記事をメルカリのb4b4r07(ばばろっと)くんが書いてくれたので、それを読むと、だいたい掴めるんじゃないかなぁと思います。

「Remocon」の課題

Future Workとしては、まだちょっと差分ベースでアップデートをしていません。YAMLにファイルって書いちゃうと、それは当然サーバー上のConfig JSONには書いてないので、そこらへんは頭良くアップデートするっていうところを、今プロトタイプだけ作って一応動いています。なので、フィジブルではあるかなと思います。

それと、セマンティックでリーダブルなDiffを吐き出すようなコマンドと、バリデーターのプラグインシステムを作って、カスタムバリデーターを当てられるようにしたり。あとは、このスライドを作って動かしていたらバグを見つけてしまったので、それをフィックスしないとちょっとやばいなっていうところです。それでステーブルにして、1.0.0を目指そうかなぁと思っています。

付録として、最初にRemote Configを与えないところからやれるのかというのは、これはできます。普通に空っぽのレスポンスでEtagが返ってくるので、それを使えばできます。 定期的にまたは特定の時間にアップデートするにはどうするかっていうと、もちろんcronとかを使うことによって可能です。

コンディションをAPIで作れるかというと、NOとなっています。正確には、たぶん知ってるエクスプレッションだったらできるっていう感じですね。さっきも言ったんですが、コンディションに使うパラメータ群を取る方法がまだわかっていないので、ちょっと現実的じゃないっていうことで、NOにしています。

あと、Remote Configをアプリケーションレイヤーでフェッチする時のベストプラクティスをグーグラーの人が書いてくれてるので、参考にすると非常にいいと思います。

できれば、コンディションのエクスプレッションも全部書きたいので、誰か知ってる方がいれば教えてください。以上です。ご静聴ありがとうございました。

(会場拍手)