System Metapher パターンなんて、使うべきじゃない!

Domain-Driven Design の16章「構造」では、システム全体を、表現するテクニックとして、System Metapher パターンをあげている。

私は、メタファーテクニックは、賛成できないなあー。

エバンスも、

■ 使えるプロジェクトは、多くはない
■ メタファーは、しょせんは、本来のモデルではない借り物
■ メタファーを使う価値をプロジェクトの途中で、みなおすべき
■ メタファーの弊害に気が付いたら、メタファー利用を停止すべき
...

てな感じで、注意点を並べている。全体として、否定的なトーンを感じる。

Fire Wall


DDD では、ネットワーク上の Fire Wall ソフトウェアを、System Metapher が役に立っている例としてあげている。

イメージはぴったりかもしれない。

使うべき時


業務のプロが、使っているメタファーは、そのままドメインモデル、ユビキタス言語として、もちろん取り入れるべき。

プロジェクト管理という問題領域だと、火を噴くとか、火消しとか、言いますね。これは、プロジェクト管理ソフトのメタファーとして有効かもしれない。

火事の種類、火事の進行状況、火災の通報、消化方法の種類、...

現実世界の火事をモデルにした、全体モデルをつくれそうだなあ。

もっとも、火を噴いたプロジェクトを管理するソフトウェアを造っても、だれも使わないとは思いますが...

業務のプロの言葉に注意深く耳を傾ければ、ちょっとしたメタファー(別のドメインの概念から借りてきた概念)を使っているケースは、それなりにありそう。

でも、業務全体(=システム全体)を、借り物の概念でとらえることは、ほとんどないと思う。

ほんとうに、ある業務全体イメージを、別の領域のモデルから借り物でやっているドメインでは、借り物の概念を、そのまま、ドメインモデルとして、ユビキタス言語に取り入れるべきでしょう。

ソフトウェアをはじめ、IT の世界は、実は借り物(メタファー)だらけなんですよね。

プログラム、アプリケーション、ビルド、ネットワーク、コンピュータ、...

コンピュータ登場前から、使われていた言葉ばかり。

プログラム=式次第
アプリケーション=申し込み用紙
ビルド=建築
ネットワーク=網細工
コンピュータ=勘定方
...

てな感じですね。

期間限定で使うべき時


開発メンバーが、対象の問題領域が、ちんぷんかんぷんの時には、初心者向けのメタファーで、理解が早まるなら、使うのはあり。

サービスの提供( Service Delivery ) は、「物の出荷」(Shipment) と同じ、とかね。

おっと、「同じ」を使うと、メタファーじゃなくなっちゃうね。ルール違反。

○○の「ような」と使うのは、明喩。

メタファー(暗喩)というのは、「ような」抜きで、使うもの。

ソフトウェアのソースコードを「プログラム(式次第)」と言い切れば、りっぱなメタファー。

「プログラム(式次第)」の「ようなもの」と言えば、これは、明喩。

ようするに、メタファーというのは、本当は別の名前(概念)を、これが、そのものです、と言い切る言い方。

モデリングで使うのは、基本的には、まちがっている、というのが私の意見。

絶対禁止:カタカナのメタファー


カタカナ言葉のメタファーは、絶対使うべきではない。

Firewall : アメリカ人のチームなら OK
ファイアウォール : 禁止!
防火壁 : まあ、よしとしましょうか。

複数の人が聞いたときに、イメージにばらつきがある言葉は、絶対にさけなきゃいけない。

カタカナ言葉で、メタファー(暗喩)を使ったら、10人いたら、10人のイメージはばらばらです。

ソフトウェアやITで、日本で、とんちんかんな理解をされている技術が多いのは、カタカナ言葉+メタファーという、最悪のパターンの言葉が氾濫していらからだと思っている。

実際に、私たちのチームでは、「カタカナ」禁止のモデリングをしているけど、明らかに、メンバー間の意識合わせには、有効です。

ゴミ箱


マッキントッシュのデザインでは、メタファーが積極的に使われたことが有名。

「ゴミ箱」なんていうメタファーは、なかかなしゃれていた。

でもねえ、フロッピディスクを、取り出すために、フロッピアイコンを「ゴミ箱」に移動する、というのは、ひどいデザイン。

最初、ディスクが初期化されてしまいそうで、怖くて、できなかった。

私は、この時のトラウマ(?)があるので、メタファーの危険や失敗は、声を大にして主張したい。

メタファー(暗喩)は、モデリングのテクニックとしては、まちがっている。使うべきではない。

ドメイン層の構造の改善 : Evolving Order パターン

ドメイン層のオブジェクト群を、どういう視点で整理し、ドメイン層の構造を、どうやって育てていくか?

アプリケーション全体の構造


私たちのデフォルトのレイヤアーキテクチャは、

