読者です 読者をやめる 読者になる 読者になる

たなかこういちの開発ノート

システム開発に携わる筆者が、あれこれアウトプットするブログ

業務プロセス全域をデザインするにおいて、境界付けられたコンテキストを如何に捉えるかという話

DDD サブジェクト指向 モデリング
要約
 
エンタープライズ・システムでは、同じ用語でも、部門や担当が異なれば意味も異なっている、という状況は日常的です。各担当が各人のリアルとして見ている個々の"Fact"と、全ての担当の見解を統合的に説明できる“イデア”であり仮説である"Truth"には、乖離があるのが普通です。複数の"Fact"から唯一の"Truth"を見出すところは、まさにシステム屋に期待されているポイントではないかと思います。
 
Truthを見い出し得る限り、Truthを共有する統合された唯一の境界付けられたコンテキストを設置することを目指した方が、実装上の重複を避けられるなどの開発メリットを受けられます。これは普通のOO的方法論(=古典的OO)です。
 
対象領域の規模や複雑さからTruthを見い出し難い、あるいは見い出すことが出来ても共有し難い場合、個々のFactに寄り添って複数の境界付けられたコンテキストを設置する方がよいでしょう。これはサブジェクト指向を導入する、ということです。
 
いずれにせよ、業務プロセス全域を如何にデザインするか考えた時、「まずは境界付けられたコンテキストを見定めて、それぞれにて如何にユビキタス言語を成立させるか」というアプローチではなく、「境界付けられたコンテキスト間で、曖昧さ無く矛盾無く双方向にtranslationができるようなユビキタス言語が構築できるように、コンテキストの境界を調整する」というアプローチが必要とされるでしょう。
 
〜・〜
 
「同じ用語も、部門が異なれば違う意味合いで用いられているものである」ということは、エンタープライズ・システムをやっていれば、日常の事だと認識するでしょう。
 
 
ある出版社の例をみてみます。その出版社は「書籍」と「雑誌」を制作し、取次(※出版業界における卸のような位置付けの業態です。)や書店に卸しています。「書籍」は返品されることがあります。返品された「書籍」は、程度がよければ改装され再度出荷されます。程度が悪ければ廃棄されます。「雑誌」は返品されたら直ちに廃棄されます。「書籍」は返品分含めて資産として扱われ、「雑誌」は資産として扱われません。「書籍」には「ジャンル」という販売管理上の分類があります。「ジャンル」は、一般書籍、企画書籍(※雑誌と書籍の中間的なもの、書籍だが決して重版しない)、音響・映像媒体付き(※特別扱い)、成人向け(※特別扱い)、といったものです。「ジャンル」観点では、「雑誌」も一つの「ジャンル」として扱われます。加えて「取引条件」という売価や原価に関わる諸条件が、おおよそ取引先×ジャンルの数分定められています。「取引条件」は特定の書籍(群)に個別に定められたものもあります。
 
◆注意◆
ここでの「ある出版社の例」は“フィクション”です。幾つかの事例を合成して本記事でのストーリーを作っていますので、実際に本記事で述べるような事象が生起したプロジェクトがあったわけではありません。
 
ここで、販売管理、営業、経理の各部門で、「在庫」という用語が何を意味するのだと定義したか、最終的な結論を記します。
 
販売管理::在庫 = 制作され未出荷の書籍 ∪ 返品され再出荷可能な書籍 ∪ 制作され未出荷の雑誌
 
営業::在庫 = 制作され未出荷の書籍 ∪ 制作され未出荷の雑誌
 
経理::在庫 = 制作され未出荷の書籍 ∪ 返品され再出荷可能な書籍
 
※記号「∪」は和集合(union)を表します。
 
営業部門は、新刊書籍や雑誌をどこに何部卸すか計画し交渉することが責務です。返品については関知しない、としました。経理部門は、資産管理観点で書籍の在庫数には関心がありましたが、雑誌の在庫数は扱っていませんでしたので、そのままに定義しました。販売管理部門は、書籍も雑誌も返品分も管理しています。
 
 
さて、このような結論に至るまでに、主に「返品」について為された議論を追ってみます。営業や販売管理の各担当者(=ドメインエキスパート!)の見解は以下に示す通りでした。営業部門では、ジャンル毎に担当者が置かれ、業務プロセスもだいぶ異なっていたので、各ジャンル担当者の見解をそれぞれ伺う必要がありました。
 
