🐥

なぜ「実践マイクロサービスAPI」は退屈だったのか

2024/01/09に公開

はじめに

先日実践マイクロサービス APIという書籍を購入しました。
動機としては、マイクロサービスを実装するためにマイクロサービスという手法について学ぶためです。
その目的で上記書籍を読み進めていましたが、マイクロサービス API の実装という面では中々読むのがしんどかったです。
今回はなぜしんどかったについて、言及していきたいと思います。

本題に入る前の注意書

ここでは本題に入る前に、あらかじめ言っておきたいことについて二点ほど記載します。
まず一点目についてですが、書籍自体を退屈と言いたいわけではないということです。
今回紹介する実践マイクロサービス APIという書籍をタイトルではあまり良くない本のように捉えていますが、この本自体は確実にとても非常に素晴らしい本です。
マイクロサービスの概要から始まり、マイクロサービスを設計する際に意識することや、API 実装幅広く扱っています。
また、JWT を中心とした認証・認可のやり取りやテスト手法、果てには EKS を使用したデプロイ方法についてまで触れています。
458 ページというボリュームからも分かるように、マイクロサービスを実装する上で考えるべきことや実際の手法について、多くのことを学べます。
その中でも特に私が気に入っている部分は、GraphQL API の実装について解説している部分です。
GraphQL の概要、Query や Mutation の構文についての解説は簡素なものですが、実際に使う API を実装する際に意識することを紹介してくれています。
とりあえず使ってみて、後から概要を把握するのが好きな私にとっては、今この本で学べたことはとても良かったです。
以上のように、実践マイクロサービス APIはかなりの良書です。
今回、本題の内容をより印象づけたいがために、タイトルは本書を批判していると捉えるものになっていますが、この本そのものの価値を乏しめているわけではないことをご留意いただけますと幸いです。
二点目ですが、マイクロサービスにおいて欠かせないインフラ周りについてはほぼ触れません。
サービスを独立して動かすため、Kubernetes といったコンテナ管理やサービスごとのログを収集して、エラーの原因究明をしやすくするなど、インフラ周りでやることは多岐にわたります。
しかし、今回はそういったことには触れません。
理由は二つあります。
一つ目は、私自身の理解が浅いためここまで取り上げると、記事にするまでに多くの時間を要してしまうためです。
二つ目は、この記事の主題がマイクロサービスを構築するための API を実装する点に着目しているからです。
二つ目がインフラ周りに触れない最大の理由で、今回は API を実装するという点だけに着目しており、その観点で言うと実践マイクロサービス APIは退屈だと結論づけようとしています。
インフラは今回の主題に関わってきません。
マイクロサービスを構築するのにインフラは重要ですが、今回は関係ないので省略しています。
以上が、この記事の内容へ入る前に読んでいただきたい内容です。

マイクロサービスについて

マイクロサービスとはなんなのか

まずマイクロサービスそのものについて見ていきます。
マイクロサービスの定義自体は完全に定まったものはないですが、Sam Newman が著者のマイクロサービスアーキテクチャは以下のように言及しています。

マイクロサービスとは、一体となって動作する、小規模で自律的なサービスのことである。

また、こちらの記事ではマイクロサービスアーキテクチャのことを以下のように述べています。

In short, the microservice architectural style [1] is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API.

ざっくり訳すと、「それぞれ独立して動き、かつ HTTP リソース API といった軽量なプロトコルで通信する小さなサービスを用いて、一つのアプリケーションをデプロイするのがマイクロサービスのアーキテクチャ」となります。
このように、マイクロサービスにとって重要なことは次のようなことだと分かります。

  • それ単体で動く
  • 小規模
    • ただし、コードの絶対量が少ないというよりは、サービスが扱う領域が一つのみといったサービスの責務が小さいことを小規模としています。
  • サービスたちを集めて、アプリケーションを構築する。