■インタフェース (UI、REST API、... )
■アプリケーションサービス
■ドメイン
■インフラストラクチャ(永続化、メッセージング)

です。

アプリケーションサービスは、ドメイン層の薄いファサード。
実際の仕事は、ドメインのオブジェクトに委譲する。

ドメイン層の構造


ドメインで扱うデータの種類が増え、ビジネスのロジックが膨らんでくると、ドメイン層も、構造化して整理しないと、わけが分からなくなる。

初めはトランザクションスクリプトだった


ドメイン駆動設計に取り組み始めたころは、ドメイン層の設計パターンは、ドメインモデルではなくトランザクションスクリプトでやっていた。

ユースケースごとに トランザクションスクリプトのクラスを作っていた。

「会員を登録する」というユースケースに、会員登録サービスのクラス。
会員登録の画面コントローラに、トランザクションスクリプトを直接書いたりしていたけど、さすがに、UI や「ビュー」依存のコードとは、分けたかったので、画面コントローラから、呼び出すトランザクションスクリプトを、独立させて、別クラスにしていた。

このトランザクションスクリプトクラスは、いちおう、ドメインの「データ+ロジック」だったので、当時は、これを「ドメインモデル」パターンだと思っていた。

実際には、データの入れ物クラスが別にあって、それを参照する方式。
データの入れ物クラスを、セッションに保存しながら、画面をまたがった処理をしていく。

Public なデータの入れ物クラスを、セッションに保存して、後続のクラスが、自由に使う。
先行したクラスの処理と、後続のクラスの処理は、整合性は、無頓着。

なんてことはない、グローバル変数を、いくつかまとめた、グローバル変数オブジェクトを、せっせと作っていただけ。

グローバル変数オブジェクトを、複数の処理手続きクラスが、無秩序に、変更して参照する、完全なアンチパターン。

グローバル変数オブジェクトを、作成してセッションに保存する手続きと、それを参照する手続きが、ひとつのユースケースで、一人のメンバーで、一回こっきりの作り捨て、という場合は、これでも、破綻しない。

でも、実際には、中核の「グローバル変数オブジェクト」は、いろいろなユースケースで、いろいろな開発メンバーが、いろいろな理由で、コードを変更しちゃう。

「グローバル変数オブジェクト」のそれぞれのフィールドの意味や使い方が、だんだん、処理手続きクラスごとに、違ってくる。変更のたびに、怪しげなコードが膨らんでいく。

こうなってくると、あとは、破綻の道をまっしぐらです。

ロジックとデータをいっしょに


ここ2年間くらい、データと関連するロジックは、同じクラスに書く、というドメインモデル風のオブジェクト設計をこころがけてきた。

Date クラスや Money クラスに日付のロジック(ビジネスの知識)をまとめておく、というような Value Object スタイルの設計・実装がだんだん増えてきた。

関心事オブジェクト ( Object of Concern ) 、例えば、会員オブジェクトや、商品オブジェクトの状態の持ち方や、状態に依存したビジネスルールという知識をまとめることも、少しずつ増えてきた。

トランザクションスクリプトを、全面的にドメインモデルに切り替えたわけではない。

「データとロジックを一つのクラス」に、という方針で、小さなリファクタリング(設計改善)を続けたら、なんとなく、ドメインモデルに近づいてきたかなあ、という感じ。

今も、構造は、ユースケース単位


リファクタリングの出発点が、ユースケース単位のトランザクションスクリプトだから、現在でも、ユースケース単位に、ドメインオブジェクトをパッケージングしたがる。

ユースケース単位で、担当割りして、どっちのユースケースが、どのドメインオブジェクトを面倒みるか、というような議論をいまでも、しがち。

発想の転換のこころみ


ユースケース単位ではなく、次のようなパッケージング単位を指向しているが、なかなか、それが自然な設計スタイルになってきていないのが現状。

■関心事オブジェクト(Object of Concern) ごとのパッケージ構成

関心事オブジェクトごとのパッケージ。

例えば、顧客について、

◇顧客エンティティ(識別情報+以下の Value Object への参照)
◇顧客の最新の状態(応募とその回答状況、最後のアクセス時間、利用回数、... )
◇顧客の活動履歴 ( 応募履歴、アクセス履歴、... )

などを、ひとつのパッケージにする。

DDD(Domain-Driven Design) 的には、エンティティのアグリゲート単位のパッケージ。

■トランザクションイベントパッケージ

トランザクションイベントを表現するオブジェクトを集める。

トランザクションイベントというのは、例えば、応募した、とか、回答した、とかいう、アクタのアクション単位の記録。

トランザクションイベントが発生すると、「関心事オブジェクト」の状態を変更し、活動履歴に、記録を追加する。

参照方向は、トランザクションオブジェクトから、関心事オブジェクトへの片方向。

