マイクロサービス、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 アプリはフレームワークに従うことで初心者に近い人でもある程度のものができるようになっている。それを一歩抜け出るきっかけになりそうな、そんな期待がある。

おしまい。

  1. 『マイクロサービスアーキテクチャ』の中の言葉を借りれば「データポンプ」 

  2. ということは全部の画面の欲しい情報が揃っていないと完全な DB 設計はできないので、実装と設計は本来不可分 

More

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 Develop Document Jekyll