一般書籍を扱う営業担当者の見解は次の通りでした。
 
一般書籍は寿命の長い商品で、売れ行きや返品の推移を見ながら取引先にフェアーの提案などプッシュしたり、重版の計画を立てたりするのである。この活動は初版新刊時点から連続したものである。
 
企画書籍を扱う営業担当者の見解は次の通りでした。
 
企画書籍は旬のものなので時期を逃すと売れない。出版時期が決まっているので、作家さんや制作業者とのスケジュール交渉も多い。返品などの後処理は販売管理が担うものと認識している。
 
販売管理担当者の見解は次の通りでした。
 
返品や補充注文などの定型業務は、販売管理で十分に担える。在庫推移は必要があれば随時レポートできる。営業部門には非定型業務の多い新刊配本に注力してもらいたい。(これは経営からの指示でもあったはず。)
 
予想通り、営業部門の一般書籍と企画書籍の各担当者の見解はほとんど別物でした。ちなみに、営業といっても「sales」だけでなく「marketing」も担っている様子です。業務のAs-Isを素直に認識した業務モデルを描くならば、以下のような三つの境界付けられたコンテキストが存在すると捉えるべきように思えました。
 
- 一般書籍営業(※新刊配本、一般受注、返品、在庫管理を含む)
- 企画書籍営業(※新刊配本中心)
- 販売管理(※一般受注、返品、在庫管理含む)
 
※以降、他ジャンルと経理部門についての議論は省略します。
 
しかしそうだとすると、「返品」、「一般受注(※補充注文など定型的な注文受付業務)」、「在庫管理」の概念が、「一般書籍営業」と「販売管理」に重複して出現することとなってしまいます。この定義は「販売管理」のドメインエキスパートが嫌いました。販売管理のドメインエキスパートの“メンタルモデル”としては、返品や一般受注は販売管理の管轄であり、営業が一般書籍で歴史的経緯から今も担っているが、本来は移管されるべき業務である、という認識でした。
 
では、下記はどうでしょうか?
 
- 一般書籍新刊営業(※新刊配本のみ)
- 企画書籍営業(※新刊配本)
- 販売管理(※一般受注、返品、在庫管理を含む)
 
販売管理のドメインエキスパートの認識を重視したかたちです。「企画書籍営業」には元々「新刊配本」しかありません。一般書籍の営業には、新刊配本部分を抜き出して残し、返品と一般受注は「販売管理」にのみ含めるとしました。これはしかし「一般書籍営業」のドメインエキスパートの同意を得られませんでした。
 
結果的に下記のように定義しました。
 
- 営業(※新刊配本+各ジャンル固有のワークフロー)」
- 販売管理(※一般受注、返品、在庫管理を含む)」
 
新刊の配本については、整理してみると一般書籍でも企画書籍でも基本同じワークフローに乗る事が分かりました。要件的な同一性から結局「営業」の境界付けられたコンテキストは、新刊配本を中核として統合して一つとすることとしました。一般受注と返品は販売管理の専業としました。この切り口は結局一般書籍の営業担当のドメインエキスパートのメンタルモデルには全く適合していない、というものです。
 
この結論は、経営レベルの方針、つまるところ経営の“メンタルモデル”に寄っています。端的にいって、一般書籍はジリ貧であり企画書籍重視というスタンスだったのです。一般書籍も、継続的に売れるのは極めて限られた作家のシリーズに限定されていて、ある意味「一般書籍」というよりも“特定作家書籍”というのが実態でした。経営としては、定型業務や社内管理は販売管理に寄せて、営業には一般書籍も含めて新刊配本時のプッシュ力に重点をおきたいと考えていたのです。結果的には、この経営方針に沿って境界付けられたコンテキストを分けることとなりました。
 
 
業務プロセスの概念モデル的には、以上のように決着しました。自分たちの担ってきた業務やそれに対する“メンタルモデル”がある意味否定された(=少なくとも現在の主流からは乖離してしまっていることを認識させられた)一般書籍の営業担当者もしぶしぶ了承しました。しかし、「とはいえ一般書籍に関わる目下の業務が目下回らないのはあり得ない」、という担当者の最終意見も無視するわけにはいきませんでした。最終的に、システムの実装としては別のレベルでの対応が行われました。業務プロセスの概念としては先の通りですが、結局開発対象機能としては、業務プロセス分析から得られた境界付けられたコンテキストの概念モデルはほとんど消えて、下記のように機能をばらばらに捉え、単機能を独立性高く実装しました。(※独立性高いのはサービス層やアプリケーション層であり、DBはシェアードです。)
 