イベントオブジェクトは、どの関心事オブジェクトを、どう変更すべきか知っているけど、関心事オブジェクトは、どんなイベントが自分を変更したか、しらない、というモデル。

DDD Sample では、こうなっていないで、関心事オブジェクトとイベントが循環参照、つまり双方向になっている。

あれは、片方向に設計改善したほうが、すっきりするんだけどなあ。

トランザクションイベントパッケージのドメインオブジェクトは、

◇イベントタイプ (列挙型クラス)
◇イベント (何を、誰が、いつ、どのイベントタイプを、を「記録」する)
◇メッセージ (発生したイベントを、適切なアクタに、「通知」する)

記録(永続化)と、通知(メッセージング)は、ビジネスアプリケーションの根幹の機能です。

実装技術としては、データベース技術であり、非同期メッセージング(含む、電子メール)ですね。

ドメインの重要な関心事である「記録」と「通知」を、実現する手段が、データベースであり、メッセージングサーバー、ということ。

ユースケースに依存した構造から離れる


「関心事オブジェクト」パッケージと、「トランザクションイベント」パッケージ、という構造で、ドメイン層を整理していくと、自然にユースケース単位のパッケージではなくなる。

ドメイン層の構造と、ユースケースモデルの構造が別になる。

ユースケース単位に、アプリケーションサービスクラスを作って、こいつが、ドメインモデルを使って、役に立つことを実行してくれる。(処理の大半は、ドメインオブジェクト側で行う)

ここまで、くると、まさに、PoEAA や、DDD で言っている、ドメインロジックを「ドメインモデル」で実装するパターンになる。

ここがスタートライン


ドメインモデルのリファクタリングがここからが本番。
これまでの設計改善は、ユースケース単位のトランザクションスクリプトから、ドメインの関心事単位の、ドメインモデルへの設計変更。

これは、ドメインモデルありき、というより、「関連するデータとコードは一つのクラス」という発想を重視したら、結果として、ドメインモデルになってきた、ということ。

トランザクションスクリプトがだめで、ドメインモデルだけが正しい設計パターン、なんて考えているわけではない。

Evolving Order パターン


DDD 16章の Evolving Order パターンを読みながら、書き始めたら、ちょっと、違った、Evolving Order (育てる順番)ストーリーになっちゃったなあ。

しかも、エバンスが、「最初に構造ありき」は危険。設計者の発想の自由を奪う力説しているのに、こっちは、「関心事オブジェクト」パターンと「トランザクションイベント」パターンなるものを、構造設計のデフォルトとして、持ち出している。

まあ、エバンスも、「白紙」からの格闘は、時間のロスといっている。
DDD 書いたときには登場しなかった「ドメインイベント」を、最近は entity や value object と並んだ存在で力説している。
ファウラーも、「ドメインイベント」や「イベントソーシング」を PoEAA 書いた後で、発見(?)している。

自分の経験からも、「トランザクションイベント」が「関心事オブジェクト」を変更する、という設計パターンは、ビジネスアプリケーションの基本だと思っている。

ドメイン層のデフォルトの分析・設計パターンとして、「イベント」が「関心事」を変更する、というパターンは、なかなか、よいと思っている。

ガウディ、すごい

スペインのバルセロナに行って、サグラダファミリア教会、見てきた。
すごかった。圧倒されました。

個人的には、自然の植物や動物は、自然のものが一番で、それを、人工物のモチーフにした、ガウディのデザインって、好きになれない(と思っていた)
人工物の設計は、エンジンむき出しのバイクとか、F1やジェット戦闘機、M-16ライフルとか、ローマの水道橋とか、実用一点張り、機能美を追求すべきと思っていた。

でも、サグラダファミリアで、実物みて、設計のスケッチとかも見たら、一気にふっとんだ。
すごいのひとことです。自然をほんとうに見つめて、つきつめて造形すると、こうなるのか、という衝撃を受けた。

自然というエネルギーと、人のよる造形のエネルギーが、私の理解を超えたところで、共振している。
頭の中で、どこかで、がんがんへんな音をたてている場所ができちゃった感じ。

たぶん、ガウディの衝撃が、システム設計とどこかで、つながりはじめた音なんだと思う。

もうひとつ、印象的だったのは、中世の石職人が、地道に大聖堂を建てていく雰囲気が、濃厚にただよう現場だったこと。

完成後よりも、ようやく全体像が見えてきた今の時期に行ったのは、とても、幸せなタイミングだったかもしれない。

500年前にも、こういう感じで、聖堂を創っていたんだろうなあ、という、ちょっとしたタイムスリップ気分。
ヨーロッパの建設工事って、今でも、新しい歩道も、石職人が昔ながらの雰囲気で、地道に作っていたりして、いいんですよねえ。

ドメインモデルの構造設計

Domain-Driven Design (DDD) 第16章 Large Scale Structure (構造) のテーマは、ドメインモデルの内部の構造の設計。

