この記事は ドメイン駆動設計 #1 Advent Calendar 2018 の 21日目 です。
前日は @mafuyuk さんの「DDDをチームに導入する際に考慮した4つのこと」でした。
明日は @dnskimo@github さんです。
この記事の内容
実務でドメイン駆動設計(以下、DDD)とマイクロサービスアーキテクチャを実践していますが、
DDDとマイクロサービスの粒度について、チームメンバーでの解釈が異なっていることもありました。
この記事では、DDDの構成要素とマイクロサービスをどう合わせるのがいいのか? を考察していきたいと思います。
いきなり結論
先に結論を言ってしまうと、「DDDのサブドメインをマイクロサービスの単位とする」 になると考えます。
境界づけられたコンテキスト : サブドメイン(のドメインモデル) : マイクロサービス が、1 : 1 : 1 になるのが理想形です。
以降、その理由を解説していきます。
まずは言葉の定義を
DDD や マイクロサービス の文脈で登場する言葉は受け手の解釈によるところが大きいので、以降の考察がブレないように記事中の言葉を定義しておきます。
DDD
マイクロサービスとの関係と言う観点では「ドメイン」「サブドメイン」「ユビキタス言語」「境界づけられたコンテキスト」あたりの概念を共通認識できていればOKです。
これらについて、 ドメイン駆動設計 #2 Advent Calendar 2018 の 18日目の記事 「DDDのドメイン・サブドメイン・ユビキタス言語・境界づけられたコンテキストを整理する」 で解説していますので、そちらを参照してください。
マイクロサービス
書籍 「マイクロサービスアーキテクチャ(以下、Newman)」 を参考に、「マイクロサービス」 は以下の特徴を持つものとします。
- ある関心事について、その問題を解決するための一連の機能を提供します。
そのマイクロサービスだけで問題が解決まで完結しなければなりません。 - 1つの マイクロサービス には、そのサービスを利用するための複数のエンドポイント(RESTful API や メッセージキュー など)が含まれます。
- 他のサービスが停止していても独立して稼働し続けることができます。
その間は他のサービスとの間に不整合が生じえますが、最終的に整合性が取れた状態になります。(結果整合性) - 他のサービスが稼働したまま、単独でデプロイすることができます。
- マイクロサービスを構成するモジュールは、1つだけのこともあれば複数の場合もあります。
たとえばJVM系言語であれば1つの warモジュール だったり、APIエンドポイントごとの複数の jarモジュール だったりします。
ちなみに、同書では以下のように「マイクロサービスはDDDの境界づけられたコンテキストの単位にすべし」と書かれています。
一般に、マイクロサービスは境界づけられたコンテキストときれいに一致するようにします。
- Newman 第3章 サービスのモデル化方法 / 3.3.2 モジュールとサービス
既に述べたように、境界づけられたコンテキストに沿ってサービス境界の線を引くようにします。
それにより、チームも境界づけられたコンテキストに一致することになります。
- Newman 第10章 コンウェイの法則とシステム設計 / 10.8 境界づけられたコンテキストとチーム構造
マイクロサービスについての詳細は、以前の記事 「書籍 マイクロサービスアーキテクチャ まとめ」 も参照ください。
DDDとマイクロサービスのパターンについての考察
言葉の定義ができたところで、DDDのどの構成要素をマイクロサービスに対応づけるか?考えていきます。
マイクロサービスの単位はDDDの設計の結果、つまり「境界づけられたコンテキスト」と「ドメインモデル」がどう分割されたか?が前提となります。
例えば「ドメイン」が「サブドメイン」に分割されていないのにマイクロサービスにしようとしても、おそらくデメリットだけが強調されてメリットはないでしょう。
下表は DDDの設計の結果 と マイクロサービスの単位 をマトリクスで俯瞰したものです。
以降でそれぞれの組み合わせを見ていきます。
1.モノリシック | 2.マイクロサービス (境界づけられたコンテキスト単位) |
3.マイクロサービス (サブドメイン単位) |
|
---|---|---|---|
A.サブドメインに分割されていない | ⭕️ マイクロサービス化は無理。 |
❌ マイクロサービスのメリットが活かせない。 |
❌ マイクロサービスのメリットが活かせない。 |
B.境界づけられたコンテキストに複数のサブドメインがある | ⭕️ マイクロサービス化を検討すべし。 |
❌ 1つのマイクロサービスに、複数のサブドメインが混ざってしまう。 |
⭕️ ただし、成果物が混在してしまうことに注意。 |
C.境界づけられたコンテキストとサブドメインが1対1 | ⭕️ マイクロサービス化を検討すべし。 |
⭕️ きれいに一致する |
⭕️ きれいに一致する |
A.ドメインがサブドメインに分割されていない
「ドメイン」が「サブドメイン」に分割されていない、つまりドメイン全体が一枚岩(泥団子とも言う)になっているなら、 そもそもマイクロサービスアーキテクチャを採用すべきではない です。
「ドメイン」が一枚岩と言ことは、それらの概念は強い整合性を保つべきで結果整合性は採用できないし、一部分だけを単独で発展させていくこともできないはずです。
そのような「ドメイン」を無理にマイクロサービスに分割してしまうと、サービス間でデータの整合性を保つのに苦労したり、複雑な基盤(分散トランザクションとか)が必要になったり、一度に多数のモジュールを同期を取ってデプロイしなければならなくなったり...とデメリットが大きすぎます。
また、ドメインの知識をプロジェクト全体で共有しなければならないので、マイクロサービスにしても組織内での調整・合意形成がボトルネックになります。
無難にモノリシックな構成にするのが良いと思います。
B.境界づけられたコンテキストに複数のサブドメインがある
DDDの設計の結果、「ドメイン」が「サブドメイン」に分割されていますが、 1つの「境界づけられたコンテキスト」の中に複数の「サブドメイン」が含まれている(つまり、複数の「サブドメイン」でユビキタス言語を共有している)構造です。
このケースでは、マイクロサービスアーキテクチャも採用できますが、ドメインの構造とマイクロサービスの単位がきれいに一致しない ので注意が必要です。
マイクロサービスを「境界づけられたコンテキスト」単位に作る場合、1つのマイクロサービスで複数の「サブドメイン」を扱う形になるため 「サブドメイン」を分割した意味が薄れてしまいます。
例えば、ある「境界づけられたコンテキスト」に「コアドメイン」と「支援サブドメイン」が含まれているとすると、マイクロサービスは「支援サブドメイン」のことを考慮しなければならないため、「コアドメイン」に注力できなくなります。
また、「支援サブドメイン」を変更してデプロイする際、「コアドメイン」の機能も停止しなければならなくなるなどの影響を受けてしまいます。
一方、マイクロサービスを「サブドメイン」単位に作る場合は、それぞれマイクロサービスの独立性・凝集性を確保できます。
ただし、この場合に注意が必要になるのは、成果物(ドキュメントやソフトウェア資産)は「境界づけられたコンテキスト」でまとめられるので、 1つの「境界づけられたコンテキスト」に複数のマイクロサービスの成果物が混在することになる 点です。
そのため、構成管理 や 継続的インテグレーション/継続的デリバリ で工夫が必要になるかもしれません。
C.境界づけられたコンテキストとサブドメインが1対1
DDDの設計の結果、「ドメイン」が「サブドメイン」に分割されており、かつ 「境界づけられたコンテキスト」と「サブドメイン」が1対1に対応している 構造です。
このケースでは、ドメインの構造とマイクロサービスの単位がきれいに一致します。
なお、1つの「境界づけられたコンテキスト」には1つの「サブドメイン」しか含まれていないので、 マイクロサービスの単位は「境界づけられたコンテキスト」でも「サブドメイン」でも同義 になります。
まとめ
以上の考察から、「DDDのサブドメインをマイクロサービスの単位とする」 のが一番しっくりきます。
これであれば、DDDの設計の結果...つまり「境界づけられたコンテキスト」と「サブドメイン」の関係が1対1なのか、1対多なのか...に関係なく、マイクロサービスの単位は変わりません。 (前出の図中の B-3
と C-3
)
このパターンは、マイクロサービスに関するパターンを紹介しているサイト microservices.io および 書籍 Microservice Patterns でも Decompose by subdomain pattern として紹介されています。
Define services corresponding to Domain-Driven Design (DDD) subdomains.
一方、「境界づけられたコンテキストをマイクロサービスの単位とする」と言った場合、DDDの設計の結果によってマイクロサービスの内容が変わってきてしまうので、解釈の仕方によっては適切なマイクロサービスの単位にならない 恐れがあると思います。(前出の図中の B-2
と C-2
)
なお、前出の 「マイクロサービスアーキテクチャ」も含めて、多くの文献で「境界づけられたコンテキストをマイクロサービスの単位とする」ことが紹介されてはいます1が、それらはおそらく 「境界づけられたコンテキスト」と「サブドメイン」が1対1になっていることを前提としている と思われます。
つまり、意図としては「サブドメインをマイクロサービスの単位とする」と同じことを意味していると思います。(前出の図中の C-2
と C-3
)
おわりに
言葉遊びのようなまとめになってしまいましたが、逆に言えばそれだけいろいろな解釈の仕方ができて、曖昧になりやすいとも言えます。
DDDとマイクロサービスアーキテクチャを採用する際は、プロジェクト・チームで認識を合わせておくほうが良いと思います。
また、マイクロサービスアーキテクチャの採用にDDDの実践は必須ではありませんが、疎結合・高凝集なマイクロサービスを導き出すための視点をDDDが与えてくれます。
DDDすべてを実践しなくても、DDDの戦略的設計(ドメインをサブドメインに分割し、ユビキタス言語を境界づけられたコンテキストで区切る...)だけでも導入する価値はあるのではないでしょうか。
参考文献
- 書籍 マイクロサービスアーキテクチャ
- 書籍 Microservice Patterns
- DDDのドメイン・サブドメイン・ユビキタス言語・境界づけられたコンテキストを整理する
- Microservices と DDD - 魔女の一撃
- microservices.io
-
私自身も、この記事を書くまで「マイクロサービスは境界づけられたコンテキスト単位に作るべきだ」と言ってました。 ↩