[DDD] Maintaining Model IntegrityとModularity

いわゆる大手SIerのいわゆる大規模開発といった現場に遭遇すると、下請け業者が何社も参画していて、その会社間のインタフェースの整合性などの調整役で元請のひとたち(いわゆるスーツさん)が忙殺されているなんてことがある。「大規模開発だって、適度な大きさのチームに分割すれば1つ1つは小~中規模である。」というのは話を単純化しすぎている。チームが本当に隔離された状態でも独立して開発できるならそうとも言えるが、それらが完全な別システムでない限り何らかの連携があるはずで、あるチームが扱っているサブシステムに機能が追加されて出力が変更されると、別のチームのサブシステムに何らかの影響を及ぼすかもしれない。

DDDではそういったことにも言及していて、チーム間のモデルをどうやって整合させてゆくかということに対し、14章のMaintaining Model Integrityで述べている。

  • モデルの境界(おおよそチームが取り組む範囲)を BOUNDED CONTEXTで表現
  • BOUNDED CONTEXT間の関連や全体像を CONTEXT MAPで表現
  • BOUNDED CONTEXT間の関係は色々なパターンがある
    • 両極端なものを挙げると、モデルの一部を共有するSHARED KERNELというものや、完全に独立させる SEPARATE WAYSというものなど
  • (感想)UBIQUITOUS LANGUAGEというくらいなので、モデルはなるべく統一された1つを共有するもの(べき)という主張だと思い込んでいたが、意外と現実路線だった
    • モデルを共有すればするほど良いわけではない。共有部分の変更について、それを使っているチームとの整合性をとらなくてはいけないから
    • BOUNDED CONTEXTは理想形というよりは、ありのままを表現する。チームというのは政治的に決まる要素が多い(報告する上司・ルートが違うということでチームが分かれたりするものである)

DDDのパターンにMODULESがあるが(a.k.a PACKAGES)とあるように Javaでいう packageのこと。BOUNDED CONTEXTと MODULESは必ずしも1:1ではないが、境界を越えれば必ず異なるMODULEであるとのこと。つまり、1つのBOUNDED CONTEXT内で複数のMODULESがあっても良いが、CONTEXTをまたいで1つのMODULEというのは無いということか。(正直、英語の意味がうまく掴めなかった・・・)

ところで Java7からは落とされたが、OSGiやSuperpackageのように モジュールを実装する技術(Modularity)はこれからもっと進化していくだろうから、何をモジュールとするか、モジュール間の依存関係をどのようにするかというモジュール設計技術も進化していかないと意味がない。

ということで、DDD本をちょっと読み返したりしている。

参考:
JavaEE勉強会 DDD要約 Chapter Fourteen. Maintaining Model Integrity

[DDD] モデルって何だ?

前回のポスト(1ヶ月以上も経ってしまったが・・・^^;)の続き。
モデルって何だ?の問いに一言ふたことで答えようとすると、自分としては「関心ごとの捉え方」なんだけど、それだけでは???な感じになってしまう。ちゃんとした答え(というのがあるのか分からないけど)は、世の中の巨匠たちの記事や書籍に任せるとして、、
自分が身近な(DDDとか知らないけど興味を持っているくらいのレベルの)人に説明するとしたら、こんな風に言うだろうということを引き続き書いてみる。

まずは、とある先輩の言っていたことが自分の中で刺さったので、ほぼそのまま使わせてもらう

「水を顕微鏡でのぞいても、H2Oという文字が浮かんで見えるわけではない。モデルなんだ。」

H2Oとは言うまでもなく水のことで、化学式で水素2つと酸素1つであることを表している。
化学式を扱う人にとっての関心ごとであり、捉え方だ。
現実世界において、水というものは、飲料でもあるし炊事洗濯にも使われるし色々な側面があるけれども、それらはこのモデルでは関心ごとではないのだ。また、このモデルでは原子の関係として水を捉えているので、お湯でも氷でも水蒸気でも区別せず同じ水として捉えるということだ。