- 新刊配本(※一般書籍、企画書籍共通)
- 企画書籍ワークフロー(※主にスケジュール管理)
- 一般受注(※補充注文など)
- 返品
- 在庫管理(※参照系として)
- ...
 
そして、なんのことはない、ロールによるアクセス制御で、使える機能セットを好きなように組み替えられるようにしました。
 
念のために補足しておくと、実装から境界付けられたコンテキストの概念的な境界は消えたものの、上記のような開発対象機能を抽出、定義できたのは、これまでのような分析を経て業務プロセスの概念モデルを描こうという過程を経たからこそです。作業工程に意味が無かった訳ではありません。
 
もう一点補足すると、後半の論を先取りすることとなりますが、境界付けられたコンテキストの境界が消えた、というのは、実はエンタープライズ全域(というか、この例での開発対象範囲全域)で唯一のコンテキストとするような境界取りをした、ということなのです。
 
 
以上の例からの学びを挙げます。
 
(1) 複数ドメインエキスパートによる複数の“メンタルモデル”は、相互に整合しないことがままある。整合しているかいないかは、ある程度業務分析を進めてみないと分からない。分析を進めてみたところ、お互いに認識すり合わせでき、整合を取れる場合もあるが、業務モデルの想定自体が異なっていて、整合の取りようがない場合もあり得る。
 
(2) 分析の当初、ドメインエキスパートの“メンタルモデル”のAs-Isに1対1対応するところの概念境界を設けるようなステップはあるし、必要なステップでしょう。(先が分からないので、そこから始めるしかない。)しかし、整合しないままの“メンタルモデル”に基づいて、それに1対1対応した「境界付けられたコンテキスト」を定義しようとしたならば、実態/実体としては唯一のはずの業務概念(※今回の例で言えば「返品」など)が、異なる二つのユビキタス言語セットで表されることとなり得る。(※これを「ユビキタス言語の方言化」と呼ぼう。)整合性について十分な分析をすれば、「営業::返品」と「販管::返品」は完全に同一であることが分かったはずのところが、分析が不十分だと、似てるが違う機能である、という判断になる可能性がある。そのままシステム実装に進んだら、共通化できたはずの機能を重複開発してしまうおそれがある。
 
(3) 一つ確かなのは、ドメインエキスパートの(As-Isの)“メンタルモデル”のままに、システムの実装上の機能分けをするのはあぶない、ということである。
 
※このことは、エンタープライズ・システムをやってる者にとっては、改めて云うほどのことではありません。
 
(4) 一つ不確かなのは、このような場合、DDDのいう「境界付けられたコンテキスト」とは、各ドメインエキスパートのAs-Isの“メンタルモデル”にそのまま従って定義するのが妥当か、それとも、分析し整合取り作業を終えたあとの認識に基づくのが妥当なのか、という点である。後者はもはやドメインエキスパートにとっても、新しい認識世界となっている。
 
(5) なんだかんだ言って、実装としては“各業務機能単位”で独立した実装を行うのが、運用時にも柔軟さを失わずに済む唯一の方法だろう。なお、この“各業務機能単位”はDDDのいう「集約」に相当すると云ってよいだろう。
 
(6) (3)、(4)、(5)からさらに以下のことが云えそうである。
 
(6a) エンタープライズ全域で最適化された「集約」を見出すには、エンタープライズ全域を唯一のコンテキストに捉えるべきだろう。適宜境界付けられたコンテキストを分断すると、実装上の重複が生じる可能性を残す。
 
(6b) 一方、エンタープライズ全域で唯一のユビキタス言語を定めるなどというのは、非現実的な作業にも思える。適切な粒度に区切ることで、それぞれの“自分たちの楽園”を維持できるようにすることも境界付けられたコンテキストの用途に思える。
 
(6c) 無理なく無駄なく集約を見出すのを支援する事が境界付けられたコンテキストの一つの役割だとするなら、結局境界はどのように定める事ができるのだろうか。
 
 
境界付けられたコンテキストを捉えようというときのもやもやな状況を説明できる理屈の一つに、私は「Fact-Truth構造」というのがあると考えています。「Fact-Truth構造」とは次のようなものです。
 

f:id:tanakakoichi9230:20160409231300j:image

図1.Fact-Truth構造のイメージ
 
