Microservices Advent Calendar 3日目です。今日も2時間遅刻です。。
今回はシリーズものを一旦お休みにして、別のことを書きます。
管理画面を作りたいが、既存の特定のマイクロサービスにと1対1に対応しないため、新しくサービスを作りたくなるときがあります。このとき、手拍子に新しいマイクロサービスを立ち上げると失敗することがあります。考慮すべきだと思う点をまとめました。
サマリ
- 「管理画面」に引きづられると責務の分割の目が曇る。 UIのことは基本的に責務とは別 として考えるべき。
- SPA (Single Page Application) として作るとわかりやすい。
- サーバを作るなら、単に管理画面を表示するためのサーバなのか、ドメインとしての責務を持つサーバなのかをはっきりすること。それにより考え方が異なる。
「管理画面」は責務ではない
管理画面、あるいは 管理ツール。
画面、ツールという言葉からもわかるように、これは ユーザインターフェイスです。それ単体で、なにか責務のまとまりになっているというわけではありません。
そこから考えられる最悪のシナリオは、手拍子に管理画面サービスを作ってしまい、本来他のサービスがもつべき責務を持ってしまった状態です。
もちろん、管理画面を提供するために新たに必要になるロジックは存在するでしょう。その場合基本的にはその責務を担当するべきサービスがすでにあるはずです。なぜなら、「管理画面」それ単体は、なにかを管理するための単なるUIだからです。
責務を考えずに「管理画面サービス」を作るとどうなるか?
はい、次のような問題がよく発生します。
- 本来ならその責務を担うサービスが持つべきロジックを、「管理画面から設定される」という理由で、管理画面サービスに持ってしまう。
- 結果、責務が分散することで、凝集度が低下し、あることを複数サービスに実装しなければいけない状態になりメンテナンス性が低下する。
- 管理画面サービスに他サービスからデータを同期する必要が生じることがある。
マイクロサービスにおける管理画面の作り方
ここでは、ブラウザで動く管理画面を作成するものとして、どのような作り方があるか、またそれによるメリットデメリットを考えてみます。
選択1. SPA (Single Page Application) で作る
最初からサーバを置くことを考えるのではなく、まずはシンプルにクライアントアプリケーションとして出発しよう、という考え方です。
これが最もアーキテクチャに間違いを起こしにくい、と私は思っています。可能ならまずこの選択肢から考えてみると良いと思います。
現実的にはいくつか考慮するべき事柄がありそうです。思いつくものをあげていきます。
SPA + BFF (Backends for Frontends)
管理画面の要件によっては、クライアントから多数のマイクロサービスにアクセスする必要があることもあるでしょう。そういった煩雑さをクライアントアプリケーションから取り除くために、クライアントのためのサーバを作る場合があります。それをBFFと呼びます。
この場合、BFFサービスに書くロジックはあくまで UIのためのロジックであるべき、ということに留意します。すなわち、例えば以下のようなものだけをもつべきでしょう。
- 各バックエンドサービスのAPIを集約する
- 表示用に、データを加工する
- 見た目の制御のためだけのようなロジック
- ex) localStorageで代用が効くような簡単な設定
- キャッシュ
要件から、並列処理に向いた言語で作成するのが良いでしょう。
覚悟のないSPA、という選択
SPAとはブラウザを超える体験を再実装する覚悟
という名言があります。 SPAと覚悟 という、teppeisさんによる素晴らしい発表の資料にあります。
さて、往々にして、管理画面はそこまでの覚悟は求められない傾向にある気がします(モノによりますが)。だから思い切ってSPAにしてしまうという考え方もアリかなと思っています。
以下はこの発表があったときのタイムラインでのaxrossさんのツイートですが、このように、SPAでなくても実現できる程度の体験であっても、SPAで作るのが楽、という感じです。
SPA流行ったの、モバイルアプリ天下になってJSON返すサーバーが増えたから、WebクライアントもHTML求めるなってモチベは少なからずあると思ってる #frontendmeetup
— axross (@axross_) 2016年9月16日
SPA書ける人いる?問題
上と少しかぶります。
シンプル にクライアントアプリケーション と書きましたが、シンプルというのはあくまで発想とか切り分け方のことであります。実態としては、以下のような問題もあるでしょう。
- 実装は、動的HTMLを生成するサーバよりも難しい場合がある
- ノウハウを持っていない場合がある
- ex) RailsのViewは書けるけどSPAは書いたことない
そんな方には Vue.js をお勧めします。SPAを作る上ではもっとも学習コストが低く、かつVue.js単体で十分面倒を見てくれます。人気度もReactとAngularに続いて高く、今後も安定して使えることが見込めます。
選択2. DBをほぼ持たないようなサーバで作り、HTMLをレンダリングする
SPAは難しいからサーバでHTML作るという判断になったときです。
この場合、上で説明したBFFと留意することはだいたい同じで、違うのはそのサーバ内に表示のためのロジックが入り込むくらいです。あくまで ビューのためのサービス だということに強く留意するべきです。繰り返しになりますが、ドメインロジックはあくまでその責務を担当する別のサービスに寄せるべきです。
選択3. 新しく責務を担うサービスを作る
管理画面の要件を整理したら、普通に新しい責務として分割できるレベルだった、という場合です。
この場合に注意すべきなことは、 管理画面の機能 != 新サービスの責務 であるということです。
つまり、管理画面から使える機能だといっても、その管理画面に対応するサービスの責務とは限らないのです。この話を具体例で示してみましょう。
例
とあるアプリケーションがあり、 バックエンドのサービスA が存在しています。このサービスは、次のような責務がありました:
- アプリケーションの機能全般
- このアプリケーションの契約者を管理する
さて、ここで新しく、契約者を管理するような管理画面を作成することになりました。要件をよくよく聞くと、単に「管理画面を作る」のではなく、契約に関してもともとなかったような新しいロジックが多数必要なことがわかりました。そこで、元のバックエンドサービスから、新しく 契約・契約者に関する責務を持つサービスB として切り出すことになりました。
- サービスA: アプリケーションの機能全般を司る
- サービスB: このアプリケーションの契約者を管理する
- 管理画面: 契約者に関する設定
さて、上記の管理画面の要件に 契約者ごとの、あるアプリケーション機能のON/OFF が含まれていたとします。これはサービスA・Bどちらの責務でしょうか?
これは、 サービスAの責務 にすべきと考えられます。サービスAはユーザがアクセスして実際に機能を提供するときに、その機能がONかOFFか判断する必要があります。これはれっきとしたサービスAの責務でしょう。
今後、契約者のこの設定以外にも他の設定でONとかOFFとかの条件が増えるかもしれませんね。そういったときに、その設定をサービスA以外に散らばって持っていては、やはり凝集度の低下によりサービスAのメンテナンス性が下がることになります。
Railsアプリケーションは大抵向いていない
あまりここに並べるのもしっくりきませんが、すこし実践的な判断方法の一つです。
これまでの分類で、サーバが出現するとしたら以下の3つに分類されます。
- 選択1をしたのときのBFF
- 選択2: DBも責務も基本持たない、集約とHTMLレンダリングのサーバ
- 選択3: 管理画面で使われる、新しい責務を持つサーバ
このうち、選択3はともかく、選択1のBFFと選択2には、Railsは向いていません。
まず、サーバを立てているということは、APIの集約がメインです。ふつう、この目的ではNode.jsなど並列処理が向いた言語が良いでしょう。
またDBを持たないのであれば、ActiveRecordもないので、RailsのViewを作るための便利メソッドは使えません。
いずれにしても、ActiveRecordの出番がなく、並列性を求められていたら、Railsを使う理由はほぼないといえるでしょう。だから使っちゃダメというわけではないですが、少なくとも得意分野ではないです。
今回はRailsで説明しましたが、多くの言語・フレームワークに置き換えられる話かと思います。
まとめ
一言で言えば、 見た目と責務を分けて考えよ ということに行き着くのだと思っていますが、管理画面は往々にしてそこが問題になりがちなため、一つのテーマにしてみました。マイクロサービスで管理画面を作るときの、一つの指針として参考になれば幸いです。