Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

0063 号 巻頭言

DDD を理解したいあなたのための DDD 入門以前

Rubyist Magazine 63 号をお届けする。

突然のお知らせで恐縮だが、日本 Ruby の会の主たる事務所が東京から北海道に移転した。それもあってあまりまとまった時間がとれず、11 月のうちに書くはずだったのが気がつくと 12 月も半ばを過ぎていたので、今回は以前書きかけていた文章を発掘してお茶を濁したい。

Ruby とは直接関係がなくて恐縮だが、Ruby に限らずソフトウェア開発では現在でもちょくちょく話題になることがある、DDD についての話である。


ドメイン駆動設計こと DDD は 2020 年代のソフトウェア開発でもよく話題にされるが、率直に言うとストレートにポジティブな評価が行われているとは言い難い。 どちらかというと、ある種マニアックで、対象分野が制限されており、また初心者にはとっつきにくいところがある手法と思われている節がある。

しかし、2000 年代の DDD はそのようなものではなく、当時主流であったオブジェクト指向ソフトウェア開発での主流における新たな開発・設計技法として提案されたものだったと感じている。 DDD を含めたソフトウェア開発を巡る議論の中で、この 20 年ほどの間に失われた評価・文脈があるのではないか。本稿では DDD そのものについての説明は最小限にとどめつつ、DDD が生まれた当時の状況を説明することで、DDD が現れた当時のソフトウェア開発を取り巻く風景を現代に蘇らせることを目的としている。

なお、本稿は筆者の個人的な理解に基づくものであり、DDD コミュニティやソフトウェア開発コミュニティでの一般的な理解とは異なるところもあるかもしれないことはあらかじめ断っておく。

ソフトウェア開発における困難

DDD はソフトウェア開発における困難に向き合っている。その「困難」とは、「ソフトウェア開発者は、自分が開発しているソフトウェアの対象分野に必ずしも詳しくない」という事実である。

ソフトウェアは様々な領域で使われている。言い換えると、ソフトウェアの対象分野はいくらでもある。そうすると、ソフトウェア開発者が知らない分野についても、うまいことソフトウェアを作る必要が生じてくる。 しかしながら、自分がよくわかっていないものを作るのが難しい、というのはソフトウェア開発者ではなくても容易に想像できるだろう。

この問題の解決策は本質的に 3 通りしかない。

  1. 対象分野に詳しいエキスパートがソフトウェア開発にも詳しくなる
  2. ソフトウェア開発に詳しい開発者が対象分野にも詳しくなる
  3. ソフトウェア開発者と対象分野のエキスパートが協力する

要は両方に詳しい人が作るか、片方ずつしか詳しくない人たちが協力し合うか、である。

最近よく聞かれる「ノーコード・ローコード」と呼ばれる手法やツールがあるが、これは 1. の方向でこの困難を解決する際に使われているツールだと言える。 それ以前にはエンドユーザーコンピューティング (EUC) という言葉もあったが、これも 1. の方法論を実現するための手法の一つであったとも考えられる。

この方法はある種の理想ではあるが、これだけではうまくいかない場合が多い、というのがソフトウェア開発の歴史が教える知見である (もっともこれは現状の知見であり、将来的には変わる可能性もある)。いずれにせよ、現時点では限界があることに真っ向から異議を唱える人は少ないと思われる。

一方で、2. の方法もありうるが、これもまた汎用的とは言い難い。現実で 2. が使われるパターンと言うと、ソフトウェア開発に関するサービスやツールを作る場合が多いのではないだろうか。つまりソフトウェア開発者が知っている対象分野に限定すればよいソフトウェアを開発しやすい、ということでもある。言うまでもなく、こちらも適用できるソフトウェアに限界がある。

その結果、消極的な選択として、3. の方法を取らざるを得ないことが少なからずある。……というところまでは、比較的多くの人の同意が得られるのではないか。

ソフトウェア開発におけるモデルとロールとしてのモデラー

しかしながら、ソフトウェア開発者と対象分野のエキスパートが協力したとして、一足飛びにソフトウェアの実装ができあがることはほとんどない。一定以上の複雑さを持っている場合はなおさらである。 実装の他に、ソフトウェアの実装に直接依存しない、すなわちもう少し抽象度が高い表現が必要となる。

さらに時代背景についても付け加えておきたい。 ソフトウェア開発の歴史において、初期のソフトウェア開発言語は表現力に乏しかった。これはソフトウェア開発言語の言語処理系 (と言語処理系を実行するハードウェア) の限界によるものである。 現代では当然のように使われる GC や型推論といった機構は、例えば 1980 年代では湯水の如く計算機リソースと実行時間を食いつぶしかねない代物であり、誰でも容易に使えるものではなかった。 その結果、現代から見た場合、対象分野の知見とソフトウェアの実装そのものとは、今以上にかけ離れたものであった。

このようなギャップを埋めるためのものとして使われる道具の一つに「モデル」がある。