『A、B、Cという各事実が認識されるだろう。しかし各事実それぞれは必ずしも真実そのものを表している訳ではない。真実とは複数事実から浮かび上がるもの、または、個別の事実とは真実の一断面を表すもの。』、、、というものです。
 
※次の記事にFact-Truth論の詳細を書いています。よろしければご参照ください。
 
 
※このFact-Truth論はネットのどこかで見かけたものです。が、その出典はもはや分からなくなってしまいました。。
 
ドメインエキスパートは、彼ら/彼女らのFactを見ていて、それを説明してくれます。しかし、FactはTruthにとっては一断面でしかない、複数のFactからTruthを浮かび上がらせるのは、システム屋に期待されるところではないかと思います。
 
FactはTruthではないものの、各ドメインエキスパートにとっての現実(real)という揺るぎなさがあります。Truthは本質(idea(イデア))かもしれませんが、常に仮説(virtual)であるという危うさがあります。本質はTruth、確かなのはFact、Truthは理念、Factは実際、FactとTruthの関係にはこういったアンビバレンスさがあると思われます。
 
そんな中で「境界付けられたコンテキスト」を定義しようというとき、Truthに寄るべきか、それぞれのFactに寄るべきか、揺れ動いてしまうのだと思われます。前節の学び(6a)の、エンタープライズ全域で「集約」の重複を避けたいという思いは、Truthを見い出したいというものだし、学び(6b)の“自分たちの楽園”を維持したいという思いは、Factに寄り添っていきたい、というものでしょう。
 
「Fact-Truth構造」が本当にこの手の概念構造を良く表しているのだとしたら、結論的には、FactもTruthも両方捉えるしかない、のだと思います。両方を捉えようというとき、私はFactに寄ったモデルを「Subject」、Truthに寄ったモデルを「(Domain) Object」と称することとしています。
 

f:id:tanakakoichi9230:20160409231312j:image

