オライリー・マイクロサービスアーキテクチャを読む ~サービスのモデリングとコンテクストの境界~

読まなくていい導入

 マイクロサービスアーキテクチャというやつの出自を調べてわかった事は、どうやら彼は、僕たちが勝手にいだく彼への印象とそう変わりない、表裏のない人間だという事だ。
 彼の性格は非常にシンプルで、装いもこの上なくスマート、また人当たりも柔らく気さくでおしゃべりなナイスガイだ。
 しかし、彼について調べていくうちにふと気づいたことがある。彼は確かに気さくではあるが、どうも自分と他人との間に明確な壁を作っているようだ。
 彼自身は「なに、あまり深く関係を築きすぎると、いざって時に離れ難くなるだろ?」などと軽口を叩いていたが、どうもそこには彼なりの一貫した哲学のようなものがあるらしい。

さて、オライリー・マイクロサービスアーキテクチャを読むの2回目です。 (前回の記事はこちら)
前回はまとめごとにクソみたいなコメントを差し込むことで記事を読みづらくしてしまっていたので、今回は先にだーっとまとめを書いて、そのあとコメントを書いていくようにしようかなと。
一個一個コメント書くとすごい勉強になるけど、その代わりめちゃくちゃ時間がかかるしね。
それでは本題へ。

二つの概念

優れたマイクロサービスを設計するには、まず二つの重要な概念を常に念頭におく必要がある。
それは高凝集性疎結合である。

疎結合と高凝集性

関連する振る舞いをするものは同じ箇所に、関連しない振る舞いをするものは違う場所におく。
サービスを独立してリリースするためには、個別のサービスの振る舞いを変更するのに必要な箇所が一箇所にまとまっていなくてはいけない。
変更箇所が散在していると多くのサービスを同時にデプロイしなくてはいけなくなり、デプロイのコストとリスクが高まる。
関連する振る舞いを定義したソースは一箇所で管理し、それぞれのサービス同士の境界が疎結合になるようにドメイン設計する必要がある。
ネットワークを介して通信を行い、他のサービスとの結合部分を疎にすることで、サービスの独立性は保たれる。

境界づけられたコンテクストとドメインモデル

サービス同士の境界に関して設計する時、エリックエヴァンスがドメイン駆動設計の中で定義した境界づけられたコンテクストは重要な概念となる。
全てのドメインは内部に複数の境界を持ったコンテクストを保持する。それぞれのコンテクストは内部に境界の外部に対して秘匿されたものと、外部に対して共有されるものの二種類をモデルとして持つ。
この境界づけされたコンテクストは外部に対して公開されたインターフェイスを持ち、そのインターフェイスの設計が他のコンテクストと共有されるモデルを決定する。
前回の記事でメンションした通り、マイクロサービスの境界はドメインコンテクストと一致させる必要があるため、サービスはドメインコンテクストによって分割され、共有されたモデルによって外部と協調する。
逆に言えば、境界づけられたコンテクストから情報が欲しい場合は、この共有されたモデルを通じてコンテクストから情報を引き出す必要がある。

エリック・エヴァンスのドメイン駆動設計を読んだことがない人向けの説明  

ドメインというのは、大雑把に言えば画像共有や会計といった、システムが価値提供の対象とするビジネスそのもののことです。
境界づけられたコンテクストというのはそのドメインの中で画像タイムラインや領収証管理といった業務領域や関心範囲のことを言います。  

ちなみに境界づけられたコンテクストの定義に関して、当書の中で筆者は「明示的な境界によって強制される特定の債務」という言葉が一番気に入っていると述べています。

ドメイン駆動設計におけるモデルというのはそれだけで一記事書けそうなくらい難しい概念なのですが、簡単にいうと現実に存在する物質や概念をシステムの関心範囲のみで抽象化し、プログラム上で現実のビジネスを表現するために作成されるもの、みたいな感じです。  
例えばInstagramのような画像共有システムにおける投稿画像というモデルは、その画像そのもののデータ、どこで撮ったか、いつ投稿するかなどは関心範囲となり得ますが、その画像がiPhoneで取られたかニコンのD7500で取られたかなどはシステムの関心範囲ではないので捨象されます。(カメラガチ勢のカメラコミュニティサイトなら話は別ですが。)  

ドメイン駆動設計自体がプログラムと現実世界のビジネスを一致させることで、現場の人間と開発者の意識が対等に会話できることを目的の一つとしてるので、プログラムの概念の振る舞いや属性の実装を、できる限り人間が現実に行う挙動と合わせるための洗練されたオブジェクトみたいなものかなぁと僕は理解しています。(DDDはクソほど難しいのでまだ勉強中です。)

コンテクスの境界の定め方

コンテクスト境界はドメインに対する知識が不十分な状態で定めようとすると、ドメインに対する知識が深まった段階で境界認識が誤っていたことに気づき、疎結合を解かざるを得なくなることもある。
そのためドメイン知識が不十分な段階で急いでマイクロサービスに分割する必要はなく、徐々に分割していく方法を撮った方がいいケースが多い。
具体的には、モノリシックシステムにおけるモジュール化などの手法を用いて関連するコードを一箇所にまとめ、あらかじめできる限り疎結合になるように設計しておき、モジュールの境界がコンテクストの境界と一致する場所でサービスを分割するという手法がある。
全てのモジュールの境界がコンテクストの境界とは限らないが、モノリシックに作成されたシステムの中でモジュールの境界はコンテクストの境界としては非常に有力な候補である。
いずれにせよ、新規システムを始める場合、最初からマイクロサービスへの分割を急ぐ必要はなく、モノリシックから初めてコンテクスト境界を見定めるべきである。

ビジネス機能とコンテクストのインターフェイス

 コンテクストの境界とインターフェイスについて考えるとき、なんのデータを共有するかから考えると、データに対するCRUDだけを提供する貧血症な共有モデルに行き着くことが多い。
 インターフェイスは外部に対して公開したいサービスの機能そのものであり、「このサービスの責務は何か」「このサービスがその責務を全うするためにどのようなデータが必要か」という観点からモデリングしていく必要がある。

マイクロサービスのネスト

 あるマイクロサービスが徐々に肥大化してきてサービス分割を考える段階になった際に、取りうる手段は二つある。
 一つは完全に独立した対等なマイクロサービスを複数作成し、それぞれと直接コミュニケーションすることで機能を提供する方法。
 もう一つはあるサービスを受け口にして、このサービスが新たに分割された子サービスとコミュニケーションをとる方法である。
 前者はマイクロサービスの独立性が高くなるが、後者の方法をとると元の大きなコンクスト境界を残したままサービスを分割できる。
 外部から見た場合、大きなコンテクスト境界が内部的に分割されてようが、ただ巨大なマイクとサービスであろうが関係なく、また入れ子にすることで内部ロジックを外部コンテクストから秘匿化できるメリットもある。
 また、テスト時にも入れ子型のマイクロサービスは利点がある。入れ子型のマイクロサービスは、元の大きなコンテクスト境界の境界ラインを外部に対して保ち続ける。そのため、外部のマイクロサービスはこのコンクストから提供される機能を、内部的のより小さいコンテクストに対して気にかけることなくスタブすることができる。
 どちらの手法をとるかは、開発の組織体制によるものが大きい。分割された小さなサービスを全て元の大きなサービスを担当していたチームが管理するなら入れ子型の方がいいだろうし、独立した別個のチームで開発を行うのであれば、対等なトップレベルのサービスに分割するのが正しい手法となる。

以上。コメントは後日別記事で。 ではでは。