モデルはソフトウェアやシステムについての表現の一種である。図 (ダイアグラム) として表現されることも多いが、必ずしも図であるとは限らず、文章で記述されることもある。 現代でも使われるモデル表現としては Unified Modeling Language こと UML があるが、それ以外にも ER 図であったり、あるいはデータフロー図といったものもある。 数学的・形式的な表現が使われることもあるが、もっとざっくりしたものであることも多い。

また、モデル、とりわけ図として表現されるモデルについては、ある程度「誰でも読める」ことを期待しやすい。 対象分野のエキスパートがソフトウェアの実装を読むことは非現実的であっても、モデルの図を見てあっているか・間違っているかを判断してもらうことはそれなりに現実的である。 それもあって、実装に先立ち、モデルを書くというワークフローが広まった。

しかし、ソフトウェア開発の困難は、モデルを導入すれば解決できるものでもない。モデルにもモデルの難しさがある。

  1. 適切なモデルを書くこと自体の難しさ
  2. 知識をモデルに落とし込むことの難しさ

最初の 1. については、モデルの表現能力が高まり記法が複雑化したり、モデルが対象とするシステムが複雑化していくと、「誰でも読める」とは言い難くなる。 ましてやそれを正しく書くことは困難になる。

それよりも問題なのは 2. である。モデルは対象分野を反映したものである以上、対象分野のエキスパートを中心に書く必要がある。 しかしながら、対象分野のエキスパートといえども、それを正確に記述し、伝える訓練は通常受けていない。そもそも暗黙的に理解しているだけで、それを第三者に伝えられるような理解をしているかも疑わしい。深く理解していることと、それを説明できることにはギャップがある。 もちろん対象分野のエキスパートはソフトウェア開発にも詳しくないため、どのようなシステムを作れば解決するかもわからない。 一方で、ソフトウェア開発者もエキスパートと組んでモデルを記述することは容易ではない。こちらも自分の知らない分野の知見を聞き出し、学ぶための訓練は受けていない。

そこで生まれたのが「モデラー」というロールである。 もちろん、モデルだけを書くことがモデラーの役割ではない。対象分野のエキスパートと組み、その知見を整理し、明示的 (explicit) に記述した上で、さらにシステム化しやすいようにする。 モデルはその活動の一部の成果物として書くもの、という位置づけである。なお、モデルを書く・作ることは「モデリング」とも呼ぶ。

その結果、ソフトウェア開発に関わるロールとして、「ソフトウェア開発者」「モデラー」「対象分野のエキスパート」の 3 つが導入されることとなった。 もちろんこれはロールであり、ソフトウェア開発者とモデラーが同一人物であったり、ソフトウェア開発者のチームの一部がモデラーだったりすることもある。

「設計」と「分析」の分割

さらにもう一組の言葉を導入したい。「設計」と「分析」である。

これまで書いてきたモデリングに関することは、広い意味での「設計」と呼ばれる活動である。とはいえこれは実装に先立つあれこれをすべて「設計」という言葉でくくるようなものであり、若干広すぎる。

モデルに関していうと、以下の 2 つを分けて考えて、それぞれを別の活動の成果物とするのが良いのではないかと考えられた。

  • 対象分野に関する知見を整理し、記述するためのモデル
  • それをこれからシステム化するためのモデル

前者は「分析モデル」、後者は「設計モデル」と呼ばれる。そして分析モデル等を成果物とする活動が「分析」であり、設計モデル等を成果物とする活動が「設計」とされる。

分析と設計はフェーズであるという捉え方もあったが、2000 年代に一世を風靡したオブジェクト指向開発プロセスフレームワークであるラショナル統一プロセス (RUP) では、分析と設計は別々のワークフローであり、その中でさらにフェーズが分かれ、また分析と設計は一部は並行して行われる形として整理されていた。

……長くなったが、ここまでが DDD に至るまでの前置きである。

DDD という開発手法

ここまでていねいに前提を説明しておくと、DDD とは何だったのかも説明しやすくなる。DDD とは以下のような特徴を持つ開発手法である。

  • 分析モデルと設計モデル (と実装モデル) を統一し、単独のモデルを分析から実装までに用いる (「モデル駆動設計」)
  • モデルの記述までしか行わず実装をしないモデラーを廃し、ソフトウェアの実装者とモデラーを融合させる (「実践的モデラ」)
  • ソフトウェア開発者と対象分野のエキスパート (ドメインエキスパート) が継続的に協力し、設計について理解を深め合う (「ユビキタス言語」、より深い洞察へ向かうリファクタリング、戦略的蒸留)

DDD の時代背景として重要なのは、Java 等のオブジェクト指向プログラミング言語が普及したことと、(当時としては) リッチなハードウェアリソースが使えるようになってきたため、プログラミング言語での表現力を当たり前に使えるようになってきたことが挙げられる。