システム全体のアーキテクチャを

・UI層
・アプリケーションサービス層
・ドメインモデル層
・インフラ層

4層構造で設計する。

ドメインオブジェクトが増えてきて、ドメイン層が複雑になってくると、ドメイン層の中も、構造設計をしたほうが、わかりやすくなる。

大規模なモデルが対象?


エヴァンスは、プレゼンテーションで、「Large Scale Structure」のパターンを使うような規模のプロジェクトは少ない。

DDD で、この章は不要だったかもしれない、とか言っていた。

でも、私は、別の意見。

小規模でも、ドメインオブジェクトの構造は、きちんと設計すべき。
DDD の16章のパターンは、いつも使うべきテクニックがたくさん含まれている。

ドメインモデルの階層構造


16章には、Responsibility Layers パターンというのがある。

ようするに、ドメインモデルも階層構造で整理しよう、ということ。

ざっくり言えば、

上位層 ビジネスのルールやポリシーを表現したオブジェクト
中間層 ビジネスで日々発生するイベントを扱うオブジェクト
下位層 商品、店舗、顧客など、ビジネスの資産を表現したオブジェクト

というような階層構造。

商品の販売ビジネスなら

上位:「価格ルール」
中間:「受注」「出荷」「売上」「請求」「入金」
下位:「商品」「倉庫」「顧客」

というような感じ。

この層をどういう名前で呼ぶかは、いろいろな流儀がある。

私は、

上位:ポリシー層
中間:イベント層(イベント+ステータス更新層)
下位:リソース層

という整理の仕方を基本にしている。

そして、基本は、上の層から下の層へ単方向の、参照だけにするようにする。

「価格ルール」オブジェクトは、「受注」オブジェクト、「商品」オブジェクトを知っている(使う)。

「受注」オブジェクトは、「価格ルール」オブジェクトを知らない。
「受注」オブジェクトは、「商品」オブジェクトを知っている。

「商品」オブジェクトは、「受注」も「価格ルール」も知らない。

ドメインオブジェクトを、

・ポリシー
・イベント、ステータス
・リソース

の三階層に分け、参照方向を限定することで、ドメインモデルの構造を設計する。

これは、「大規模になってきたから、整理のために必要」なのではない。

「業務上の意味・役割が異なるオブジェクト」を分けて考える、というドメインの知識の表現手段として、役にたつということ。

ドメインオブジェクトが10個くらいの規模でも、役割別に、ドメインモデルを階層構造で設計することは、ドメインモデリングの基本テクニックなんです。

特に、「イベント」「ステータス」「リソース」の三つの概念は、業務のモデリングの基本中の基本。

リソース:「商品」を、「店舗」で、「顧客」に売る。

ポリシー:いくらで売るかのルール。

イベント:いつ、誰に、何を、いくつ売ったかの記録。

この三つで、ビジネスをとらえ、表現していくのが、業務アプリのモデリングの基本中の基本。

Domain-Driven Desing 15章のまとめ : Core Domain は DDD の基本プラクティス

エバンスは、セミナーで、15章の「コアドメイン」(問題の核心)は、Domain-Design Driven(DDD)本の、もっと前に書くべきだった。2章とか、3章に書くべきだった、というようなことをしゃべっていますね。

◎ユビキタス言語 (いつでも、どこでも、業務の言葉)
◎モデル駆動設計 (絵や文で、コミュニケーション)
◎Hands-on モデラ  (実際に、コードを書くモデラー)

という、ドメイン駆動設計の基本コンセプトのひとつとして「コアドメイン」を力説すべきだったと。

コアドメインの効用


Core Domain を見つけ出し、そこに、モデリング、設計・実装のエネルギーを集中する。

その他の部分は、Core Domain との関係(近い?遠い?)、Core Domain にとっての重要性、という視点で整理する。

Core Domain との関係が弱く、重要でもない部分は、できるだけ、コストをかけない。

もちろん、そういう部分も必須だし、バグがあったり、性能問題がでるようでは困る。

でも、Core Domain 以外は、できるだけ、時間をかけずに、必要最低限のものを手に入れることをいつも考える。

作業の順番も、Core Domain から開発していく。
初回のイテレーションは、Core Domain のドメインモデルの設計・実装から手をつける。

Core Domain を軸に、

・人の配置
・作業の順番
・モデルの構造
・設計の選択肢

を検討して、意思決定していくことで、役に立つソフトウェアを、もっとも、効果的に開発することができる。

アンチパターン


Core Domain が不明、関係者でイメージがばらばら、だと、プロジェクト期間を通して、みんなで苦労するけど、できあがったものは、動いてはいるけど、ただそれだけのソフトウェア。

仕様の変更や、拡張要求があった時も、どこをどういじるか、見通しが悪く、副作用が恐くて、うかつに変更はできない。