図2.Subject=Fact、(Domain's) Object=Truth
 
このFact-Truth構造は、概念的モデルを表すだけではなく、実装レベルのデザインを理解するにも適用できると考えています。なんてことはない、正規化された一式のリレーショナル・モデルをTruth、それからO/Rマッピングされた複数のオブジェクト・モデルをFactと捉えます。O/Rマッピングは唯一に限る必要はありません。集約ルートが異なったり、含めるエントリーが異なっていたり、選択する項目が違っていたりする、さまざまなO/Rマッピングの定義が可能です。DDDの一つの集約は、一つのO/Rマッピングの表れとします。同一のデータ資源に対して、複数の集約を定義できる(※サブジェクト指向的な集約)とします。「Subject」は、このような(サブジェクト指向的な)集約が集まって構成されると考えます。
 
こちらの記事の後半にも記しましたが、一式のリレーショナル・モデル(Object)に対して、幾つのプロジェクションされたSubjectを想定するかという観点で、「古典的OO」と「サブジェクト指向」を統合して捉えることができると思っています。即ち、「サブジェクト指向」の一般としては、一式のリレーショナル・モデル(Object)に対し、プロジェクションされたSubjectが複数存在し得る、とします。
 

f:id:tanakakoichi9230:20160409231324p:image

図3.サブジェクト(OOモデル)は、一つのリレーショナル・モデルからの様々なプロジェクション
 
ここで、一式のリレーショナル・モデルに対して、偶然にもしくは意図的にプロジェクションされたSubjectだけが唯一つ存在するような特別なケースが「古典的OO」だと理解します。
 

f:id:tanakakoichi9230:20160409231332p:image

図4.サブジェクト指向における古典的OO
 
偶然にもしくは意図的に、一式のリレーショナル・モデルに対して、参照系中心のSubjectが一つと更新系中心のSubjectが一つ存在していたら、、それはCQRSかもしれません。
 

f:id:tanakakoichi9230:20160409231339p:image

図5.サブジェクト指向におけるCQRS(っぽいもの)
 
そうすると、更新系1個に参照系n個とか、もうなんだって想定できますね。
 
 
ユビキタス言語定義に纏わる別の話です。「ジャンル」についです。ジャンルが異なれば業務プロセスも異なる、というわけで、営業部門と販売管理部門はジャンル別の管理に力を入れていました。営業や販売管理部門からみれば、雑誌も、資産計上の対象か否か、という課題ではなく、単に一つのジャンルを構成しているという認識です。対して、経理部門から見ればジャンル自体に関心はありません。経理部門の関心は「取引条件」のどれが適用されているか、という点です。ところが、「取引条件」が大きくは「ジャンル」毎に定められていたことから、経理部門では「取引条件」のことを「ジャンル」と称していたのです。こちらもすっかり思い込んでいましたので、これには苦戦させられました。概要レベルでは話は通るのです。掘り下げていくといつの間にか迷子になっていることに気付くのです。販売管理部門から「ジャンル一覧」を見せてもらっていたので、無意味と思いつつ、経理部門で「ジャンル一覧を具体的に見せてもらえますか?」とお願いしてみたのです。「取引条件一覧」が出てきたとき、全ての謎が解けました。
 
「販管::ジャンル」と「経理::ジャンル」は意味が異なっていました。さて、ユビキタス言語の定義つまりコンテキストの境界をどのように引きましょうか。選択肢は二つあります。
 
一つ目は、販管と経理でコンテキストを分ける、というものです。「販管::ジャンル」と「経理::ジャンル」は意味が異なっていたのですから、基本的に語彙のシェアは出来ないと判断されます。
 
二つ目は、販管と経理が唯一のコンテキストに同居できるように努力する、というものです。具体的には「販管::ジャンル」を「global::ジャンル」だと定義、「経理::ジャンル」は「global::取引条件」だと定義します。
 
一つ目はFactに寄り添う姿勢で、先の学び(6b)に対応するものです。二つ目はTruthを見出そうという姿勢で、先の学び(6a)に対応するものです。
 
我々は二つ目の選択肢を取りました。何故なら、少なくとも「ジャンル」については既にTruthに気付けているのです。何もわざわざ再分離してtranslationロジックを挟むような実装を選ばなくてもよいでしょう。
 
我々の取った選択は一般化できると思います。コンテキストの境界を定める時、Truthを見い出しTruthに寄るべきか、無理なくFactに寄り添うべきか、その判断は下記のように行う事ができるでしょう。
 
Truthを見出し得る限り、Truthに寄るべきである。その帰結は詰まるところ「古典的OO」である。
 
重複を避けられ、総実装コストを下げられるであろう。
 
対象領域の規模や複雑さからTruthを見出し難い場合や、見出す事が出来てもステークホルダー間で共有し得ない場合、個々のローカルFactに寄り添うしかない。サブジェクト指向を導入するのである。
 
重複よりも混乱のリスクの方が高い状況である。ローカルFactに寄り添うのであれば、逆に隣接コンテキストからの侵入は徹底して防御(※DDDのコンテキストマップの話)しなければならない。
 
いずれにせよ、ここでのポイントは、境界付けられたコンテキストは対象のサブドメインに潜在的に内在するものを見出す、というようなものではなく、まさに意図をもってデザインするものだということです。できれば、唯一の境界付けられたコンテキストを設置できるように、唯一の統合されたユビキタス言語の成立を目指したいところです。複数の境界付けられたコンテキストに分割することになるのであれば、各々のユビキタス言語が相互に曖昧さ無くtranslationできるように、境界を調整していく必要があります。「コンテキストの境界を見定めて、その後各境界内にてユビキタス言語を構築する」というアプローチではなく、「曖昧さ無く矛盾無く双方向にtranslationができるようなユビキタス言語が構築できるように、コンテキストの境界を定める」というアプローチが必要とされます。
 
 
<追記>
・・・と、ここまで(だいぶ時間をかけて)一旦書いたのですが、何やら予感がしたので改めてDDD本第4部を確認しました。そうしたらあろうことか、「第14章 モデルの整合性を維持する」とほとんど同じテーマ立て、ほとんど同じ論旨の記事になっていました。特に「重複した概念」(※本記事での書籍の「返品」)、「偽同族語」(※本記事での「ジャンル」)を捉えての話と、「象のモデルを統一する」話から「モデルコンテキスト戦略を選択する」話への流れ(※本記事でのFact-Truth論)あたりが全く同じですね。長い旅に出て、ふとどこかで見たことある街だと思ったら、いつの間にか故郷に戻っていた、というような感覚です。。
 
◆以上

関連記事

ドメインとデータ、サブジェクトとオブジェクト、および、事実は常に事実であり、真実は常に仮説である、という話 - たなかこういちの開発ノート

「サブジェクト指向」について(私的実践DDD、その4)(2 of 2) - たなかこういちの開発ノート