エバンスDDDでは説明できない
何もエバンス氏のドメイン駆動設計が時代に合わなくなったわけじゃないんです。
今日でもアジャイルとかスクラムとかとの親和性は高いと思っているんですが...
昔からいわゆる青本を見て「モデル駆動設計に偏っているなぁ」と思っていたんです。
で、最近、リファクタリングの観点リストをまとめる機会があって、その時にプログラミング言語の特性について色々と考えたんですが、その時に自然言語を含む「言語」と「モデリング」の関係を説明するには「ユビキタス言語」の解釈では全然足りなかったんですよ。
エバンス氏は「ユビキタス言語」について設計者がドメインエキスパートと直接話をしながらモデリングを行うためのツールと捉えていて、これが必要な理由を伝言ゲーム的な認識齟齬を防止するためとしています。
そのこと自体は良いのです。ただし、このユビキタス言語の言葉をプログラムの中でも使うことを推奨してるのですが、これって言語学の用語でピジン語 1 と呼ばれる自然言語(人の言語)のかなり特殊な使い方を推奨してるってことになるんですよ。
でもピジン語って文法がないから、ユビキタス言語ではドメインエキスパートと設計者のコミュニケーションと、プログラム・コードの間で文としての齟齬があっても構わないってことになるんです。そんなわけないですよね。もちろん仕事では大人な対応をするから、これが問題になることはないはずなんですが...
どうせなら矛盾の少ない体系を使いたいですよね?
というわけで越境を宣言します。
そもそも何故ドメイン駆動設計はユビキタス言語とモデル駆動設計で構成されるのか?
この設問に対して、皆さんなら何と答えますか?
かのエリック・エバンス氏も「なぜこの2つなのか」については述べていないようです。
他のフォロー本とかでも見かけないですね。なのでこれに対する答えを推測するならエンジニアリングやプログラミング言語の基本から判断材料を集めてくる必要があります。
あらゆるエンジニアリングの基本
「ユビキタス言語」と言うエバンス氏の造語を使うのをやめて「言葉の統一」と言う一般的な用語に置き換えれば、先の2つはドメイン駆動設計どころかソフトウェア設計の枠も外れて、全ての設計の基本中の基本になります。
そう、「言葉の統一」と「モデル駆動設計」はあらゆるエンジニアリングの基本です。
ソフトウェア開発の場合はプログラミング言語という言語をツールとして使うので
前者の比重が他分野に比べて大きいのでしょうが、根本は変わりません。
後ほどその辺りも合わせて深掘りしていきますが、
その前にプログラミング言語の基礎について述べておきます。
ここからプログラミング言語は始まった
プログラムの3大要素の「状態、制御、演算」を知っている人は多いでしょう。
(まあ、私も記事で紹介しているし)
でもこれってCPUとかの動作原理、言い換えればハードウェア由来の要素なんですよね。ソフト屋としては「プログラミング言語が言語である所以である」純然たる「プログラミング言語の基本要素」も気になります。
言い換えれば「マシン語とプログラミング言語の最初の違い」って何でしょうか?
型?いえいえ。
答えは「ラベル」です。普通の言葉で言えば「名前」ですね。このラベルを加えることで、言語と言うより装置の一部だったマシン語は人が操るプログラミング言語に成りました。つまりラベルが存在しないプログラミング言語はありません。
では、そのラベルの役割は何か?
それは名前に紐づいた何かを思い起させる事です。
いわゆる「連想」ってやつですね。
この「連想」と「論理構造(実処理)」の2つこそがプログラミング言語の最も基礎的な要素ってことになります。プログラミング言語にはフラクタル性があるのでこの要素もプログラミングのあらゆる箇所で形を変えて顔を覗かせます。
「連想配列と配列」が代表例ですね。
他にも「関数変数と無名関数」とか、「クロージャ引数の名前アリと名前無し」とか、
この対比が適用できる要素はソフトウェアとその開発工程に偏在しています。
感が良い人はもうお分かりでしょうが
「ユビキタス言語とモデル駆動設計」も設計過程における「連想と論理構造」の発露です。
では、エバンスDDDの基本は「プログラミング言語の2大要素」から来ているのでしょうか?
もしそうなら「連想」についての深い記述があるはずなので、残念ながらおそらく違います。
青本の傾向から見ておそらくエバンス氏は独自の経験則として導き出したのでしょう。先ほどの問いの答えは出てしまいましたね。
だがしかし、私が推したいのは「連想と論理構造」です。
こっちだと以下のような良いことがあります。
- ソフトウェア独自の事象により深く言及できる。
- 各ラベルのネーミング基準を説明しやすい。
- 文単位の約束事に対する説明がしやすい。
- 論理構造に対する設計基準を定めやすい。
- ドメイン駆動設計の始まりがプログラミング言語の始まりと同期する。
個々のメリットは詳細の中で述べますが、注目すべきは「始まりの同期」です。
極論なのは間違い無いでしょうけど浪漫がありますよね?
だって80年ぐらい前にはDDDしてた可能性があるんですよ!
...さて、妄想はこれぐらいにして、そろそろ深掘りしましょうか?
プログラミング言語とソフトウェア設計の基本を同期させる
ここからがようやく本番です。
ここでは「連想と論理構造」がソフトウェアの設計や実装、さらにはDDDと「どう関係しているのか」を述べます。
連想と言語
プログラミング言語に限らず、全ての言語は常に「連想」を伴います。
単語に限らず慣用句や文でも人が何らかの事象を思い浮かべることで言語はその役割を果たします。
この時に個々の受け手が別々の事象を思い浮かべたらコミュニケーションが成立しませんから
ソフトウェアに限らず複数の人が集まって作業する場合は「言葉の統一」は必須事項です。
ソフトウェア開発の場合は「人の言語」と「プログラミング言語」の2種類を同時に扱うので
この両者も可能な限り統合して同じ言葉を使うようにする必要があります。
じゃないと開発者自身が混乱しますから。
と、ここまでが「ユビキタス言語」とか「連想する内容を他人と合わせる」話でした。
だがしかし、日々プログラミングをしていて直面するのはもっと根本的な問題なんですよね。
そう、「そもそも連想できない」つまりは「何書いてんのかサッパリわからん」ってやつです。
これが読み手の知識不足や技術不足なら「学習してください」と言えるのですが、
実際のところ書き手の力不足が原因なことが多くて、しかも教材らしきものが出回っていないので「良いソースをたくさん読め」とか雑なアドバイスしかしてないのが現状です。
ただ、この方法だと数年単位の時間が必要ですし、そもそもそこまで努力できる人が稀なんですよね。
私もそんな面倒なことはイヤです。
と言うわけでもう少し詳しいアドバイスをしましょう。
個々の名前をつける際に、何となく思い浮かんだ言葉を翻訳するのではなく
「連想の速度と精度の最大化」というテーマに取り組んでみてください。
続けるのは大変でしょうが、確実にコードの読みやすさが向上するはずです。
論理構造とモデリング
ソフトウェア設計に限らず全ての設計はモデリングという工程を通ります。
モデリングとは「形作ること」つまりは何らかの構造を作るってことです。
ソフトウェア開発ではその構造が論理構造になります。
では論理構造って何でしょうか?
一番単純かつ難解な二値論理から始まり、型や関数とかモナド、あるいはデザインパターン、ライブラリやフレームワークに至るまで、ソフトウェア開発で出てくる実装に関する概念のほぼ全てが論理構造です。
「モデル駆動設計」の「モデル」というのは「何らかの要件を満たすための論理構造」のことです。
粒度感的にはデザインパターンが一番このモデルに近いですね。
つまり1つもしくは数個のデザインパターンに相当する論理構造を作りながら設計を進めるのがモデル駆動設計です。
「何を当たり前のことを言っているんだ?」と思うかもしれませんが
ソフトウェア業界だと設計者の専門や経験からちょっと外れると応用が効かなくなって実装は現場任せになることがよくあります。こうしたケースの多くは実装段階で混乱します。ソフトウェア業界では技術の流行の移り変わりが早いですが、それらを追いかかるだけでは設計に必要な知見は身につきません。
あらゆる設計は「理論」と「実装技術」の両方に基づいています。
モデルも同じくこの2つがベースです。そしてソフトウェアではモデルは論理構造でできています。
論理構造やモデルは実装技術ではありませんが、ほぼ実装技術に直結しています。
同様に論理構造は理論や思想や哲学ではありませんが、それらに裏打ちされています。
「モデル駆動設計」では理論と実装技術に裏打ちされた論理構造を部品として使ってモデルを構築していくことで、先述のような混乱を起きにくくします。
言語構造と論理構造
プログラミング言語はラベルの他に型、制御コード、値といった要素で構成され、それらが組み合わさって文となって初めて命令や宣言として成立します。パーツが組み合わさって文になるのは自然言語と同じですが、自然言語と違って、CとかJavaとかSwiftといった汎用プログラミング言語は「言語構造」すなわち文法が「論理構造」とほぼ一致しています。
比較的わかり易いとされるPythonや、裏に沢山の論理構造を隠し持っているHaskellだってそれぞれの言語の論理構造と文法は一致しています。
このためプログラミング言語を使って直接モデリングを行うことが可能です。
この特徴は一見すると便利なようですが3つほど問題を抱えています。
一つ目の問題は冗長で読みにくくなりやすいことです。
型、変数、スコープ等の宣言は論理構造としては必要ですが、関心ドメインからは外れており、これらが増えると設計に集中できなくなります。この問題に対しては型推論や「シュガー・シンタックス」と呼ばれる簡易記法などの仕組みで冗長な部分を省略することで読みやすくする工夫がなされています。
もう一つの問題は言語が提供していない論理構造を構築するのが難しいことです。
これを解消するために他の言語へのインターフェースを提供したり、内部DSLを構築できるようにする工夫がなされています。
DSLとはDomain Specific Language の略で領域制限言語と訳されていますが、要は特定分野向で使われる論理構造を表現するための文法を持つプログラミング言語です。SQLとかHTMLとかYAMLなどが代表例ですね。jsonみたいに他の言語の一部だけを抜き出した変わり種もあります。
最後の問題は自然言語の文法から遠いことです。
近年は深層学習を使った自然言語解析などの研究も進んで、自然言語とコンピュータとの距離は縮まっていますが、それはそれ。
実際にはプログラミング言語と自然言語の差異はほとんど減っていないし、それどころかライブラリやフレームワークでは言語構造でも用語でも自然言語と大きくかけ離れた実装が日々増産されています。そのせいで言語よりライブラリの習得の方が難しいケースをそこそこ見かけたりします。
最後の問題は結構深刻ですね。
技術者の力量を図る試金石にもなっているので一概に否定できないのですが、せめて慣れたらサクサク爆速で書いたり読んだりできるように文法も合わせて気を使って欲しいところです。プログラムで使う単語のほとんどは英語ベースなので前置詞や助動詞や過去形、複数形の使い方ぐらいは合わせるべきだし、メソッド(モナド)チェーンを使った一連の文などでは句の分け方1つで読みやすさが大きく変わります。
でもって、そこを外したら、いくら頑張って論理構造を設計しても「読みづらくて保守性が悪い」という烙印を押されてしまいます。
特に理系学科の出身者は自然言語を操る訓練が足りていない(かつての自分もその典型でした)ことが多く「中身はしっかりしてるけど読みにくい」という勿体ない状況が頻発しがちなので要注意です。
ちなみにエバンス氏が提唱するユビキタス言語は青本を読む限りでは「IT版ピジン語 1」とでも言うべき「話し言葉」であり、かつ、DDDが「設計」を対象にしていることから、「実装言語」についてはほとんど触れられていません。確かに「設計」は特定の実装言語には左右されませんが、言語がサポートしている「論理構造」とは無縁じゃないし、プログラミング言語もPythonのように「クレオール語2」的な言語の方が読みやすい3ようなので、そのうち時代が変わるんじゃないですかねぇ。
DDDはどこから来て、どこにいくのか
「マシン語を人にわかり易くする」「そのために論理構造に名前をつけて言葉にする」というのがプログラミング言語の原点です。ソフトウェア設計もプログラミング言語を基にしている以上、これらから自由ではいられません。特に「言語の性質とモデリング」に着目しているドメイン駆動設計は最も原点に近い設計思想だと言えます。
ただし、エバンスDDDはオブジェクト指向を基にモデリングを行なっており、それより前の時代の構造化設計や旧い関数型プログラミングでDDDと呼べる設計ができていたのは未知数です。とはいえ旧いフローチャート図でもモデリングは可能ですし伝言ゲーム等の言葉の問題は普遍的なので、そこそこ旧い時代からDDD的な何かはあったことでしょう。
同様にモデリングのベースとなる論理構造が今後進化を遂げれば、DDDもまた進化していくのでしょうね。
結論
- それ!DDDの専売特許じゃないですから!(言語の統一とモデル駆動設計は全エンジニアリングの基本!)
- エバンス氏のDDDはプログラミング言語の問題には触れていないから、自分に言わせると物足りない。
(連想と論理構造 推し) - ドメイン駆動設計の起源はプログラミング言語と同じ!(浪漫)