ドメインモデルも同じように、業務の「関心ごと」をどうとらえているか、を表す。
例えば、医療関係の業務において、自分は「患者」(「顧客」だけどね)として捉えられ、昭和○年○月○日生まれの男性で○○健康保険組合員だとか、子どものころ小児喘息だったことなどが関心ごとだろう。DDDに興味があって、それに絡めてBlog書いているなどいうことは間違いなく関心ごとではないだろう。
しかし、Amazonのような小売り代行の業務なら、「顧客」のそういった「嗜好」が関心ごととなり、DDD本を購入したとかチェックしたという履歴を嗜好と捉え、嗜好に関連する商品をおすすめしてくる。
(嗜好という概念、名前はこのblogで勝手に考えて付けたもので、実際中の人の捉え方とは違うかもしれないです。あくまで例です。)

モデルは現実の業務の捉え方を表す。
だけど、モデルが現実世界のエンティティの特徴を正確に、またはできるだけ多くを表現しようとする必要はない。極端だけど、もしamazonが会員登録の時に、「あなたの病歴を入力してください」などと促してきたら、商品をカートに入れて決済目前だったとしてもユーザーは立ち去ってしまうだろう。

そういえば最近のおすすめには、もう持っています。とか、興味ありません。を入れられるようにもなり、嗜好の情報をより入れられるようになった。
おすすめの商品を履歴から機械的に出力しているということが大分認知されてきているという流れで、追加で情報提供してもいいから、よりノイズの少ないおすすめ商品を求めるユーザーのために追加された機能なのかと思う。そういった情報はコンピュータの世界では履歴データ、ユーザー入力データであるが、業務の捉え方では、やはり嗜好(とか興味など)なんだと思う。

モデルが関心ごとであることと、捉え方であること、を例示してみた。もちろんこれは理解するための入り口であり、モデルとは何であるかということを包括的に説明しているもんでもない。(自分も勉強中だし)

モデルの持つその他のあんな側面こんな側面を羅列してもまとめきれないので、最後にリンクを貼って閉める。

[DDD]モデルは特定の図のことではない

ドメインモデルとは特定の図ではなく、図が伝えようとしている考え方である。

どうしてもモデル=UML、モデリング=UMLお絵かき を連想してしまう人は、なかなかこのことを理解できないかもしれない。しかし実際にDDDをやるとして(自分の場合は近い将来にはなさげだけど・・・)、「モデル」と言った時に人によって違うものを指しているようでは話にならない。まったく(ドメイン用語の)ユビキタス言語の実現よりほど遠い。
というわけで、自分が身近な人に説明するとしたらこんな風に言うだろうということを遠い未来のためにw書いてみた。

モデルと図(ダイアグラム)の関係は、設計と設計書の関係にあると思う。
ソフトウェアの設計とは、例えば クラス構成を考えてそれぞれのクラスの責務を考えたり、XXというライブラリを使うとか決めたり、などと言った、考えたことや決めた事そのものが設計だと思う。しかし伝統的な開発だと、設計を実装したりするのが別の人だという場合もあるし別の設計との整合性をレビューするためにも、その決めた事を他人に伝えるために可視化しなくてはいけない。そうやって可視化する方法の一つに設計書というものがあるわけだ。

もし一人で考えて簡単なツールをつくるくらいで設計書を書く人は普通はいないけど、設計書を書かなかったからと言って設計しなかった(つまり何も考えなかった)わけではない。考えたり決めたりしてから実装、また考えて実装…を細かく繰り返してやっているはずだ。
でも2人以上で開発するなら、あなた以外の人にはあなたの頭の中は見えないから、共有するためには最低限口頭で言葉にするか、何らかの可視化(ホワイトボードでもドキュメントでも)が必要となる。

まとめると:

  • 「設計」は考えたことや決めた事。方針。
  • 「設計」は頭の中にある。
  • 設計書を書くことは、設計をすることとイコールではない。
    • でも考えたり決めながら書いても悪くはない。それは厳密には設計とその可視化を細かく行い、相互にフィードバックを反映している。と、ここでは捉えてほしい
    • ちなみにこういう作業のやり方で、いきなり「清書」はしないないほうがよい

ところで、伝統的プロジェクトのマネージャが設計作業と設計書を書く作業を同じように捉えている(というか後者のみに着目して管理している)のは、彼/彼女にとってそれしか見えるものが無いのだから仕方ないことだ。それは受け入れてあげよう。だけど毎日3ページずつドキュメントが出来あがる計画を立案して進捗を管理しようとしたらそれは違うのだと教えてあげよう。設計作業はドキュメントライティングとは違うということを。同じように、プログラミングをタイプライティングと思ってるはずなので、それも指摘してあげよう。

