マイクロサービス、WebAPI、設計の初歩的なメモ
マイクロサービスとか WebAPI とか、相変わらず1周2周遅れで取り組んでいるわけですが、やっとなんかちょっと分かったような気がしたのでだいぶ初歩的なメモ。
サービスをどう分けるか
すごく簡単なところなんだけど「境界で隔てた独立したサービスがお互いのリリースを阻害しない」というところがなるほどなと思った。
いや、実際、自分の中では「複数のサービスが連携して動く」くらいの理解でしかなくて、一つのサービスが他のサービスに依存しているんだったら「どんどん開発環境の準備面倒くさくなるよね?」と思ってたんだけど、「リリースを阻害しない」ことが大事なら当然開発環境の準備も依存関係が面倒を起こしたらダメだなということが急にピンときた。
例えばすごく素朴な例で言うとサービスA とサービスB の二つのサービスがあったとして、サービスB でサービスA のデータを JSON で GET して表示
+---------+ +---------+
|Service A| JSON -> GET |Service B|
+---------+ +---------+
なんてことを想像していたのだけど、これは「サービスBの開発時に完全なサービスAの動作を必要」としており、リリースどころか開発プロセスまで重くしてしまっている。
そうではなくて、例えばサービスAのデータのうち「サービスBに必要なものを必要な形式で送り込んでおく」ようにすれば、サービスBはサービスBで独立して開発を進めることができる。1
+---------+ +---------+
|Service A| PUT -> JSON |Service B|
+---------+ +---------+
この場合、ごく素朴な例では恐らく GET のパターンより PUT のパターンの方が実装量は多くなる。それでも独立性は高く保たれ、両サービスの開発、リリースはお互いを阻害しない。もちろんサービス B に引きずられて A の負荷が上がってしまうということもない。
恐らくマイクロサービスについてはまず境界の分け方が話題になると思われるが、自分にとっては開発環境の再現しやすさがものすごく気になっており、それを考慮したうえで分けるとすれば GET 型よりは PUT 型で連携するようにした方が、初期の実装量は多くなってしまうが、のちのちの開発、リリースのペースを落としにくいのではないかというのが現在の理解。
※ もちろんサービスの連携方法としてこれが合う場合と合わない場合があるとは思うけど、リリースを阻害しないことがマイクロサービスの要件なのであれば、そもそも依存したサービスなしに開発できないのはマイクロサービスとして分割するのに適していないところで分割しようとしているのではないかという気がする。
マイクロサービスとWebAPI開発サイクル
WebAPI | The Good Parts という本によれば Web API は大きく
- LSUDs ( Large Set of Unknown Developers )
- SSKDs ( Small Set of Known Developers )
の2つに分けられるとある。
マイクロサービスという文脈で WebAPI を考える場合は後者の SSKDs 限定で考えてよい。
このマイクロサービス前提の WebAPI を当初から考えていた際に、どうしても納得いかなかったのが Swagger, API Blueprint などの仕様がクローズアップされる手法。
これについては
に書いた通り Pact を中心に置くと決めるのでよさそう。
マイクロサービス的WebAPIの設計
WebAPI の設計については、「単に DB アクセスの wrapper みたいなのじゃ意味ないよね」というのは分かるんだけど、じゃあどうすればいいかはやっぱりよく分からなかった。ちょっと実際にやってみて分かったのは、
そうは言っても特に PUT 前提で考えるとデータストアの特性に API 設計は引っ張られざるをえない、という点。
例えば一気に書き込まざるを得ないファイルベースのデータストアのようなものを利用するとなった場合、PUT の API も一気に送る方式になる。そうすると個別に送る場合とデータ構造も異なってくる。特定のデータだけの UPDATE は難しいので、DELETE ALL と PUT のみ、みたいな形になる。
もちろん将来的にその方法はまずいというのが最初から分かっているのであればそれに適したデータストアを用意すべきだ。だが、まだしばらくそんなに本格的なデータストアは要らないな、ということであればこの判断もアリだろう。
今回、API ばかりを意識して設計を進めてしまった結果、実装しながら何回も設計をやり直すことが起きてしまった。これまで通常の Web サイト開発においては DB 設計と URI 設計を優先的に考えていたのだけれど、マイクロサービス的な WebAPI 開発においてもやはりそこら辺はあまり変えずにいけばよいのかなという気がしている。
少なくとも最後の Model での処理がちゃんと終わらないようなインターフェイスだけ「綺麗だから」とか「書きやすいから」ということで設計しても意味がない。GrapeだーSwaggerだーPactだーみたいなツールに振り回されているのは適切な設計作業じゃない。まぁ、ふりかえってみれば「そりゃそうだ」としか言いようがないんだけど、改めてそこを押さえつつ、ちゃんとインターフェイスとして使いやすくないとダメだね、と反省したのでした。
でも、そこら辺の見極めがつくようになれば、マイクロサービスというのは決して大げさな言葉ではなく、大規模サービスだからとかそういうことでもなく、力を抜いて自然とそういう設計ができるようになるんじゃないかな、ということがなんとなく想像できるようになってきた今日この頃でした。
結局大切なことは最終的に何が欲しいのか?であって、そこは外しちゃダメ。API だけを見て API 設計はできない。 1) 本来 DB 設計はどんなデータを「取得」したいかによって決まる。ダメなデータ構造がプログラムを複雑化するのと同様に、ダメなテーブル設計が DB の性能を殺す。だから画面で欲しい情報を整理して、DB 設計に落とし込む。2 2) URI 設計はユーザーとのインタラクションの設計と同時にアクセス解析のルール設定。 3) API 設計も最終的にそのサービス間のインタラクションはどこにキクのか?から逆方向に設計を進めていく。API は最後に決まる。もちろん、ここで決めたことしかできないとなるとこの API は汎用性が足りなくて不便ということになりかねないが、そこはそれ。マイクロサービス向け API は CDC を武器にどんどん変えていけばよい。YAGNI であり、そのための Pact だ。
そんな感じかな。
昨今では Web アプリはフレームワークに従うことで初心者に近い人でもある程度のものができるようになっている。それを一歩抜け出るきっかけになりそうな、そんな期待がある。
おしまい。