Core Domain パターン


Core Domain にこだわり続けたプロジェクトは、同じ時間とエネルギーを使っても、ソフトウェアで、もっとも価値を生み出す部分、差別化ポイントが、なんども改良され、レベルの高いものに仕上がってくる。

すべてのコンポーネントが、 Core Domain を中軸に、整理されている。

だから、仕様の変更や、拡張要求を、 Core Domain とどういう関係か判断すれば、変更すべき箇所や影響範囲が、すぐわかる。

Core Domain への変更なら、ここは、なんども改良してきているから、かなりいじりやすいはず。
副作用も心配ない。

Core Domain ではない、補助的な subdomain への仕様変更なら、それは、局所にカプセル化してあるので、安心して変更できる。

「原点」とか「軸」がしっかりしていれば、全体の見通しがよくなり、格段に扱いやすくなる。

それが、 Core Domain パターンの意図だし、実践する効果。

やり方


出発点は、プロジェクトの初期に作成する「コンテキスト図」に書き込んだ「システムの目的」ノート。

システム名とシステムの目的を表現するために、使った言葉、関係者で、同意された目的が、 Core Domain パターンの出発点になる。

詳細な要件の確認などが始まっても、いつも、この「システムの目的」=「Core Domain の要約」にこだわり続ける。

ドメイン層のオブジェクトが増えだしたら、パッケージ設計や、パッケージ間のクラスの移動をしながら、「 Core Domain 」を、具体的なコードで表現することにこだわる。

これが「Core Domain」だ、という宣言だけでは、不十分。

Core Domain 以外の補助的な Subdomain のパッケージ群、クラス群を、Core Domain との関係という視点で、いつも整理していく。

Core Domain を軸に、Core Domain との関係性で、全体を一貫して整理することで、大量のドメインオブジェクトを見渡すための、わかりやすい地図が手に入る。

Core Domain は、開発プロジェクトという山、ドメインオブジェクトなどのコードの海を、うまく航海していくための、羅針盤なんです。

Abstract Core パターンは、危険な臭い

エバンスは、Domain-Driven Design(DDD)で、Abstract Core パターンの説明で「多態性(ポリモーフィズム)」を取り上げている。

これは、技術者向けの説明として、とっても危険な臭いを感じる。

Object クラスと toString()


Java の技術者が、当たり前のように使っている「多態性」の例は、toString() メソッド。

すべてのオブジェクトは、Object クラスを拡張している。
そして、どのオブジェクトでも、オブジェクトの文字表現は、toString() という同じメソッド名を使う。

メソッド名は同じだけど、対象のオブジェクトによって、さまざまな文字表現が戻ってくる。

多態性の例としては、わかりやすい。

で、こういう「同じメソッド名」、「お約束のメソッド名」をいつでも使いたがる。

お約束のメソッド名なら、名前を考えなくてもいいから、楽だし、「わかりやすい」と思う。

問題は、その「お約束」は、誰のお約束で、誰にとって「わかりやすいか」ということ。

Java のプログラマなら、常識、事実上の標準みたいな、ネーミングも、ドメイン(問題領域)の表現手段として、適切とは限らない。
むしろ、不適切なことが多い。(技術者の常識は、業務の常識ではない)

この発想のギャップ、視点の違いを、きちんと意識して、ソフトウェアを開発しよう、というのが、ドメイン駆動設計の要点だと思う。

ユビキタス言語パターンは、ようするに「業務の言葉」をコードのあちこちで使う、ということ。

コードが、業務の言葉だらけになるほど、良い設計という価値観。

ドメイン駆動設計、ユビキタス言語パターンを丁寧に続けると、そのドメインの経験・知識が乏しい技術者にとっては、とんでもなく違和感のあるクラス名、メソッド名だらけになるはず。

逆にいえば、Java の技術者にとって、見慣れたクラス名やメソッド名がずらっと並んだ、ドメイン層の実装は、良くない設計、ということ。

私たちが取り組んでいる、人材ビジネスのドメインだと、応募は「Application」。

だから、Application パッケージとか、Application クラスが、ドメイン層の真ん中に、でーんと登場する。

一般的な技術用語としては、 ApplicationService クラスは、アプリケーション層のレイヤ抽象クラス。

でも、私たちの問題領域だと、ApplicationService は「応募」を扱う、具体的なサービスの名前。

ドメイン駆動設計じゃなければ、これは、技術者にとって、はなはだ気持ち悪いし、混乱の元だから、別の名前にすべきでしょうね。

でも、ドメイン駆動設計的には、Application は、業務の重要な関心事なので、この名前は、ドメイン層の名前として使うべき。

サービス層の、技術概念としての「アプリケーション」は、別の言葉を探す。

技術的にぎこちなくても、ドメイン中心に、設計・実装する、というのは、そういうことでしょう。