さて、「設計」がそうであれば、頭の中にある「モデル」とは?
自分の日本語能力では一言でうまく言い表すことができないのだけれども、「関心ごとのとらえ方」というのが一番近いように思う。ダイアグラムはそれを可視化したもの。
ただ、このエントリでは「考えや思想」とそれを「可視化したもの」、「考えること」とそれを「可視化(文書化)すること」は区別するべきということが言いたかったので、ここまでにとどめておく。
というわけで、「モデル」とは何であるかについては、別の機会に書くことにしたい。

[DDD]なぜDDDなのか

なぜDDDなのか。自分がDDDの考えに共感している部分をDDD Quickly日本語版の6章Eric Evansへのインタビューから引用しつつ書いてみる。

-引用-

長い目で見れば、ソフトウエア開発は業務の心臓部の奥深くにある、より複雑な問題を扱う方向へ進んでいます。

たしかに、機械語を書いていたころから比べれば、ソフトウェアの開発技術は、どんどん人間が理解できやすい方向に、また人間のやりたいことを表現しやすい方向に向かっているはず。

-引用-

しかし、J2EEが現れると、フレームワークの巨大なコードの山の下にJavaの基本的な表現方法が埋もれてしまいました。そして初期にできた慣例(例えばEJBHomeやすべての変数にget/setプレフィックス付きのアクセサをつける、というような)に従うことで恐ろしいオブジェクトが出来上がりました。開発ツールもとても使いにくく、チームの労力のすべてがツールを動かすことに費やされてしまいました。 そして一度汚いコードやxmlを生成してしまったら、オブジェクトを変更するのはとても難しく、その結果、だれも変更しようとはしませんでした。

DDD本でもよく悪例として登場する EJBHome。当時はその複雑さを扱うことがある意味「技術」だった気がする。IDEやツールなどで、元々の複雑であるものをシンプルなものに変えようと頑張っていたと思うけど、それはかなわなかった。

-引用-

こういう困難な状況がありましたが、ここ4年間で事態は変わりました。(中略)様々な新しいフレームワークが生まれ (そのほとんどはオープンソース)継続的に改善されています。HibernateやSpringのようなフレームワークはJ2EEの特定の領域を扱いますが、よりライトな方法をとります。AJAXのような手法はより少ない労力でUIの諸問題を解決しようとする試みでしょう。価値あるJ2EEの要素を選び出し、新しい要素と組み合わせることについてはプロジェクトは賢くなっています。このような新しい動向の中でPOJOという言葉が生まれました。

-引用-

また、この間にアジャイルプロセスが十分に普及しました。いまやプロジェクトのほとんどが反復開発や、ビジネスパートナーと一緒に働くことや、モジュールを継続的に統合すること、コミュニケーションしやすい環境で作業をすることに最低限の注意を払っています。

-引用-

だからDDDは、今後さらに重要になるでしょう。そしてそのための基盤が作られていくように思えます。

ソフトウェア開発をとりまく状況はドメインの心臓部に注力できる方向へ、再度歩みを進めた!

-引用-

ソフトウエアのユーザの業務ドメインに含まれる深い問題に注力しなければならない、という原則

-引用-

この原則は決して廃れることがないでしょう。複雑に入り組んだドメインを扱うときにはいつでも適応できる原則だからです

正直、DDDを扱うためのインフラ(フレームワークなど)がまだ成熟していないというか、より重要なドメインの問題に取り組む前に、動かなきゃ意味ないし。(まだまだ動かすために注力しなくてはいけない)というのが現状だと感じている。だが、大きな流れとしては、インフラはより扱いやすくなり、よりドメインの問題に注力できるようになっていくはずだ(べきだ。)そういう時代がいつ来るか分からないけれども。