それまではメモリをじゃぶじゃぶ使うようなプログラミングは忌避され (あるいはそもそもまともに動作せず)、コードにおいて豊かな表現力を追求することは二の次とされていた。 つまり分析モデルに近い実装を行うよりも、ハードウェアに優しいコーディングの方が重宝されていたとも言える。 DDD の時代になって、ようやくハードウェアの制約をあまり気にすることなく、より理想的な実装を追求できるようになってきたのではないか。 それを踏まえた上で、DDD では分析による知見をそのままコードとして実装することを目標とするようになった。

なお付け加えておくと、DDD でよく使われるリポジトリなどのアーキテクチャは、この統一モデルを実装するための手段である。 分析モデル・設計モデルが単独のモデルとして統一されている以上、他の実装に関わる機能は統一モデルには持たせず、モデルはモデルのみで他に依存せず完結させるのが適切な実装である、というのが DDD の考え方である。 言い換えると、このようなモデルが独立した形で実装されているのであれば、特にリポジトリ等は使わない形でも DDD にすることは可能ではある。

2 つ目の実践的モデラについては、これはどちらかというと経験則によるものではないかと思われる。

ソフトウェア開発においてある種の分業が機能することももちろんあるのだが、モデリングと実装を分業化して分断することはなかなかうまくいかない。その具体的な (失敗) 例は『エリック・エヴァンスのドメイン駆動設計』第 3 章にある「実践的モデラ (HANDS ON MODELERS)」 の節に書かれている。 DDD ではその経験のもと、さらに分析・設計でも実装でもモデルが統一されていることを踏まえた上で、適切なモデルは実装を行っていく際の知見を直接把握する必要があるとする。

この実践的モデラのプラクティスは、実装者とエキスパートの距離が近づくことにもつながっている。両者の間にモデラーが媒介者として割り込まないためである。

3 つ目は 1 つ目と 2 つ目を踏まえた DDD の核心になる。そこで導入されるのが「ユビキタス言語」や、より深い洞察へ向かうリファクタリング、そして戦略的蒸留である。

ユビキタス言語は名前ほどユビキタス=普遍ではない。それは「境界づけられたコンテキスト」の中のみでユビキタスな言語であり、その境界の外側では異なる言語を使っても良い。 これはそもそも対象分野のエキスパートが複数の対象分野ごとにおり、それぞれのエキスパートが異なる言葉や概念を使っていることをモデルに反映させるためである。 ドメインエキスパートの言葉をそのまま反映させるために導入されるものがユビキタス言語であり、また境界づけられたコンテキストである。

そして「より深い洞察へ向かうリファクタリング」というキーワード (これは『エリック・エヴァンスのドメイン駆動設計』の第 3 部の部タイトルである) について強調しておきたいこととしては、DDD が登場してきた時期はソフトウェア開発のプラクティスとしての「リファクタリング」が広まってきた時期と重なるということである。 旧来のソフトウェア開発では、「動いているコードは触るな」的な声が今以上に根強くあったが、リファクタリングはそれを廃してより良いコードに改良する風潮を広めることを後押しするものであった。

モデリングに詳しいモデラーを排除し、実装者がモデリングを行う場合、理想的なモデルを書く上での困難を増やしかねない。 少なくとも初期の実装を行っている際に理想的なモデルができあがっていることは現実的ではない (もっとも、優れたモデラーがいたとてしても現実的かどうかは疑問ではある)。 「リファクタリング」という概念は、この問題を解決するための手法として借用されている。 現実的には分析モデルや設計モデルには実行可能なユニットテスト的なものは存在しないため、厳密な意味でのリファクタリングとは異なるのだが、実装モデルも兼ねている統一モデルはリファクタリングを行うこともできる。このプラクティスを拡張することで、モデルを継続的に洗練させていくという DDD の考え方が実現可能な開発プロセスとなっている。

またこれを表現する言葉として (戦略的) 蒸留という言葉が導入されている。蒸留しなければ理想的なモデルは作られず、そして蒸留にはソフトウェア開発者とドメインエキスパートが協力しあうことが欠かせない。 ドメインエキスパートと対話しつつ継続的に蒸留させることで洗練されたモデルを実現する、という手法は自動テストやリファクタリングや CI などを駆使して顧客と対話しながら洗練されたソフトウェアを開発するという、当時のオブジェクト指向コミュニティで流行しつつあったアジャイルソフトウェア開発の影響が色濃く反映されている。

DDD とは、このような背景を踏まえて登場した開発手法である。

まとめ

本稿は DDD の失われたコンテクストを現代に復元するためのもので、言ってみれば DDD を理解するための大前提にすぎない。 これをもって DDD を完全に理解できるものでもないし、ましてやそのメリット・デメリットや導入方法が分かるものでもない。

このあとは、それぞれの状況や対象分野を踏まえて、DDD を導入にするかどうか、導入するにしてもどの程度参考にするかどうかを検討する必要はある。 あくまでその手助けとして本稿を読んでいただければ幸いである。