Abstract Core パターンの適切な進め方


エバンスも書いているけど、Core Domain を抽象化した Abstarct Core として設計・実装したパッケージ名、クラス名は、Domain Vision Statement パターンで書いた、そのドメインの「重要な関心事の要約」と、ほぼ、同じになる。

Domain Vision Statement は、技術者以外の関係者、特に、業務の専門家たちにわかりやすいように、普通の日本語の文章として、書く。

そして、Core Domain それをさらに要約した Abstract Core は、この「業務の重要な関心事の要約」そのものになっているはず。

Domain Vision Statement の初版は、プロジェクトの最初に書く。モデリング、設計・実装をやりながら、発見したこと、新たに理解したことを、反映して書きなおしていく。

そうやって、Domain Vision Statment を育てながら、ドメイン層のクラス群も育てていく。
いきつくところは、日本語で書かれたドメインの重要事項の要約と、それが、そのままパッケージとクラスになった、実際のコードになる。

適切な Abstract Core を設計・実装した、ということは、そのパッケージ/クラスを、素直に日本語で説明すれば、そのまま、業務の重要な関心事、こだわりポイントになっているはず。

技術的な視点の 抽象化、多態性にこだわった Abstract Core を、日本語にしても、それは、業務の専門家には、ちんぷんかんぷん。

モノは、ハッシュコードを持つ
人を拡張すると、従業員になる
...

Abstract Core パターンを適切に実践するには、いつも、Domain Vision Statement 片手に、業務の専門家と、その要約文の適切さを確認する。

そして、自分たちの設計・実装している、 Abstract Core が、その要約文を自然に表現しているか、謙虚に、検証してみる。

オブジェクト指向設計や Java プログラミングで一般的な設計パターン、用語、命名は、基本的には、業務の知識の表現として、不適切だと思ったほうが良い。

プログラミングの世界で覚えてきた、抽象化、継承、多態性、モジュール化、...

ドメイン層の設計パターンとしては、ほんとうは、利用できるテクニックなんだけど、問題は、覚え方。

抽象化を、Abstract 宣言として覚えた
抽象化を、馬と犬と猿と、哺乳類で覚えた
抽象化を、Object をルートとするクラス階層で覚えた
...

こういう発想を捨てた上で、 Abstract Core パターンに取り組めば、すばらしい仕事ができる。

この発想で、Abstract Core パターンに取り組むと、とんでもないソフトウェアができあがる。

もちろん、ドメイン駆動設計でも、Abstraction はとても重要な設計概念です。

ただし、どういう方向に抽象化していくか、という視点が、一般的なソフトウェア工学で語られる、内容とは、ちょっと、別の方向だということ。

もちろん、答えは、業務の専門家たちの言葉の中になる。

彼らが、さざまざな概念をまとめて一言で、表現した時、それを必死になってキャッチする。

あるいは、似たような言葉を使い分けたことを、敏感にキャッチする。
「取り消し」と「キャンセル」の二つの言葉がでてきたら、そこに、別の概念の臭いを感じ取る。
彼らをそれを別のものとして使い分けて、けして、一般化していない、ことに注目する。

コンパイラが、たった一文字違いのクラス名をきちんと識別するように、同じクラス名も、パッケージが違えば、ちゃんと識別するように、業務の言葉の、ちょっとした表現の違いに、注意深くなることが、ドメイン駆動設計では、とても重要だし、役に立つスキル。

Abstract Core パターンに取り組む、第一歩は、技術的な視点で覚えてきた 「Abstraction」をいったん、捨て去ること。

そして、業務の専門家が、どうやって、自分たちの知識を表現しているかに、注意深く耳を傾ける。
「顧客」という一般化を彼らは、ほんとうにしているのか?
「個人の顧客」と「法人の顧客」は、いつも、別の言葉(概念)で、けして「顧客」という一般化をしていないのでは?

こういう「業務の言葉」の使い方に敏感になることが、ドメイン駆動設計、良い設計と実装をするコツ。 Abstract Core パターンの実践の基本。

Core Domain を具体的に設計する : Segregated Core

Core Domain の実体は、"ステレオタイプ <<core>>" とマーキングした、パッケージになる。

山ほどある、ドメインオブジェクトの中で、重要なものを、集めて、パッケージに入れる。
そのパッケージに、<<core>> をマーキングすれば、いっちょうあがり?

まあ、ひと目でできるモデリングじゃないけど、基本的な作業を地道にやれば、それなりの Core Domain モデリングできるようになる。

Domain Vision Statement パターンや、Hilighted Core パターンは、実際のコードという形のあるパターンではない。 Core Domain をみんなで共通理解にするためのコミュニケーションのやり方。

Generic Subdomains パターンと Cohesive Mechanisms パターンは、設計・実装に直接関係する。
でも、Core Domain を直接、生み出すわけではない。