ところで、建築家(リアルなアーキテクト)の人は普通の建物のいわゆる「設計」をほとんどしないらしい。何を建てるかによって、どう建てるかは最初から決まっているのだと聞く。自分のイメージとしては、ソフトウェア工業も成熟するにつれ、技術的な組み合わせについては最終的に建築なみの決まり事のようにになると想像している。もちろん、東京ビッグサイトみたいな特殊で一度きりの建物はスクラッチで設計するのかもしれないが。
ビジネスソフトウェアの場合も、共通的、普遍的な業務ならパッケージが用意されていて、建物のアーキテクトのように決まりきった既製品でカバーできるようにいずれなるだろう。
しかし商売というものは、競合するライバルがやらないことをやって競うものだから、すべての業務が同じにはならないので、すべてを既製品ではカバーできない。
逆にいうと、それぞれの商売の固有の問題が業務の心臓部なのだから、それを解決するのがビジネスソフトウェアの本当のミッションだ。
「DDDは 原則(principle)である。」とはこういうことなのではないか、そんな風に思った。

[DDD]もしドメインモデルを日本語コードで書いたら2

前に書いたもしドメインモデルを日本語コードで書いたらをやってみたが、やはりプログラミング言語は英語圏の人が理解しやすいように設計されていると再認識した。
元々は、機械語を読んだり書いたりしたくないから、日常使う言葉で、あるいはそれに近い言語でプログラミングしたかったから生まれたのだろうけど、たまたま英語圏の人が発明したのか、世界で広く使われているからそうしたのか、いずれにしろ現代のプログラミング言語は自分が知ってる(狭い)限り、「読める」という以上に英語的に「理解できる」表現なのではないだろうかと思う。逆に言うと、普段使っている言語で読み書きする概念をコードで表現やすいということではないだろうか、とも。
(自分が苦労しているのは単に能力が低いからというのもあるが・・・)

もちろんあらゆる英語表現をプログラミング言語で書けるわけではないし割り切りはある。だがそれにしても、日本語を母国語にしているせいでいくらかハンディを負っている気がしてならない。日本語表現をそのままプログラミング言語で表現できないこともそうだが、英語圏の人に向けて作られたプログラミングモデル(コンピュータシステムに仕事を命令する仕組み)をそのまま日本語で理解できない、というか普段は日本人がそういった物のとらえ方や理解の仕方をしていない、のではないかという気がしてならない。あくまで感覚的な話だけれども。

というわけで、なんとなく自分が苦戦しているような気がする日本語の問題を網羅的でもなんでもなく思いつくまま挙げてみる。
問題といっても日本語が悪いとかいうのではなく、うまく概念を表現できていなかったり、共通理解に至らずに終わってしまいがちだというものである。

複数形

オブジェクトにしろ ER的な関係にしろ、エンティティ間の多重度は意識せざるを得ない。しかし日本語には複数形の表現がないので、英語ほど一言では済まない。
なお、先の日記で荷役イベントたちなどと書いたが、「~たち」というのは、厳密には英語の複数形とは異なる。

英語と異なり、「猫たち」といってもそれは猫だけが何匹もいるとは限らず、猫を含めて犬や鼠、鳥…といった動物が総合的に複数いることを表すこともある。そのため「山田君たち」という表現が成立し、それは何人もの山田君がいるのではなく、山田君を代表とするグループで複数の人間がいることを示している。

Wikipedia(数(文法))より

冠詞

冠詞は本当に苦手なのだが、大体こうだと思っている。

  • Cargo : 総称としての貨物(クラス)
  • the Cargo: 特定の貨物(インスタンス)
  • a Cargo : とある貨物(インスタンス)

英語では強制的にというか、これらを意識しているから話せるわけで。日本語ではそこまで厳密に区別しないである程度話すことができる(できてしまう)

文の構造

語の順番が英語で言うSVO型ではないこと。

日本語文の基本的な構造は、「S(主語 subject)‐V(動詞 verb)」というよりは、「S(主語)‐P(述語 predicate)」という「主述構造」と考えるほうが、より適当である
…(中略)…
また、日本語文では、主述構造とは別に、「題目‐述部」からなる「題述構造」をとることがきわめて多い。