マイクロサービスそのものの概要について軽く見てきたので、次はマイクロサービスとよく比較されるモノリスについて見ていきます。

モノリシックなアプリケーション

次に、モノリシックなアプリケーションについて見ていきます。
モノリシックなアプリケーションとはその名の通り、全ての機能が一つのプロジェクトに組み込まれているアプリケーションです。
例えば、ログインが必要な掲示板を作成することを考えてみます。
マイクロサービスで考えるなら、まずログイン機能と掲示板の閲覧や投稿機能でサービスを分けると思います。
一方で、モノリシックで考えると上記機能は独立させず一つのプロジェクトに全て含めるようにします。
モノリシックアプリケーションについても、軽く見たのでモノリシックなアプリケーションとマイクロサービスを比較することでマイクロサービスの利点について確認します。

モノリスから見たマイクロサービスの利点

ここでは、モノリスなアプリケーションと比較することでマイクロサービスの利点について見ていきます。
まずはコードの密結合を避けやすい点です。
モノリスなコードで実装すると、欲しい機能に対してのアクセスが簡単です。
それこそ、ファイルからインポートするだけで必要な機能を使えます。
このような、使いやすさという点は利点でもありますが、一方でそれぞれが依存しあってしまいメンテナンスが大変になりやすいという欠点もあります。
アプリケーション希望が小さいうちは問題ありませんが、アプリケーションがどんどん複雑になっていくと依存しあうことで修正や拡張がしにくくなってきます。
モノリスにしてしまうとこのような課題を抱えます。
しかし、マイクロサービスでは上記の点が発生しにくくなります。
適切にサービスを切り出せば、各機能は自己完結型になるので、依存してしまうことがなくなります。
これによって、片方を修正するともう片方にも大きな影響を与えることがなくなり、それぞれの機能を修正・拡張がしやすくなります。
また、テストについてもモノリスなアプリに比べ実行が容易になります。
モノリスなアプリはテストが一つにまとまっているため、新しい機能に対するテストケースを追加するたびに、テストの完了時間が膨れ上がっていきます。
そのため、デプロイする時間が長くなり、ちょっとした修正も直ぐに反映しにくくなります。
一方で、マイクロサービスは各サービスが独立するため、一つのサービスに対してテストを追加したとしても、他のサービスのテストに影響を及ぼしません。
なので、テストケースの増加すればするほど全体の完了時間が遅くなるという心配もモノリスなアプリより、圧倒的に少なくなります。
その他にも、責務が分かれているのでリファクタリングもしやすく管理が容易なコードを構築しやすいといった利点があります。
機能が少ない小さいアプリを複数作成するのではなく、一つの高機能なアプリを作ることがおおくなっている現代において、マイクロサービスという考え方は多くの利益をもたらします。

マイクロサービスの課題

先程、マイクロサービスの利点についてあげましたがもちろんマイクロサービスにも課題があります。
具体的には以下の 4 点です。

  1. サービスの効果的な分解が必要
  2. 統合テストのしにくさ
  3. エラー時のサービスをまたがった対処
  4. 運用の複雑さとインフラのオーバーヘッドの増大