Segregated Core パターンは、Core Domain を、実際のコードにするための、モデリングと設計のやり方を具体的に説明している。

全体の流れ


Core Domainを具体的に設計・実装するのに、必要なモノ。

◎コンテキストモデル(一枚のシステム全体像)
◎主要なドメインオブジェクトを網羅した、ドメインクラス図
◎(黄、緑、ピンク、3色の)マーカー
◎モデルのリファクタリングの時間(開発チーム、全員参加)

ドメインオブジェクトを、ドメインクラス図を使って、黄/緑/ピンクのマーカーで、

◇ Core Domain 候補
◇ Generic Subdomains 候補
◇ Cohesive Mechanisms 候補

を色分けしてみる。

ある程度、方向が見えたら

●ドメインクラス図の描きなおし(パッケージの追加や、パッケージ間のクラスの移動)
●コードに反映( IDE のリファクタリングメニューが大活躍)

で、新しいバージョンのクラス図(パッケージ図)を作って、また色分け。
これの繰り返し。

3回も繰り返せば、だいぶ、Core Domain がしっかりしてくる。

羅針盤:コンテキストモデル


ドメインモデル全体を、やみくもに手をつけても、色分けしても、行き先が定まらず、ふらふら漂流するだけ。
忙しい、開発のさなかに、こんな無駄な作業を、やってはいけない。

羅針盤をにらみながら、いつも、最終目的地に向かって、最短のコースを進むように舵を切る。

モデリングで、その羅針盤になるのが、コンテキストモデル(一枚のシステム全体像)なんです。

コンテキストモデルには、

◎システム名
◎システムの基本目的

が書かれている。