Wikipedia(日本語#文の構造)より

題術構造とはこのようなことだろうか。

お急ぎ便の貨物は通常とは別の航路の船が搭載する。

またさらに主語やらいろいろ省略可能だということも苦戦を強いられる

(上記に続けて)
お急ぎ便でない場合は 通常の航路とする。

プログラミング言語は日本語のような題術構造はサポートしておらず、主体.操作(対象); というSVO型文法に変換しないといけない。
そして隠れた「主体」や「対象」を見つけ出す必要がある。

名づけVS匿名

上述のように、主語を省略できるという以外にも、「通常とは別のXX」といった表現が普通に使えて、特にそのXXについて名前を付けなくても誰も困らなかったりする。(クラス名を付けるのにだけ困るのだが、少なくともドメイン専門家は普段使っている言葉であり、特に困らない)
類似するものとして「その他」とか「特殊」というものある。
例えば運転免許証の大型特殊は、どう特殊なのだろうか。ロボットに変形できる?100人乗っても大丈夫?F1なみに速い?どれも特殊だ。
そういう特殊なものの種類がいくつかある場合、ありがちなのは、特殊区分Ⅰ、Ⅱなどとラベルを付けたりするのだが、その概念を示す言葉で呼称したりしない。
そもそも今まで名前の無かった概念に名前を付けるというのは、英語圏の人々にとって一般的なことなのだろうか。ビジネス書だけの世界なのだろうか。
少なくとも日本生まれの日本人の自分は、学校でも仕事でもそんな名づけの儀式のような機会に遭ったことがない。「例のアレ」で十分押し通すことができた。

まとめ

これまで挙げたものは、ドメインのモデラーなどという崇高な立場でもなく、非プログラマの人が書いたもしくはその人から訊いた仕様を実装するときによくありがちで、今までも気の利いた仕様策定者か(大抵そんな人は居ないので)プログラマが、仕様→実装変換を頑張ってきた、そんなものばかりだと思う。
ただ、日本語という言語にそのような特徴があるが、日本人は技術者以外それらの概念を理解できないのか、というとそんなことはないと思う。
DDDでのモデリングは、ドメイン専門家との対話を通じて(ドメイン専門家ですら気づいていなかった・あいまいだった)概念を明らかにする作業だ。日本語の場合はそれのスタート地点が英語圏に比べて(結構)後方だということなのかもしれない。
日本語だから絶対に出来ないというわけではない。ただ、そもそも忙しいドメイン専門家から話を聞くのに、相当なハンディを負っていると感じずにはいられない。

[DDD] もしドメインモデルを日本語のコードで書いたら

QCon Tokyo2011のビアパーティで、Eric Evans御大から「日本語でコードを書くべきだ!」というお告げがあったときいたので、試しにDDDSampleCargoクラスを日本語化してみた。

public class 貨物 {
	private 貨物ID 貨物ID;
	private 位置 出発地;
	private 経路仕様 経路仕様;
	private 輸送日程 輸送日程;
	private 配送 配送;

	public 貨物(final 貨物ID 貨物ID, final 経路仕様 経路仕様){
		this.貨物ID = 貨物ID;
		this.出発地 = 経路仕様.出発地();
		this.経路仕様 = 経路仕様;
		this.配送 = 配送.導出する(経路仕様, 輸送日程, 荷役履歴.空);
	}

	// ...	略
}

なんか、目に悪い気がする・・・

日本語コードの問題

実際書いてみて色々不便なことや困ったことがあったので、代表的なものを以下に書いてみる。

キャメルケース(Wikipedia)

JavaのNaming ConvensionではRouteSpecificationrouteSpecificationのように型と変数は最初の文字が大文字か小文字かで区別される。しかし、日本語には大文字・小文字という概念がないので、まったくおなじに記述される。

public 貨物(final 貨物ID 貨物ID, final 経路仕様 経路仕様){
	this.貨物ID = 貨物ID;
	this.経路仕様 = 経路仕様;
}

日本語で書いた途端、「経路仕様」が型(総称的な…)なのかローカル変数(とある…)なのかメンバ(特定の貨物の…)なのか、文脈で考えなくてはいけなくなる。
まぁこれはこれで、あるいみ日本らしくなった気がするw

Eclipseだとメンバ変数の色を変えて表示してくれる。
貨物.java in Eclipse

色はある程度カスタマイズできるはずなので、Eclipseにおせーてもらえば結構イケるかも。
読めなくなっている14行目は

this.配送 = 配送.導出する(経路仕様, 輸送日程, 荷役履歴.空);

と書いているのだけど、導出する()staticメソッドなので斜体で表示されており、フォントがマズくてつぶれて読めなくなっている。というか斜体がイケてる日本語のフォントってあるのかな。

ところで、14行目の警告はこれ。

The static method 導出する(経路仕様, 輸送日程, 荷役履歴) from the type 配送 should be accessed in a static way

上記の通り、配送.導出する()メソッドはstaticなのだが、コンパイラがメンバ変数の「(this.)配送」と判断してしまっている。メンバ変数名を「配送」にしたままstaticなコールってできるんだろうか。
まぁこれはコーディングルールとして変数を _配送 とするとか、逃げ道はある。

複数形

例えばこういうこと。
List<荷役イベント>たち;

public class 荷役履歴 {
	private final List<荷役イベント> 荷役イベントたち;

	public 荷役履歴(Collection<荷役イベント> 荷役イベントたち){
		this.荷役イベントたち = new ArrayList<荷役イベント>(荷役イベントたち);
	}
}

類似品

// オマイラっていいますからね
List<荷役イベント> 荷役イベントら;
// ちょ、Domain Expart、言葉汚くない?
List<荷役イベント> 荷役イベントども;
// 何て発音するんだ?「荷役イベントイベント」か?山々とか人々とかにしか使っちゃいかんだろこれは
List<荷役イベント> 荷役イベント々;
// これ書いたら負けだと思ってる。
List<荷役イベント> 荷役イベントs;

// それから、プログラミング言語APIの名前からユビキタス言語を作るのもダメだと思う。
List<荷役イベント> 荷役イベントリスト;
Collection<荷役イベント> 荷役イベント集まり;
Set<荷役イベント> 荷役イベント集合;

プログラミング

// 全力で打った private void
pりヴぁて ヴぉいd

コーディングはリズム重要!普段はコメントも覚書は英語かローマ字で書いておいて、javadocとともに後で清書する派なので。IMEのON/OFFを切り替えるだけでもかなりウザい。
でも、型、変数、メソッドが全角で、予約語、括弧{}().(ドット)やスペースは半角なわけでリズムはかなり悪い。IMEの使い方がヘボいのもあるけど。
それといつの間にか全角スペースが混入するので、JStyleなどで表示させてないとハマる。全角の括弧もフォント的に見分けがつきにくいし、何らかの日本語入力支援をIDE(のplugin)で実現しないとツライ。

Eclipseのコード補完は普通にバリバリ効く。

final 貨物 貨物;

ローカル変数の宣言も、右側の「貨物」はCtrl+Spaceで入力されたし、this. のあとのCtrl+Spaceなら、型から推測してくれるので、メソッドパラメータや戻り値の型に互換するメンバを候補に出してくれる。これは今までもEclipseがしてくれていたことだが、イチイチ日本語を打たなくてよいのでとてもありがたく感じた気がする

語の順番

配送.経路を更新する(this.経路仕様, this.輸送日程);

経路を更新する()のもとのコードは

Delivery#updateOnRouting(RouteSpecification, Itinerary)

なんだけど、これは自分とらえ方としては例えば

Delivery#updateOnRoutingWith(RouteSpecification, Itinerary)

のWith省略形だと思っていて、英語のS+V+O型に近いし 英語を話すDomain Expartも直感的に理解しやすいのかと想像している。
他方、経路を更新する(経路仕様, 輸送日程)というメソッドシグネチャがもう日本語的にイケてない。
日本語で自然に書こうとすると、自分の日本語能力では

配送#経路を更新するよこいつらで→(経路仕様, 輸送日程)

くらいしか思いつかない。

接続詞

上記同様、自然な日本語に近い書き方をしようとすると、これをどうしたらよいものか。

貨物 [ | | ] 経路 [ | | ] 更新する。

まとめ

DDDでは、ドメインの概念をユビキタス言語で表現し、それを会話でも使うし、コードでも使う。だから日本語でコード書いてみた。
やはりjava(に限らず、プログラミング言語一般的に)は、日本語の文法構造にはあっていない。わかっていたことだが・・・
日本語コードでドメインモデルを表現するには、現時点ではある程度割り切りが必要である。
将来的にはIDEが頑張れば解決する問題もある。
しかし、プログラミング言語構造とそもそも相容れない文法構造であることや、複数形のように日本語に存在しない概念もある。
ドメイン専門家との会話で「貨物たち」などという不自然な日本語を使うだろうか。

考えさせられたこと

日本語と英語とプログラミング言語について、いくつかある。
もうちょっとかんがえさせられてから、改めて書くことにする。