それぞれ簡単に見ていきます。
まずサービスの効果的な分解についてです。
マイクロサービスはそれぞれが独立しているが故に、各機能を疎結合にすることができ、拡張などがしやすいというの利点でした。
しかし、サービスの分割を適切に行わないと片方のサービスがもう片方のサービスありきになります。
これでは、マイクロサービスの利点を打ち消しているにととどまらず、デプロイが複数回必要となるため、モノリスなアプリよりも管理がしにくくなります。
このような状態を分散モノリスといい、マイクロサービスを構築する際はこの状態を避けるための設計を考える必要があります。
次に、統合テストのしにくさです。
先程、マイクロサービスはテストしやすいと言っていましたが、それはそれ単体をテストするときです。
複数の機能を組み合わせてテストを行う統合テストでは、マイクロサービスは独立しているが故にモノリスなアプリより行いにくくなっています。
この統合テストを構築する難しさはマイクロサービスには存在することを把握する必要があります。
複数の機能の組み合わせへの対処が難しいというのは、エラー発生の時もあります。
例として、注文サービスと発送サービスについて考えます。
注文サービスで注文処理をした後、発送サービスで発送処理を行うの適切な流れとします。
この時、注文サービスでエラーが発生したらモノリスなアプリではロールバックが容易です。
単一のデータベースを使用しているので、そのデータベースをロールバックすれば良いからです。
一方、マイクロサービスでは各サービスはそれぞれ別のデータベースを使用している場合があります。
モノリスなアプリでは一つのデータベースをロールバックすればよかったのに、マイクロサービスでは片方のエラーを検知して各サービスのデータベースをロールバックする必要があります。
この複数ロールバックを行う複雑さは、マイクロサービスの課題です。
最後に運用の複雑さやインフラのオーバーヘッド増大についてです。
マイクロサービスは複数の機能が独立して動くため、それぞれのデプロイ・状態の管理などを可能にする必要があります。
この一括して管理ができる仕組みを導入するのがかなりの労力です。
単一のアプリであれば、Vercelといったデプロイツールでサクッとできますが、マイクロサービスの場合、EKS などオーケストレーションツールを用います。
学習コストがかかってしまうのは、マイクロサービスを導入するのを重荷にします。
また、マイクロサービスは各サービスが独立しているので、アプリにエラーが起きた際どのサービスで発生したのかが分かりにくいです。
そのため、マイクロサービスでもアプリのログを統一して管理できるようにすることが求められます。
以上が、マイクロサービスの課題です。
それぞれの開発手法に利点・欠点が存在することがよくわかります。
最終的には、案件に対して適切なものを都度選択するということが必要になっていきますね。

マイクロサービスの設計

適切なマイクロサービスの設計原則

マイクロサービスはそれぞれが独立しても動くように設計され、明確な境界を持ち、軽量なプロトコルで相互のやり取りを行うものでした。
その要素を満たすには、以下 3 つの設計原則が存在します。

  • サービスごとのデータベースの原則
  • 疎結合の原則
  • 単一責任の原則

それぞれ簡単に見ていきます。

サービスごとのデータベースの原則

サービスごとのデータベースの原則は実践マイクロサービス APIにおいて、以下のように言及しています。

マイクロサービスはそれぞれ特定のデータセットを持っており、他のサービスからは API を使わなければそうしたデータにアクセスできないようにすべきである

このことからも、各サービスはそれぞれ独自のデータを持つようにして、他のサービスなどは対象のサービスを動かさない限りデータが取得できないようにするといった原則が見えてきます。
なお、この特定のデータセットですが、それぞれ独自のデータベースを持たなければいけないというわけではなさそうです。
データベース自体は共有にしたとしても、原則からは外れていないです。
ただし、各サービスが所有しているデータにはアクセスできないようにする必要があります。
このサービスごとのデータベースの原則を守ることで、別のサービスによってデータを破壊されることがなくなり、サービスの独立性を保てます。

疎結合の原則

疎結合の原則は、関心事を明確に分離した上でサービスを設計しなければならないことを意味します。
もう少し具体的には 2 つの意味に分けることができます。
一つ目は、各サービスがそれぞれ独立した状態で動作できるということです。
他のサービスを呼び出すことが前提になっているサービスがある場合、それらのサービス間で関心事が明確に分離されておらず、一体とみなします。
二つ目は、各サービスがそれぞれ他のサービスに影響を与えることなく更新ができるということです。
あるサービスが更新するたび、それに合わせて他のサービスも処理を行う必要があるとしたら、それらのサービスは密に結びついているため、設計を見直す必要があります。
この疎結合の原則を守ることで、各サービスの適切な分離を行えるため依存関係を作らずに済みます。

単一責任の原則