コンテキストモデルに登場する言葉が、「問題の核心 ( Core Domain ) 」の羅針盤になる。
(参考: コンテキストのモデリング

コンテキストモデルに登場する言葉(概念)を直接表すドメインオブジェクト、関係の強いドメインオブジェクトは、Core Domain パッケージに含める有力候補。

コンテキストモデルにでてくる言葉と直接関係しないドメインオブジェクトは、Core Domain ではなく、Generic Subdomains の候補。
(Generic Subdomains が明らかなら、そういうパッケージを作って、せっせとそっちに放り込む)

システム名、システムの目的を書いた「言葉」と、ドメインオブジェクトを直接結びつけて、考えるのが、Core Domain パターンであり、ドメイン駆動設計の核心(最重要の課題)。

例:転職サイト


システム名が「転職サイト」で、目的の「仕事と求職者のマッチング」であれば、Core Domain パッケージ名の候補は、

◎転職
◎仕事
◎求職者
◎マッチング

になる。

で、このサイト独自の価値をどこに求めるかといえば、「マッチング」。

仕事内容、求職者情報、応募や面接という転職のプロセスは、他のサイトと比べて、大きな差別化ポイントになりにくい。
(求人企業も求職者も、他のサイトの利用者でもあるので、基本は同じものしかできない)

でも「マッチング」については、いろいろ工夫の余地がある。
「検索機能」とか「リコメンデーション」とかに、独自の差別化ポイントを創り出せる可能性がある。
たくさんのドメインオブジェクトを「マッチング」との距離が近いか、遠いかによって、色分けしなおしていく。

仕事を見つけた後の、応募とか、面接予約とかは、マッチングとは直接関係しない。(別のドメイン)
仕事情報や求職者情報で、給与/仕事内容/勤務地は、「マッチング」に強く関係する。

それ以外の情報は、判断の参考にすることがあっても、マッチングとは、ちょっと距離がある情報。
...

というような感じで、ドメインオブジェクトの色分け、パッケージの追加や、オブジェクトの移動をしていけば、 パッケージ図に「マッチング」<<core>> が登場し、重要なドメインオブジェクトが集まってくる。

これが、 Segregated Core (Core を分別する)パターン、というわけだ。

モデル駆動が大切


Segregated Domain パターンは、最後は、コードで、パッケージ、クラスとして表現する。
だからといって、設計を、エディタでやってはいけない。

Segregated Domain の最終表現は、コードであり、多くの時間は、リファクタリング(コードの変更)に使う。

でも、Segregated Core パターンは、「関係者で Core Domain」を共有することが一番の目的。

最終形はコードでも、みんなのイメージあわせのためには、主要なドメインオブジェクトを並べた、全体のドメインクラス図を元に、マーカーで色分けしたりしながら、みんなの意識を統一していくことが重要。

コードを変更してから、クラス図を作るのではなく、クラス図で設計してから、コードに反映する。
これが大切。

コード駆動ではなく、モデル駆動でやる。

何が、Core Domain であり、何が、中核オブジェクト、中核パッケージであるかが共有できれば、周辺のパッケージや、クラスの設計にも、明確な方針が生まれる。

◎ Core Domain との位置づけ、距離関係は?
◎ Core Domain に対する役割は?

これも、コード上よりは、まず、クラス図で、配置して、関連線を引きながら、整理し、確認する。

特に、パッケージ間の依存関係の確認は、重要。

コード駆動でリファクタリングしていると、どんどんスパゲティコードになっていく。
最近の IDE は、よくできていて、クラスの頭文字を入れれば、候補リストがでてくるので、思いつきで、いくらでも、他のクラスを参照するコードがかけちゃう。

気が付けば、どのクラスがどのクラスに依存しているのか、誰もわからない、見通しが悪く、手のつけれないコードがなっちゃう。

モデル駆動設計とコード駆動設計の一番の違いは、たぶんの、この「依存性」のコントロールの差。

絵にすれば、関連線の入り組んだ、スパゲッティコードが誰の目にも明らかになる。
で、まっとうなエンジニアなら、もっとすっきりした絵(設計)にしたいと思う。

ところが、同じエンジニアがコードだけで格闘すると、IDE のクラス名補完機能を駆使して、あっというまに、スパゲティコードの量産をしちゃう。

Segregated Core パターンは、Core Domain の共有、だけでなく、モデル駆動設計を、ごく自然に、開発チームで共有する良いやり方でもある。

Segregated Core パターンの費用対効果


測定したわけではないけど、Core Domain を共通理解にして、それが、実際のコードになっている効果は大きい。

まず、依存関係が Core Domain を軸に整理され、あきらかに、スパゲッティの度合いが減った。
また、個々のパッケージの Core Domain に対する、役割が明確になったことで、サポート役や周辺のパッケージの作りこみすぎが減った。

結果として、変更が容易になった。
変更すべき箇所が見つけやすいし、変更した場合の影響範囲も、判断が楽になった。

途中の仕様変更があっても、現場は、それほど混乱しなくなった。
昔は、仕様変更があると、それを、取り違えて変更し、さらに仕事を増やす、という悪循環が結構あったけど、これは、目に見えて減ってきた。

Core Domain を軸に整理し、設計の判断材料も、人や時間の割当判断も、Core Domain 中心にできるようになってくると、無駄な手戻りや、オーバーエンジニアリングをずいぶん、防止できたと思う。

Segregated Core パターンを意識しはじめた頃は、めちゃくちゃ、時間がかかり、はっきり言って、費用対効果が悪すぎた。

でも、これ、実は、「しなやなかな設計 ( Supple Design ) 」のレベルが低かったために、発生していたコストだった。

Value Object をつくり、ドメインオブジェクトの粒度を、業務の言葉の粒度とあわせ、意図の明確なクラス名やメソッド名を意識するようになってからは、Core Domain とそれ以外の色分けに、必要な時間は、たいしたことはなくなってきた。

Core と Generic を色分けするのに、しょっちゅう、クラスの分割までやっていたのでは、時間がいくらあっても足りない。

Supple Design のパターンを地道に実践して、ドメイン層のクラスの名前や粒度が、業務の概念に近づいていれば、 Segregated Core パターンの実践は、かなり楽になる。

RDRA 流のコンテキストモデルという全体地図(と羅針盤)があれば、航海も順調に進む。

道半ば


RDRA(リレーションシップ駆動要件分析)を参考にコンテキストモデルからスタートし、ICONIX 流に、常に、ドメインモデルを中心に考えるようになってはきた。

そして、Domain-Driven Design(DDD)の Core Dimain パターンを意識することも増えた。

でも、気が付くと、個々の開発作業は、いつのまにか、局所最適化とか、作りこみすぎがしのびこんでいる。

本人が分かってはいる。
レビューなんかでは、ドメイン駆動設計、Core Domain 中心で話しができるのに、コードを書き始めると、いつのまにか、自分がいじっているコードに、余計な時間とエネルギーを使いがち。

きちんと考えて設計して、コードを書く量を減らすより、とりあえず、コードを書いて、ごちゃごちゃなりながら、動かすほうが、(私自身も含めて)性に合っている人が多い。

今は、「図を描いて考える、話しをする」運動を、地道に続けている。

図で設計し、コードで実現する、というスタイル、リズムを、チーム全体が体で覚えちゃうまで、「図で描いて考え、話しをする」運動を意識的に続けようと思う。

手ごたえはある。続ければ、どこかでブレークスルーが起きそうな予感もある。
それが、いつ、どのように訪れるかは、予断できませんが。

calendar
 123456
78910111213
14151617181920
21222324252627
28293031   
<< March 2010 >>
システム設計日記を検索
プロフィール
リンク
システム開発日記(実装編)
有限会社 システム設計
twitter @masuda220
selected entries
recent comment
recent trackback
categories
archives
others
mobile
qrcode
powered
無料ブログ作成サービス JUGEM