単一責任の原則は、サービスの責務ができるだけ少なくなるように設計する必要があるということです。
理想としては、責務が一つになることが求められます。
この原則をマイクロサービスに当てはめるとするなら、各サービスはそれぞれのドメインごとに構築するのが良いです。

サービスの分解

サービスをどのように分けるかは、ビジネスケイパビリティやサブドメインによる分解があります。
サブドメインはドメイン駆動設計の設計手法を用いて行われます。
正直この分解については、理解がほぼ全くできていないので、ここまでが限界です。
すみません。

なぜ退屈だったのか

ここまでで、マイクロサービス周りの概要について触れてきましたので、ようやく本題の退屈と感じた理由について言及していきます。
その前に、実践マイクロサービス APIを購入した目的を再度確認します。
実践マイクロサービス APIを購入したのは、マイクロサービスと呼べる API を実装するためでした。
なので、ここからはその観点で話を進めていきます。
実践マイクロサービス APIが退屈だったのは、主に二つの理由があります。
一つ目は、書籍に API の実装はマイクロサービス関係なく、良いとされている実装方法を遵守することに終始しているからです。
私自身ずっとモノリスなアプリを実装していました。
そのため、新しく触れるマイクロサービスに過大な期待を寄せていました。
きっと今まで経験したことのないような新しい方法で、依存関係の解消などの課題を鮮やかに解決するのだろうという期待を。
しかし、蓋を開けてみるとこれまで先人が築き上げた手法を今まで以上にきちんと行うことがマイクロサービスにおける API 実装の要でした。
実際、これまで見てきたマイクロサービスの説明については、マイクロサービスでなくてもどこかで見たような内容が多かったと思います。
疎結合の原則や独立性を保つことなどは、何かしらで見聞きしたことはあると思います。
このように、あっと驚く中身を期待した自分にとってはなんとなく肩透かしだったため、本を読み進めるのが退屈だと感じました。
二つ目はの理由は、マイクロサービスで遵守すべき原則などを意識して開発を行ったことがないからです。
もちろん、ある程度保守性を高くするために過度な依存は避けるといったことは行っています。
しかし、上記実装は肌感覚で行っており、ちゃんとした理論を勉強したり実践したりすることを行っていませんでした。
そのため、実践マイクロサービス APIを読むと内容が大切なのは分かるけど、なんとなく表面をなぞっているだけで実感が湧かないことが多々ありました。
このように私の知識・経験が不足していることで、書籍に書かれてある内容が「ふーん、そうなんだ」で留まってしまい、「大切なことが書いてあるな」と嚙み締めることができなかったのが、退屈だと感じた理由の一つです。
以上のことから、実践マイクロサービス APIはマイクロサービスに関わらず実装や設計の際大切にすべきことは、マイクロサービスの構築の際も大切にする必要があることを伝える書籍だとわかります。
ただ、私はこの当たり前が当たり前になっておらず、単語の目新しさだけで過度な期待をしてしまったせいで、書籍の重要なところを吸収できず退屈に感じてしまいました。
ドメイン駆動設計など含め、もっと勉強する必要があるなと強く感じました。

おわりに

今回は書籍実践マイクロサービス APIを読んで退屈だと感じた理由を記載しました。
前置きにも書きましたが、私はこの本を批判するつもりは一切なく、この本は素晴らしいと思っています。
GraphQL 周りは全てを吸収できていませんが、非常に役立つと感じています。
ただ、この本の根幹を自分のものにするには色々と時期尚早でした。
ドメイン駆動設計などをちゃんと学び、またこの本に戻った時その価値をただ理解するだけでなく、実践できるよう自戒も込めてこの記事を書きました。
何度も繰り返しで申し訳ないですが、実践マイクロサービス APIは素晴らしい本です。
私のような若輩者ではなければ、私が感じた以上の知見をこの本から得られると思いますので、是非とも一読いただければ幸いです。
ここまで読んでいただきありがとうございました。

Discussion