アーキテクトは「パターン言語」を使う

ソフトウェアの設計で「パターン」をうまく使えば、よい仕事ができる(はず)。

Fowler アナリシスパターン
Fowler PoEAA
Evans Domain-Driven Design
Hruby ビジネスパターン
ニコラ Streamlined Object Modeling
Hay Data Model Patterns
GoF デザインパターン
...

数え上げれば、きりがない。

個々の「パターン」を、勉強したり、実際に使ってみたり、というは、多くの技術者がやっていることだと思う。

でも、それで、設計スキルが向上したかは、かなり疑問。

なぜ、実証済みの「パターン」を使っても、良い設計にならない?
理解力不足? 使い方がまちがっている?

答えは、原点の C. Alexamder の 「パターン言語」にある。

Alexamder は、

◎ いろいろなパターンを組み合わせて「言語」として使う
◎ パターンの組み合わせ方は、多重のネットワーク構造 (つまりとっても複雑なからみ合い)
◎ パターンを使い続けることで、全体として良い設計に育っていく

ということを説いている。

パターンを組み合わせて「言語」として使う


「パターン」を、設計を表現する「言語体系」の「単語」にあたるもの。

だから、ひとつひとつのパターン(単語)を覚えて、断片的に使っても、設計にはならない。

多様なパターン(単語)をうまく並べて、文として表現してはじめて、設計の表現手段になる。

だから、 Observer パターンとは、とか、Value Object パターンとは、とか、個別に議論しているうちは、設計の議論をしていることにならないということ。

パターンの組み合わせは多重のネットワーク構造


パターンとパターンの関係は、単純なツリー構造ではない。

パターンをひとつのクラスとしてクラス図を描くと、とっても、複雑にからみあった全体像になる。

継承で整理したり、パッケージ分割して整理して、階層構造や依存関係を明確にして、全体がすっきり整理したい、というのが技術者として自然な発想かもしれない。

でも、自然言語で、こういう単語の関連の整理や、文法規則の明文化が、とっても難しいように、「パターン言語」で、パターン間の関係(単語間の関係)を、すっきり、単純化することは、できない。

むしろ、単純化できないから、豊かな表現力を持っている。それが「言語」の強みというわけだ。

パターンを使いつづけることで、全体として良い設計に育っていく


これは、Alexander が、特に「街づくり」のパターンで言及している。

ひとつのパターンを一回使えば、良い都市設計ができるわけではない。

「街づくり」に関する、さまざまなパターンを、機会があるたびに、地道に使うことを繰り返していくと、街全体が、ここち良い環境に育っていく、という発想。

りファクタリングしながら、ソフトウェアを育てていくことに通じる発想。

ソフトウェアの世界では、語彙も語法も未整備


「パターン」ものは、たくさんでているけど、それでも、まだ、ソフトウェア設計を表現するには、語彙が足りないような気がする。

少なくとも、GoF のデザインパターンだけで語れる範囲なんて、ほんと限定的。

アーキテクチャレベルのパターンから、コードの書き方スタイルのレベルまで、世の中にでているものをかき集めれば、それなりにカバーはできているのかもしれない。

でも、そういうボキャブラリ(パターン)を一通り覚えて使える技術者は、それほどは、多くない。ハードルが高い。

そして、Alexamder のパターン言語、建築の世界でもそうだと思うが、パターンとう単語を「組み合わせて使う」、語法にあたるものが、とても原始的な状態にある。

人間が言語を使い始めた時は、たぶん、単語を個別に叫ぶだけで、語順もなにもなかったはず。

それが、少しずつ、主語と述語と目的語みたいな感じで、使うことが、共通の約束ごとになってきた、ようやく、言語として、豊かな表現力を持つようになってきたんだと思う。

「パターン(単語)」の元ネタは、それなりに揃ってきているかもしれない。

これからは、その単語の組み合わせた使い方、つまり「パターン言語」を、どうやって整備していくかが課題なんだと思う。

たぶん、単語を、断片的に叫ぶことから始めるのが、自然なんだろうな。
そうやって、単語をお互いに言い合いながら、だんだん、語法が表れてくる、ということなんだろう。

まずは、断片的な単語(パターン)を、単独で使うことから、パターンどうしを関係づけて、設計を表現することから、はじめてみようと思う。

Domain-Driven Design を読み終えて

去年の11月くらいに DDD を読み直しながら、自分の頭を整理するために、ブログで、DDD ネタをいろいろ書いてきた。

500ページ、17章を、ようやく読み終わった。お疲れさまでした、という感じだな。

何度も読み返してきたけど、ちゃんと通読したのは、今回がはじめて。
今までの読み方が甘かったのが、とてもよくわかった。

まあ、新鮮な発見がいっぱいあって、何か、新しい本を読んだような気分でもある。

自分たちが実践していること、できていること、できていないことも含めて振りかえってみて、改めて、Domain-Driven Design について、思ったことを、書き留めておきたい。

モデル駆動設計


DDD 前と後で、自分にとって、一番の発想の転換は「モデル駆動設計 ( Model-Driven Design )」に目覚めたことだった。

この本に出会うまでは、自分は、徹底的にコード命。エディタだけが、唯一の設計・実装ツール、という感覚だった。
UML とか、デザインツールとか、手はだしてはいたが、ただのお試し。
実際の、開発の仕事では、一切使わず、暇なときに、絵を描いて遊んでいた、という感じ。

DDD を最初に読んでからも、数年は、DDD が、なぜいきなり「モデル駆動設計」が重要なパターンとして登場するのか、ぴんときていなかった。

発想の転換のきっかけは、Domain-Driven Design ではなかった。

ユースケース駆動開発実践ガイド で解説されていた ICONIX プロセスを、現場で、やりはじめてから。

ロバストネス図を、若手に描かせてみて、自分と発想がまるで違うことを発見したとき。
そして、オレだったら、こんな感じにするよ、というポイントを、ちょっと手書きしたら、相手が「なるほど」と一発で、こちらの設計を理解した。

3年くらい前のできごとだったけど、今でも、その小さな会議室で起きたことが、まざまざとよみがえるくらい、強烈な印象だった。

それまで、ずーと「コイツは、なんでこういうコード書きたがるかなあ」と理解できなかったこと。
ここは、こういう書き方でしょう、といっても、相手に全然伝わらず、若手に設計スキルを伝える方法がわからず苦しんでいた。

それが、一枚の絵で、あっというまに解決した。なるほど、そう考えていたか、がこっちもぱっとわかったし、相手も、ぱっとわかってくれた。

一枚の絵が、設計意図の伝達に、手軽で便利な手段という、この事件(?)の印象は、ほんとうに強烈だった。

ICONIX プロセスは、ドメインモデリング(概念クラス図)を中心にした方法論だったこともあって、DDD の実践方法として ICONIX を現場で実践する、ということに、急激にのめりこんでいった。

ICONIX は、最小限の絵だけは、ちゃんと描こう、という軽量なやり方なのも、良い感じだった。

コードを書く前に、手書きでいいから、絵にして、話しをしてみよう、というのが、「モデル駆動設計」ということなんだと思った。

今でも、メンバーのマインドは、「コード中心」から完全に抜け出せたとはいえないかもしれない。

でも、「絵を描くことで設計意図が伝わる、ありがたさ」を体験しながら、そういうやり方が、だんだん、自分たちのやり方になってきた手ごたえがある。

最近になって、それなりの技術者たちと仕事をして、ロバストネス図の作成とレビューをちょっと、やってみただけで、相手の設計の考え方がすぎ理解できたし、こちらの設計意図も、簡単に伝わった。

こういうのが当たり前になってきちゃうと、DDD 前の、コードとエディタにどっぷりとつかっていた自分がいたのが、信じられないくらい。

この感じは、実際にやってみると、すぐ、伝わるんだけど、本を読んでいるだけでは、(私もそうだったけど)ぴんとこないんですよね。

ユビキタス言語


やっぱり、DDD の基本中の基本はこれでしょうね。

チーム内での会話、コンテキスト図やロバストネス図、パッケージ・クラス・メソッド・変数の名前、スキーマ・テーブル・カラムの名前、...

開発の現場の、ありとあらゆる場面に、ドメインの用語・概念が、頻繁に登場すること。できれば、それ一色になること。

それが、ドメイン駆動設計を実践する、ということなんだと思う。

これは、私自身は、Domain-Driven Design に出会う前から実践していたし、こだわっていた。

まあ、DDD に出会ってから、さらに過激になったとは思うけど、良いソフトウェアは、わかりやすい名前から、というのは永遠の真実だと思う。

そして、わかりやすい名前というのは、アプリケーションのドメインで使われる言葉なんです。

ここらへんは、20数年前に、C 言語で格闘していた時に、師匠にうるさくいわれたこと、15年くらい前の,
Oracle 時代に、設計ハンドブックで、業務用語を積極的にテーブル名、カラム名に使う設計・実装の流儀にであったこと、などの影響が大きい。

技術者だけが理解できる命名は、基本的に、よくない、わかりにくい名前。
業務の関係者が理解できる用語を使ったソースコードが良い設計。

ドメイン駆動設計の根底にあるもの


モデル駆動設計とユビキタス言語は、テクニックや方法論として、チームに浸透させることができる。
実際に、現場で取り組んできて、やってみれば、開発メンバーが、その良さを具体的に実感できることは実証できた。

自分たちは、ドメインロジックは、ドメインモデルパターンを重視するし、実装のフレームワークは、Spring 中心にやっている。

でも、モデル駆動設計やユビキタス言語は、トランザクションスクリプトやテーブルモジュールパターンでも効果的なはず。もちろん、実装フレームワークや開発言語に何を選ぶかとは、関係なく、有効。

モデル駆動設計と、ユビキタス言語が、DDD の基本テクニック。

そして、その根底にあるのは、「ドメインの知識への興味」「ドメインの構造やルールを、発見する面白さ」なんだと思う。

そういう興味や面白さが動機になって開発したソフトウェアは、利用者の役にたつ、喜ばれるソフトウェアになる。

また、ドメインの構造をうまく表現したソフトウェアは、要求の追加も、簡単に、安全にできるようになる。
要求は、ドメインから生まれる。だから、ドメインの構造をうまく表現しておけば、追加の要求も、すんなり、そこに収まる、ということ。

こういう、知的好奇心というか、「わかる面白さ」を、チームのメンバーで共有しながら、仕事をするのは、楽しいものです。

その興味の対象が、技術テーマか、ドメインの課題か、というちょっとした(?)問題はありますが....

良いアーキテクトとは? (ドメイン駆動設計的アーキテクト論)

Domain-Driven Design(DDD)の17章に、ドメイン駆動設計的な、アーキテクトと、アーキテクチャ策定の要点(エッセンス)が6つ載っている。

だめなアーキテクト(個人/チーム)


ドメイン駆動設計に限らないと思うけど、まずは、だめなアーキテクトの特徴

× 最初に、がちがちにアーキテクチャを決め、プロジェクト全体の技術を制約
× アプリケーション開発をやっているチームに説明もしないし、声も聞かない
× ネットや本から拾ってきた、実証されていない、アーキテクチャを使いたがる

現場のことを何も考えず(知らず?)、自分の技術興味だけで調査し、サンドボックスで動けば、すべてOK、現場で問題が起きてもわれ関せず、...

こんな、アーキテクトやアーキテクチャチームが幅を利かすプロジェクトでは、良い仕事はできませんねえ。

こんなアーキテクトチームが良い


エバンスは、2つの成功パターンをあげている。

現場の技術リーダーが集まった非公式のアーキテクチャチーム


現場で、アプリケーションそのものを開発しているチームの中の、技術リーダーたちが、非公式に集まって、アーキテクチャの決め事や、改善を継続する。

公式には、概要的な決め事だけがあって、あとは、現場の技術リーダーたちが責任をもって、アーキテクチャを具体的に決め、プロジェクトを進めながら、アーキテクチャを改善し、発展させていく。

プロジェクト全体の目的や背景が、関係者で具体的に共有できていて、技術リーダーたちが、ビジネスの視点、プロジェクト管理の視点、システムのライフサイクルの視点などで、まともな議論ができる程度のマインド、経験、知識があることが、成功条件。

理想的なスーパー技術者、ということではなく、業務アプリケーションの開発プロジェクトで、まじめにリーダーがやっている人たちであれば、ほとんど、有資格者だと思う。

そういうメンバーが集まって、いろいろ話しをして、みんなが納得するものが、ベストのアーキテクチャ、だということ。

プロジェクト全体を仕切る、公式の技術チームがいない場合、自然発生的に、こういう非公式なアーキテクチャ策定チームがうまれることもある。

逆に、公式の技術チームがある場合は、この「現場技術リーダたちの非公式チーム」パターンは、いろいろ難しいだろうなあ。

公式のアーキテクチャチームが現場主義で取り組む


公式のアーキテクチャチームがうまくいくのは、

◎ アプリケーションの開発の現場に精通している
◎ プロジェクトの目的や背景。Context Map から、アーキテクチャを検討していく。
◎ 利害関係者(ビジネスパーソン、技術者、運用担当、...)と継続的にコミュニケーション
◎ 現場の声を元に、アーキテクチャを改善しつづける

という行動ができるチーム。

どんなアーキテクチャが望ましいかを、さまざまな利害関係者とのコミュニケーションを通して、模索しつづけるチーム、という感じかな。

アンチパターンのチームの裏返し。

現場主義のアーキテクト( Hands-on Architect ) が、良いアーキテクト。

アーキテクチャ策定の6つの要点


エバンスがあげている、6つの要点。

決定事項は、チーム全体に周知されること


アーキテクチャとか、大きな設計は、考え方であり、実体がない、といえば、ない存在。

アーキテクチャが実体を持つのは、現場の開発者がその考え方を理解し、日々の実装の中に、その考え方を、具体的に記述していくこと。

「周知する」と「強制する」は同じではない。

「強制」は、おそらく、相手が理解したり、納得することを軽視して、「ルール化」と「ルール違反チェック」という行動になる。

「周知する」というのは、相手が理解できるように努力し、納得して、実践してもらうことにこだわる行動になる。

「周知」するためには、相手が現場で困っていることを、いっしょに手を動かしながら、話しをするのがいちばん伝わりやすいと思う。

それを、時間のムダとか、非効率と思うなら、たぶん、ろくでもないアーキテクトの仲間入り。

決定の過程で現場の声を受けとめる


アーキテクチャは、アプリケーションの開発をしているチームが良い成果を出せるように支援するためにある。
自分の技術興味や、技術力の誇示のためにあるのではない。

主体は、常に、ドメインの概念を、ソフトウェアとして表現しようと奮闘しているチーム。
アーキテクチャチームは、そいういう現場でがんばっているアプリケーション開発チームの声にいつも耳をかたむけ、彼らの声を、アーキテクチャに反映し、アプリケーション開発者が喜んでくれることに、達成感を持つのが良いアーキテクト。

現場が喜ばないのは、選択した技術方式そのものに問題があるか、現場への周知の仕方に、大きな欠陥があるに違いない。

よいアーキテクチャは、アプリケーション開発チームに、喜ばれるもののはず。

エバンスは、「アプリケーション開発チーム」と「アーキテクチャチーム」で、技術者のローテーションを必ず行っていたチームを、うまいやり方の例としてあげている。

「計画」も発展させる


実装コードも、アーキテクチャも、マスタープランも、最初からベストの正解が、ぱっとできあがるものではない。

コードのレベルでは、リファクタリングとかのマインド、知識、経験を持った技術者やチームが増えている気はする。(楽観的すぎる?)

アーキテクチャやマスタープランになると、「最初に格闘して全体を決め、決めたら一切変更しない」という、「大きな前払い」かつ「思考停止」かつ「ソフトウェアと技術者の成長の抑圧」というのアンチパターンが、まだまだ多い気がする。

アーキテクチャや、マスタープランも、プロジェクトの中で、発展させていくのが、基本原則。

アーキテクチャチームに人材を集中させない


もっとも、技術力があるメンバー、マインド・知識・経験がしっかりしたメンバーは、アプリケーション開発チームに投入すべき。特に、コアドメインを担当しているチーム。

アーキテクチャチームは、ナンバー2に、まかせる。

他のメンバーも、アプリケーション開発チームに、まんべんなく、優秀な技術者を配置することをこころがける。

アーキテクチャチームは、技術の指導チームではなく、現場の優秀な技術リーダーたちの声を取りまとめ、実証し、絵やガイドやサンプルや部品として、その成果を現場に供給するためのチーム、という感じかな。

ドメイン駆動的には、アプリケーションのモデリング・設計・実装をするチームにこそ、第一人者を配置すべき。

アーキテクチャチームは、第一人者候補を育成する場にする。

minimalism と謙虚さ


アーキテクチャチームは、技術方式の決め事にあたって、「必要最小限」の決定をすること、他のチームの声に謙虚に耳を傾けることが必要。

これも、アンチパターンの裏返しですね。

「なんでもかんでも、決めたがって」「人の意見を聞かない」のが、最悪のアーキテクト(個人/チーム)ということです。

「オブジェクト」はスペシャリスト、「開発者」はジェネラリスト


大きな設計の最後の要点がこれ。

個人的には、これが一番気にっているし、心がけるべきだと思っている。

オブジェクト(ソフトウェアの部品)は、役割が単純明快な「スペシャリスト」であるべき。

いろいろな役割を兼任しているオブジェクトは、ろくでもない設計なんだ。

「開発者」は、正反対であるべき。

モデリング、設計、実装、データベース、メッセージング、インフラ、運用・監視、ビジネスパーソン、...

いろいろな顔(役割)を同時に持つべきだし、システム全体、プロジェクト全体で、どこでも、それなりの仕事ができる、ジェネラリストであるべき。

実際、「スペシャリスト」を自負する技術者は、アプリケーション開発の現場では、いつでも二流以下です。

得意分野をもつべきだし、磨くべき。

そして、その結果、一芸に秀でる主は、多芸に通じるに決まっている。

多芸ができない技術者は、一芸に秀でているわけがない。(つまり二流以下)

通信プロトコルが分かっているから、そのドメインのビジネスプロトコルの理解も早い、というのが、一流の技術者なんだと思う。

一流になれるかどうかは、能力というより、こころがけしだい。

Responsibility Layers と関連するモデリング手法

企業全体の情報システム、あるいは、他企業との連係を含めた、企業の活動全体のモデリングには、昔から、いろいろな方法が提案されていますよね。

たとえば、組織・部門の機能や役割体系を整理の軸にすえた方法論。(業務アプリでは、伝統的なモデリング手法かな)
あるいは、マイケルポーターの Value Chain モデルとかも有名。

これは、Responsibility Layers と似ていたり、重なる部分がある。

組織・部門の役割体系


部門ごとの役割、つまり「責任 Responsibility」に注目しているのは、基本は、DDD の Responsibility Layers といっしょ。

大きな違いは、「実際にある部門」で考えるか「Responsibility のタイプ」という概念で考えるかの違い。
昔は、企業の組織・部門は、長期的に安定した entity (実在)、というのが大手企業が素朴にもっていた感覚。
役所や大手銀行、大手企業は、いまでも、基本の感覚はそうかもしれない。

コンピュータ導入は、最初は、そういう大きな組織中心だったこともあって、部門・組織に注目するモデリング、というのが、ある意味、主流だった。

世の中は、流れ、企業や組織の流動性は高まっている。今の組織体系が、来年も固定的に存在するかは、かなり怪しい。

組織・部門に、注目するより、「 Responsibility 」に注目してモデリングしたほうが、組織変更があっても、対応しやすいシステムをモデリング・設計できる。

Responsibility Layers の視点のほうが、現代的だし、将来有望でしょうね。

Value Chain


競争優位論で有名なマイケルポーターの企業活動のモデル。

主活動は、仕入れ物流・加工・出荷物流・販売/マーケティング・サービス という価値生産の連鎖が、モデルの中核。

Responsibility Layers の Operations 層は、まさに、この主活動を記録し表現するためのレイヤ。

Value Chain の主活動の要素は、Responsibility Layers の Operations 層の Bounded Context と対応する可能性が高い。

もちろん、Bounded Context 間の関係は、まさに、Value Chain の「連鎖」の関係になる。

Value Chain モデルの支援活動のための情報システムは、一枚の Responsibility Layers に無理矢理押し込めると、話しが入り組んできて、わかがわからなくなる。

・Value Chain モデルの主活動に注目した Responsibility Layers と Context Map
・Value Chain モデルの支援活動に注目した Responsibility Layers と Context Map
・両者の主要な接点を絵にした、大きな視点の Context Map

という感じで、全体のモデリングをするのが良いと思う。

Value Chain モデルは、必ずしも、一企業のモデルではない点が重要。複数企業のコラボレーション、企業をまたがるシステム間連係のモデルとして使うことができる。

あと、Core Domain パターンの議論には、ポーターの競争優位、差別化戦略論は、とっても役にたつ。

競争優位の源泉は、どこにあるか、どこにもとめるか、というのは、 Value Chain モデルと使った、事業戦略論と、Core Domain パターンのモデリングと直接、結びついていると思う。

ドメイン駆動設計やるためのチェックリスト

Domain-Driven Design(DDD)17章に、ドメイン駆動設計を、やるための、6つのチェック項目が載っている。

□ Context Map を描いてみる: Q. ちゃんと描ける?
□ プロジェクトチームの「言語」: Q. コードもドメインの用語が中心?
□ 重要事項の理解度: Q. Core Domain を発見した? Domain Vision Statement ある?
□ プロジェクトの技術基盤: Q. 「モデル駆動設計(MDD)」向き? or MDD の障害 ?
□ メンバーのスキル: Q. 「必要」なスキルセットを持っている?
□ 知的興味: Q. メンバーは、ドメインを知ることに興味を持っている?

このチェックリストで、自分たちの5年前(出発点)、現在、今後の見通し(?)を、書いてみる。

Context Map をちゃんと描ける?



■5年前
言葉すら知らなかった。膨大な数の関心事を「ひとつ」のシステムとして格闘していた。

■現在
ホワイトボードで、時々、関連システムとのマッピングとかはやっている。

RDRA(リレーションシップ駆動要件分析) のコンテキストモデリングをやるようになってから、全体ではないけど、関連するシステム間のマップは、プロジェクトの最初から意識するようになってきた。

60点かな。それなりのレベルまでこれた気がする。

■今後
Responsibility Layers と Context Map を組み合わせた図を、リポジトリーにチェックインして、リファクタリングしながら、成長させていく、対象にしようと思う。

プロジェクトチームの言語



■5年前
コードの中身は、ドメインの用語とは、完全に別の世界。

・意味の分からない省略形
・プログラミングの世界だけの特殊な命名 ( i, val, s, ... )
・一度つけた名前は、別の概念であることが発覚しても、そのまま
...

■現在
ドメイン層は、ドメインの用語で命名する。
概念の違いを発見したら、即、名前変更のリファクタリング。

80点かな。
これは、かなり良いレベルだと思う。
5年間、ソースコード、会議、日報など、うるさく「業務の言葉」を言い続けた成果が実感できる、今日、このごろ。

■今後
インフラ層も、ドメイン駆動設計で、ユビキタス言語を浸透させる。

基盤技術の選択、サーバーの設定とかも、目的・背景を、「ドメインの言葉」で説明し、設計するように変えていきたい。

手始めに、Apache → HTTP サーバー、cisco → ルーター というように、まず、実装と概念を区別して、使い分けよう運動を開始中。

httpd.conf の timeout ディレクティブを 300 に設定、という会話ではなく、「ブラウザからのリクエストに5分間応答できなかった場合、ブラウザがエラー表示するようにする」、というように、技術者以外の関係者にも、理解できる言葉を使うように、ということ。

地道な活動だけど、見返りも大きい。この「利用者の言葉で駆動する」運動の効果は、5年間の経験から確信を持っている。

重要事項の理解度



■5年前
0点。
すべての要求を、まったく同列に、戦線を拡大し、全員、討ち死に状態。

■現在
コアドメインという「言葉」はでてくるようになった。
でも、気がつくと、目先の要求中心で、設計・実装している。

40点。落第点ですね。

これも RDRA(リレーションシップ駆動要件分析) の、システム価値のモデリングを、コンテキスト図や、要求モデル図を使うようになって、徐々に改善はしてきた。

概念クラス図でも、「コア」の概念クラスを中心に組み立てる、ということも、メンバーによってはできはじめている。

ユースケースの実装を、「コアドメイン」のユースケースから手をつけて実装していく、ということを、自分たちで判断できるレベルまではきていない。

■今後
概念クラス図/パッケージ図、ユースケースモデル/パッケージ図で、コアとそれ以外を色分けしたり、コアを中心に、コアとの関係で、配置を工夫する、とか、パッケージ図レベルでコアを検討することを、やらせてみようと思っている。

まあ、先は長そうです。
Core Domain パターンを普通に実践できるチームまで成長したいとは思っていますが...

Domain Vision Statement をさらっと書けるようになる、なんていうのは、妄想だな。
ただ、プロジェクトの初期に Domain Vision Statement を描き、それをリファクタリング(推敲)しながら成長させていく、というのはぜひ、実践していきたい。

やり方はとしては、プロジェクトの初期に作成する「コンテキスト図」に、システムの「目的」「背景」を簡潔に、ノートとして記入することを、ルールとしようと思う。

このノートを改良していけば、それが、Domain Vision Statement になっていく、という目論見です。

プロジェクトの技術基盤 vs. モデル駆動設計



■5年前
0点
Visual Studio で、お絵かきツール使って、Web アプリケーションを半ば、ちょこちょこっと作る。
人を集めて、このパターンで、量産すれば、大きなシステムが作れちゃう。

そんなわけない。完全に破綻プロジェクト。

XP, Agile , Ruby on Rails とか、モデル駆動設計というより、自動生成してでも、とにかく動くものを早くつくる、ということを重視するやり方がある。

XP でも、Agile でも、ちゃんとした技術者は、ここぞというところは手書きで使い捨てかもしれないけど、モデル駆動設計をしているはずだけど、中途半端な、XP/Agile 信者(?)は、絵を描くことが、Agile 精神に反するとか思っているらしい。

まあ、ドメイン駆動設計やるなら、「モデル駆動設計」は「ユビキタス言語」と並ぶ、二本の柱だと思う。

■途中経過 (デザインツール、導入)
数年前に、Enterprise Architect というツールを導入したが、その時点では、完全に失敗。
UML らしき図は描くけど、UML 図を描くことの意味や効果を誰も実感できず、あいかわらず、設計も、エディタで、コードでやる、というスタイルのままだった。

■転換点 ( Spring )
モデル駆動設計の大きな転換点になったのが、Spring フレームワークを、技術方式の中心に置いたこと。

なぜ、Spring フレームワークに注目したのか、正確には覚えていないけど、ジュニアの技術者たちに、データベースアクセスとか、Web MVC とかを低レベルで書かせると、生産性も品質も大問題だったことの改善策を模索していた中で出会った技術だった。

コードの自動生成とか、ブラックボックス化指向のツール/フレームワークは、カスタムアプリケーション開発には、向かないという判断があった。

Spring フレームワークのように Java2 EE ラッピング(?)して、簡単に使えるようにしてくれる技術はほんと、ありがたかった。

「EJBは存在自体がまちがいだった」と言い切っちゃう Rod Johnson の発言は、新鮮だったなあ。
Java のチェック例外批判も多いに共感した。

そして、「ドメイン層以外は、ベストプラクティスを、Spring が提供する」「開発者は、ドメイン層に専念すべき」という発言にも大いに共感。

てなわけで、Spring フレームワークで、 MVC, WebFlow, Security を順次、採用し、O-R マッピングに iBatis, テンプレートエンジンに、velocity, 最近になって、非同期メッセージングに Mule ESB という感じの技術基盤に投資をしてきた。

Spring も、Mule も、「ドメイン層のオブジェクト」をコンポーネントとして使うことを前提としたフレームワーク。

実際、Spring MVC + Web Flow から呼び出すアプリケーションサービスクラスを、Mule ESB で、メッセージ処理のコンポーネントとして、そのまま組み込んで使っている。

基盤技術は整った。あとは、「ドメイン層の実装」、そのためのドメインのモデリング、ドメインオブジェクトの設計をどうするかが課題。

■転換点 (ICONIX)
そして、ICONIX との出会い。きっかけは、単純に、Amazon とかで、Spring 関連の書籍とかを漁っていたときに見つけた本。

昔、Rational 統一プロセスとかでも、ちょっと見かけた、ロバストネス分析とかも、ちょっと、気になった。

そして「ユースケース駆動開発実践ガイド」に取り組み始めてから、世界が変わった。
ICONIX方法論は「必要最小限の図だけ描く」という、minimalism が徹底している。

また、「抽象モデル」「論理モデル」「物理モデル」とかを、教科書的に段階を踏むことも完全否定。
実践的なモデル駆動設計とは、何かを教えてくれた方法論です。

ICONIX の提唱者のダグローゼンバーグ本人が来日してセミナーやった時に、話す機会があったんだけど、まあ、とっても実践的な人。

彼らは、教育を商売にしていて、技術者が陥りがちな点とか、技術者の発想を変えるコツみたいなものを熟知していて、ほんと、得るところが大きかった。

この本が、技術方式は、Spring を使っていて、モデリングツールが、Enterprise Architect を使っていたので、私たちの既存技術とぴったりだったのも大きい。

ICONIX は、最初から、ドメインモデルを作って、成長させていくことが、中心のプロセス。

概念クラス図が、そのまま、ドメインオブジェクトに発展して、実装できちゃうよ、というやり方。
モデル駆動設計、ドメインモデルの設計・実装には、ほんとぴったりの方法論だった。

方法論といっても、よく言えば、超・実践的、悪く言えば、ちょっといいかげん。

■転換点( RDRA )
ICONIX はすごかったけど、カバーしているのは、ユースケース記述以降の設計・実装だけ。

プロジェクトの初期に、どうやって、あいまいで不安定な要件を固めていくかに悩んでいたときに、出会ったのが、神崎さんの RDRA ( リレーションシップ駆動要件分析 )

これも、UML 風の図を使う、上流工程のモデリング技法。
とても、実践的で、上流工程、要件定義の現場で実際に起きること、担当者の悩みを熟知した、これまた、超・実践的、現場主義の方法論。

システム価値、システム環境、システム境界、システムそのもの、という4段階で、システムの要件を定義していくアプローチに、とても共感した。

特に、システム価値(コンテキストモデル、要求モデル)から、システム環境(業務モデル、概念モデル)を関係者で、明らかにしながら、システム境界(画面・帳票、システム間連係インタフェース)を定義していく、というやり方が、具体的・実践的で、私たちの現場に課題にぴったりだった。

最初、本を読んでいるときは、ちょっと、重い方法論に感じて、若干、引き気味だったんだけど、神崎さんのセミナーに行ってみて、いろいろお話しを聞いたら、評価がいっぺん。

めちゃくちゃ実践的で、現場主義。
これだ、と確信し、さっそく、現場に導入開始。
上流から、設計・実装まで、「ドメイン駆動」「モデル駆動」「ユビキタス言語」で、やる、一連の流れが、見えてきた。


■現在
ICONIX は、特に、ドメインモデリングとロバストネス分析が、現場に浸透して、効果をあげている。
ロバストネス図が、そのまま、Spring Web Flow や、Mule ESB の実装設計になっちゃうところがすごい。

現場の技術者も、ロバストネス図を描いてみんなで設計を確認してから、コードを書き始めたほうが、手戻りが減って、仕事が楽になることを、何度も経験したので、今は、自然にロバストネス図を描くようになっている。

しかも、Spring/Mule ESB は、この設計を、そのまま XML 定義ファイルとか、アノテーションで宣言すれば、実装できちゃうという、「モデル」「設計」「コード」の距離の近さが、とっても、仕事を楽にしている。

モデル駆動設計用の技術基盤を使っている、という意味では、100点に近いと思っている。

もっとも、RDRA での実践度合いは、まだ30点くらい。
やれせれば、効果があることは、はっきりしているけど、自分たちだけで、うまくできない。
あと、ほったらかしにすると、RDRA レベルの作業をしないこともあるので、ここはまだまだ。

■今後
テストの自動化、テストデータの設計・実装、インフラ構築、運用、...

ここらへんが、ぜんぜん、モデル駆動設計になっていない。
最近、テストの自動化を、コンポーネント図を使って設計したり、インフラ構築やサーバーのネットワーク設定を、配置図を使って設計してから、実装するというやり方に挑戦中。

モデルを描きながら設計するのは、自分のためというより、関係者での理解を早く・簡単にできるというのが一番の効果。

これは、RDRA/ICONIX を実践しながら、ほんと、痛切に感じている。

絵を使ったコミュニケーションは、ほんとうに、開発プロジェクト全体の仕事を楽にしてくる、ある意味、魔法の道具です。

ソフトウェア開発に銀の弾丸はない、ということはよく言われる。
もちろん、私もそう思う。

でも、モデル駆動設計、絵を描きながら、設計する習慣は、「銀の弾丸」とは言わないが、スーパーバズーカ砲くらいの破壊力はある、強力な武器だと思っている。

メンバーのスキル



■5年前
10数名で、半分が、新人、半分はあちこちから引っこ抜いた混戦チームで、悪しき(?)習慣にどっぷりつかった、曲者ぞろい、てな感じ。

ドメイン駆動設計で、モデル駆動、ユビキタス言語なんて、どこにもない世界。0点からの出発。

■現在
モデリング・設計・実装のバランスがよいスキルは身についてきたように思う。

60点はあげたい。(ぎりぎり合格)

ドメイン駆動設計とか、ビジネスパターンの理解と応用、RDRA/ICONIX の実践スキルとかは、それなりになってきた感じ。

■今後
技術基盤の選定や調整、インフラの構築とかのスキルがまだ弱い。
ここは、外部の技術支援を受けながら、社内の技術メンバーは、ドメイン層の設計・実装に注力できるようにしたいと思っている。

当面は、Mule ESB をドメイン駆動設計的に活用する技術の導入、活用ノウハウの蓄積が目標。

動くソフトウェアを作る技術は、いつでも重要な技術。
昔に比べ、データ構造とアルゴリズムみたいな技術は、フレームワークやツールを活用することで、必要なスキルセットとしては、重要度は低下してきた。
(もちろん、論理思考能力とかは重要)

IT技術も、全体的に、手続き型から、宣言型に変わってきている感じなので、プログラミング=アルゴリズムとか、システムコールAPIというスキルセットではなくなってきていると思う。

知的興味


これがいちばんの難関?

■5年前
寄せ集めた腕自慢たちの知的興味は、当然(?)、技術的なことばかり。
仕事だから、顧客と仕様の話しはするけど、興味は、「どうやって実装するか」ということだけ。

新人君たちは、そもそも、技術への興味も弱く、ドメインなんて、まったく別の世界。あんたら、何が楽しくて、ここにいるの?という感じ。
新人が、何も知らない、配属命令があって、とんでもないプロジェクトに放り込まれ、それが、社会だと思ってくれる、素直な子達だった。

まあ、0点かな。

■現在
ちょっぴり、ドメイン、会社の事業や業務に知的好奇心が芽生えた感じ。
でも、期待値から考えると、30点くらいかなあ。
まだまだ興味も弱いし、理解する力もそれほど強くない。

でも、こういうメンバーで、ドメイン駆動設計ぽいことができはじめていることには、なんか、達成感も感じることがある。

メンバーにまかせる部分が増えてきて、それなりに、ドメイン駆動設計やっている感じはある。

でも、「興味」とか「エネルギー」の出方がいまいちなんだよなあ。

■今後
ドメインへの興味なんて、強制して生まれるものじゃない。

技術者の目線や知的好奇心、達成感を刺激できる「ドメインの理解と実装は面白い」と実感できるネタや機会をいろいろ考えたいと思っている。

私自身は、実装技術で、わかった、動いた、という面白さと、ドメインの仕組みをソフトウェアする面白さが一体になっていたところがある。

人のその面白さを伝えられるかどうかは、あまり自信がない。

でも、そうか、こういう業務ニーズは、こうやって実装すれば、すごくすっきりする、という、感覚、そして、それが面白いという感覚は、多くの技術者と共有できると思っている。

動けば楽しいし、人に注目され、喜んでもらえれば、うれしいに決まっている。

「ドメイン駆動設計」というのは、「人に喜んでもらえる」ソフトを作るテクニックやノウハウだと思っている。

そこに、自然に目覚める、ということは少ないんだろうけど。

DDD 第 IV部「おおきな設計」のまとめ

17章は、第 IV 部 Strategic Design の総集編。

複数のシステム、複数の開発チームが登場する開発シーンでの設計の要点みたいな話し。

数十人規模の会社でも、結構、いろいろなシステムが動いていて、それを、複数のチームが担当する、というのは、よくある話し。

チームは一つでも、数年の視野で見れば、異なるチームが担当しているのと、基本的にはいっしょ。

こういう状況では、

・サブシステム分割
・アプリケーションのパーティショニング
・システム間連携

というような課題をいつも抱えている。

Domain-Driven Design(DDD)の第IV部 Strategic Design は、こういう課題に取り組むパターンをいろいろ解説している。

17章 Bringing the Strategy Together では、第 IV 部の3つの章(14章から16章)を、総括して、エッセンスをまとめている。

第IV部では、20余りのパターンを取り上げているけど、

・Context Map パターン
・Core Domain パターン
・Responsibility Layers パターン

の三つを特に、基本的なパターンとして位置づけ、この三つを組み合わせることを、全体の構造を明確にしていく、基本テクニックとして紹介している。

Context Map を、Responsibility Layers 上で描く


企業のさまざまな情報システムは、それぞれ、異なる目的と背景があり、利害関係者も異なる。

Context Map (14章)


それぞれのシステムを、ひとつひとつの独立した文脈(コンテキスト)として、明確に定義してみようというのが、Context Map パターン。

「Map」なので、それぞれの文脈(Bounded Context) 間の、現在の関係も、絵にしてみる。

Context Map は、あるべき姿ではなく、「現在の実情」を書き出して、関係者で共有するためのパターン。

Responsibility Layers (16章)


それぞれの Bounded Context を、Responsibility Layers パターンの絵の上で位置づけて、Context Map を描いてみる、というのが、大きな設計の基本テクニック。

これ、企業システムとか考えるときは、みんな多かれ少なかれやっていることですね。

一番わかりやすのが、Decision Support レイヤ。

Operations レイヤで発生し、記録されたデータを、収集・分析して、レポートを作ったり、リコメンデーションのリストを作るようなアプリケーション。
「情報系」とか呼ぶこともあるかな。

Operations レイヤとか、Commitments レイヤは、日々の業務(トランザクション)を、サポートするためのシステム。「勘定系」。

ビジネスイベントが発生して、それを記録し、残高や状態を更新し、必要なところに、通知する。
約束した業務、予定した業務を、きちんと履行しているか、追跡する。必要ならアラートを発行する。
Potential レイヤは、マスター管理。 Policy レイヤは、ビジネスルールの記述と実行、という感じ。
こういう5つの Responsibility Layers は、絵にすると、水平にスライスする階層構造。

Context Map と Responsibility Layers を組み合わせる


Context Map で描く、個々の既存システム(既存のBounded Context)は、一つのレイヤの一部だけを担当していることもある。横の幅は狭いが、最下層の Potential 層から、最上層の Decision Support 層まで、ひととおりカバーしるシステムもある。

もちろん、重複もあるし、空白地帯もたくさんある。

Context Map だけで考えるときは、とりあえず、既存のシステム単位を洗い出して、平面にマッピングするだけ。

これと、Responsibility Layers の階層構造を組み合わせると、全体像が、立体的に見えてくる、というわけだ。

この「立体感」は、実際に、描いてみると、全体のわかりやすさが実感できる。

描くのはたいへん


ただし、描くのは、かなりたいへん。
既存のシステム全てをカバーする、それなりの知見を持っているメンバーが集まってやる作業。

ただ、開発当時の担当者が誰もいないシステムとか、ソースすらまともに残っていないないシステムとかあるのが現実。

実際にやってみると、分かっている箇所は、細部まで描きすぎ。わかっていないところは、あやふや、ひどいときには、システムごと見落とし、なんていうことがあった。

この「見落とし」は、Context Map だけで描いたときにおきて、Responsibility Layers 上に、Context Map を描きなおしたことで、「空白地帯」を発見し、そこに「システムがあるはず」という所から、発見できた。(もちろん利用者は存在をしっていたけど、システムの管理部門が見落としていた)

それぞれのシステムの名前、キーとなる情報やロジック(ビジネス知識)、システム間のキーとなる連係箇所、などを、関係者で、絵にしながら、情報を集約することは、大きな成果があった。

◎「わかっていない」ところが明確になった。
◎ システム間の重複とか、空白部分とか、全体のシステム間連携の構成の改善点を関係者で共有できた

でも、「わかった」だけで、何も改善できたわけではない。
DDD 14章の、システム間の7つの連係パターンとその実践ガイドを参考にしながら、少しずつ、手をつけていくつもり。

既存の一枚岩になっちゃって、かつ、構造疲労がめだってきた、販売管理システムを、受注・出荷・売上・請求という4つのサブシステムに分割しなおした、新システムへの移行を、9月までには、完成して、旧システムのクローズをしたいと思っている。

サービス提供側のシステムもいろいろ問題を抱えているけど、こちらは、根本には手をつけにくい。

新サービス、新機能などの案件のたびに、外付けしながら、新システムへの移行を少しずつ進める、という方針で取り組みはじめたところ。

Core Domain パターンと組み合わせる


Responsibility Layers 上で、Context Map を描くことができたら、次は、Core Domain の特定作業。
アプローチは「抽象」ではなく「捨象」が中心。

抽象化アプローチは、たくさんの候補の中から、重要そうな候補を選んで拾い上げていくアプローチ。
捨象化アプローチは、たくさんの候補の中から、重要でなさそうな(アンチ)候補を、取り除いていくアプローチ。

Responsibility Layers + Context Map の絵があれば、候補は揃っていて、整理もできているので、あとは、色分けをしていく作業の繰り返し。

同業他社と同じレベルでよさそうなところが、取り除く候補。

たとえば、請求書発行して、入金管理する債権管理システムは、重要だけど、今の事業では、他社との差別化要因や独自性を発揮する場所ではない。

こうやって、Generic Subdomains とか、Cohesive Mechanism とかに該当する部分を Core Domain 候補から除外していく。

残ったのが、サービス提供の開始・終了の管理とか、使用期間や使用量で課金する、サービス提供管理システム。

ここは、サービスの追加や構成変更、提供ルールや課金ルールを頻繁に変えるし、また、その変更を、サービスの差別化、ビジネスの競争力の源泉にしよう、というのが会社の基本戦略。

だから、サービス提供管理に関わる Operations 層、Policy 層、Potential 層のパッケージは、Core Domain 候補。

Responsibility Layers + Context Map で見えてきた全体像で、「Core」をマーキングして色づけしてみると、システムの全体構造が、さらに、はっきりと見え出す。

今まで、結構、開発投資を続けてきた現行の販売管理システムは、実は、コアドメインのシステムが業務の概念・構造から、かなりねじれて歪んだ箇所を、なんとか、つじつまを合わせるための機能追加/変更だったことが明らかになった。

コアドメイン側の「サービス提供管理」さえ、素直な構造になっていれば、販売管理業務自体は、パッケージソフトでも、どうやら対応可能、という方向が見えてきた。

全体像とコアドメインがはっきりしてきたことで、全体のシステム間の連係関係、ほんらいのあるべき姿とかが、関係者の間で共有できてきた。

こうなると、今までの手当たり次第、そのばしのぎの増築・改築モードから、少しずつ抜け出せそうな光が見えてきた気がする。

もちろん、予算も時間も技術能力も、制限だらけ。
あいかわらず、かなりの業務は、その場しのぎの増築・改築というのが実情。

でも、地図が手に入って、方向とか、到達の筋道や距離感がわかってくると、日々の業務も、その場しのぎというより、最終目標への通過点に見えてくるから、不思議なものです。

全体マップや、コアの色づけは、ときどき見直すことを続けたいと思っている。
でも、形式的に四半期に一回とかやるのは、形骸化しそうだなあ。

ある程度の資源を投入する開発案件の検討時には、全体マップとコアドメインモデルを使って、その開発の目的・期待成果を説明すること、というようなルールがよさそうかな。

まあ、これもやりながら、改善していきましょう。
正しい答え、いつも結果論。やった後しかわからないもの。
だったら、ある程度の仮説をもったら、実際にやってみて、事実からフィードバックを受け取りながら改善したほうが、結局は、早く答えにたどり着けるはず。

構造設計の良し悪し

Domain-Driven Design(DDD)の16章の最後の数ページは、パターンとして定義してないけど、構造設計について、興味深い内容が書かれている。

構造設計の良し悪しの判断?


ソフトウェアは、バグがあったり、性能問題が発覚すれば、開発チームのメンバーは、みんな問題だと思うし、修正しようと思う。
そして、直ったか直らないかは、いちおう確認できる。

構造設計になると、そうはいかない。

ソフトウェアがちゃんと動いていて、ソースの中身も、まあまあ、追いかけることができれば、全体の構造なんて、あまり気にしない技術者、チームが多いのかもしれない。

クラスが肥大化して、参照関係が入り組んできて、コードが読みにくくなり、修正の副作用が恐くなってくると、さすがに、これじゃまずい、という「感覚」はでてくる。

ファウラーが「リファクタリング」で書いているように「コードのいやな臭い」を感じる度合い、感じる人が増えてくる。

でも、臭いは、しょせん、感覚の世界。

●個人や体調によって、感じ方が違う
●いつもその臭いがしていると、なれて(麻痺して)臭いを感じなくなる
●臭いが解消したかどうか、事実として確認しにくい
...

これでは、設計の良し悪しの評価、改善手段の議論、改善の費用対効果、リスク判断、など、チームで意識統一するのは、至難のわざ。

スキルや経験の違いによって、視点、価値観、意見はばらばら。

こういう状態では、構造設計のスキルや実践レベルが向上するのは、なかなか難しそう。

最初にちゃんと設計して規則化して、構造を強制する?


プロジェクトによっては、パッケージの分割ルール、命名規則、クラスのサイズやメソッドのサイズの制限、アクセス修飾のガイドライン、...とか、構造にかかわる事項を、プロジェククトの初期に細かく決めて、ルールとして強制することもある。

私たちも、ドメイン層以外は、暗黙の習慣も含めて、結構、いろいろなルールを強制している。

UI層, サービス層、ドメイン層、インフラ層のレイヤ構造などは、かなり厳格に規則をつくって、分離構造を徹底している。
(フレームワークの使い方の約束ごと、という感じで強制している)

でも、ドメイン層の内部の構造は、分析しながら、見つけていくもんだと思っているので、特に、ルールは決めていない。

エバンスも書いているように、ドメイン層の内部の構造を、最初から、予見して、ルール化して強制する、というのは、弊害はあるけど、メリットはないと思う。

ガイドがないのも困ったもの


でも、ドメイン層の構造について、なんのガイドラインもないと、さすがに、無秩序すぎて、ソフトウェアがわかりにくく、扱いにくくなる問題がはっきりしてきた。

ドメイン層の構造も、ある程度のガイドライン、ゆるやかな決め事はプロジェクトの最初から用意したほうが良いと思うようになってきた。

ひとつひとつのオブジェクトの粒度


構造設計の前に、粒度設計というか、ドメインのオブジェクトをどういう単位で、作るか、という大まかな約束ごとを決めた。

基本は、小さいほうが良い、ということ。

そういうルールを言葉にすると、なんでもかんでもみじん切りにしちゃうやつがでてくる。
まあ、チームでちょっと話しをすれば、それなりのところに収まることは収まる。

もうちょっと、具体的な指針(考え方のヒント)としては、以下のようなことをやった。

◎ Primitive な Value Object (日付、金額、数量、識別番号、メールアドレス、... )を作る

ドメイン層のいちばん下、つまり、参照されるだけのスタンドアローンの Value Object を作ることを奨励した。

String, Date, BigInteger/BigDecimal フィールドと、それを操作するロジックを見つけたら、それを、Value Object として抽出する、というリファクタリングを地道に続ける。

◎ 発生や変更の同時性、一意性

ドメインオブジェクトは、発生時点で、専用のコンストラクタで、全ての初期値をセットするのが良い習慣、という方針。

デフォルタのコンストラクタと、setter を使って、 new, set,set,set, ... は、アンチパターンという発想に転換を進めている。(この達成度は、まだまだ)

オブジェクトの状態(ステート)の変更も、複数のステートを個別に変更するのではなく、一括して変更するメソッドを用意する。

もし、個別の変更が必要なら、それは、別のオブジェクトに分離することを、検討する。

オブジェクトの状態が、異なる理由で、異なるタイミングでいろいろ変化するのは、どこかおかしいぞ、ということ。

これは、状態(ステート)だけではなく、ソースコードの変更にも当てはまる原理。

クラスのソースコードが、異なる理由で、異なるタイミングで変更が起きるのであれば、それは、たぶん、クラスを分割したほうが良い。

電話番号のバリデーションルールを変更するときに、顧客 クラスのソースを変更するのは、おかしいよ、ということ。

◎概念の輪郭

DDD の「しなやかな設計」パターンの一つ、Conceptual Contours ですね。
ドメインのオブジェクトの粒度は、ドメインの概念の粒度と一致させる、ということ。

よく出てくる用語(概念)は、そのまま、ドメインオブジェクトとして表現すべき単位。

...

こういう議論は、なかなかチーム全員の共通意識にはならないけど、現場で具体例を使いながら、こういう考え方を含めて、意見交換をつづけると、まあまあ、だいたいの収まりの良い粒度が決まってくる。

経験から、言えば、次のような変化が起きた。

◎クラスは小さくなった (せいぜい100行)
◎メソッドも小さくなった (せいぜい10行)
◎名前は、クラス名、メソッド名、変数名、どれも、具体的で長めになった

パッケージのサイズ


ひとつのパッケージのクラスは、多くて10個程度、というガイドラインでやっている。

人間が一度に判断できるのは、せいぜい7個が限界、という認知工学の仮説(?)を尊重して、クラスの数を決めている。

アクセス修飾


クラスは、ほとんど、public になっているのが現状。
メソッドは、不要なものは、極力 private にしている。でも、private 以外は、public 、つまりどこからでも、グローバルにアクセスできるというのが実情。

構造の設計


こういう、粒度、パッケージサイズでドメインオブジェクトを作っていくと、クラスの数も、パッケージの数も増える。

パッケージは、ツリー構造でいちおう整理をしているけど、これは、ファイルの整理であって、ソフトウェアの(実行時の)構造設計とは、別の課題。

ドメインオブジェクト、ドメイン層のパッケージを整理して、参照関係を限定した、構造設計を、現場に浸透させるのは、なかなかたいへん。

パッケージ図、依存関係の矢印


構造設計は、ソースコードでは、検討できない。
ソースコードをいくら読みやすくても、ドメイン層全体の構造が、一目でわかる、なんていう手品はありません。

ちゃんとした構造設計をしようね、というなら、パッケージ図と、パッケージ間の依存関係の図示は、ぜったい必要な作業。

そういう図が存在しないプロジェクトは、構造設計なんて、誰も、気にしていない、ということ。

それでも、ソフトウェアは動くので、まあ、それはそれで一つのやり方なんだとは思います。

ただし、ドメインの構造の分析、その構造の表現をしていないソフトウェアは、変更がたいへんになることはまちがいない。

ドメインの構造と、ソフトウェア(のドメインモデル)の構造が、ほぼ対応がとれていれば、仕様変更が簡単に、合理的に、安全にできる。

ドメインとソフトウェアの構造がねじれている、あるいは、構造があやふやだと、技術者は仕様変更依頼がとても不合理で、理解不能な内容に見える。

この状態で、ソフトウェアを変更して、良い結果が生まれるわけがない。

パッケージ図を使って、パッケージの依存関係を描きながら、ドメインの概念の構造を分析・モデリングして、それをそのまま設計・実装に落としていくのが良いやり方。

構造の表現、構造のテスト


Java とか一般的な言語だと、パッケージをレイヤ構造で整理した内容を、素直に、実装する手段はありません。

下のレイヤから上のレイヤへのアクセスを制限する、なんていう便利なアクセス修飾の手段がない。

パッケージに、アクセス可能先を宣言したり、アクセス可能元を宣言するような、パッケージ単位のアクセス修飾宣言の仕組みがあったら、面白いのになあ、とか思っている。

パッケージ図の依存関係の設計を、そのままコードで表現する方法ということですね。

記述方法がないのだから、テスト方法もない。
まあ、ソースをリバースして、クラス図やパッケージ図を生成するくらいならできるけど、パッケージ間の依存関係、という宣言がないので、リバースエンジニアリングしたパッケージには、当然、パッケージ間の依存関係は登場しない。

こういう構造を、暗黙のルールではなく、明示的な宣言と、テスト方法がでてくると、ソフトウェアの構造設計技術が、ずいぶんと進歩するような気がする。

ドメイン層の構造設計のキーワード


DDD 16 章の最後の数ページから、ドメイン層の構造設計のキーワードをいくつか拾っておく。

Refactoring


もちろん、構造設計も Refactoring ですね。
最初から、良い構造なんてわからないわけです。

だから、開発を進めながら、時々、構造設計も見直して、リファクタリングを地道に進めるのが定石。
基本の手段は、

◎モデル駆動設計(パッケージ図を描く)
◎ユビキタス言語(ドメインの概念の構造を調べる)
◎継続的インテグレーション (パッケージ構成を、安全に変更しつづける)

Minimalism


構造は、できるだけシンプルにするのが良い。
構造がシンプルというのは、「参照関係」をできるだけ少なくする、ということ。

クラスを大きくすれば、参照関係は内部に取り込めるけど、これは、筋が悪い。
クラスを分割して、かつ、参照関係を、必要最小限に保つように、努力することが大切。

もちろん、双方向の参照や、循環参照は、ご法度に近い。
単一方向の参照がもっともシンプルで扱いやすい。

みんなで話す


構造は、ソースコードレビューや自動テストという、具体的な評価手段がない世界。

パッケージ図を描いて、それが、どういう意図で、コード上、実際にどうすべきか、ということを、チーム内でいつも共有することが必要。

この実践は簡単ではない。
「コードのいやな臭い」のように「感覚的」な話しになりやすく、なかなか、短時間で、効果的なコミュニケーションができない、というのが実感。

まあ、話しを続けることで、じょじょにだけど、チーム内に、共通の文化が生まれてくることは、実感できたきた。

ドメイン層の構造設計も、2年くらい、言い続ければ、それが、当たり前になってくれそう。

構造の改良は、しなやかな設計をうむ


ドメインの構造の理解が進み、その構造を、ソースコードの構造に反映できれば、ソフトウェアは「しなやか」になります。

扱いやすく、わかりやすいソフトウェアになる。
変更依頼にも、短時間で、自信を持って、対応できるようになる。

ドメインの概念の構造の理解と実装は、開発者の仕事をとても楽に、楽しいものに変えてくれる。

Responsibility Layers パターンを、実践の中で、発見し、体得していくと、ソフトウェアが、わかりやすく、柔軟に、同時に、堅牢になるのが、実感できる。

◇ ドメインの静的な制約を表現した Potential 層
◇ 業務で起きている事実を表現する Operation 層
◇ 業務の予定、予約を扱う Commitment 層
◇ 業務上、起きて良いこと/起きてはいけないことを動的に制御する Policy 層
◇ 業務の責任者が判断するための参考情報を提供する Decision Support 層

分析・設計を続けていく中から、こういうドメインの階層構造を、発見できた時に、ソフトウェアが見違えるように、わかりやすく、扱いやすくなることを、実際に体験すると、ドメイン層の構造設計の価値、ありがたさに目覚める。

コアがはっきりすると、仕事が楽になる


構造設計の改善を続けていくと、コアになるパッケージ、Generic Subdomain を実装したパッケージ、Cohesive Mechanism を実装したパッケージ、というように、パッケージの役割が明確になってくる。

ドメインのコアがはっきりしてくると、全体の構造、開発メンバーの配置、開発プロセスの進め方の軸がはっきりしてくる。

こうなってくると、ソフトウェア開発の仕事は、ずいぶんと楽になる。

コアがわからないと、要求仕様全体と格闘し、アーキテクチャが複雑化し、開発パワーも、全体に広く薄く割り当てることになる。

みんなで苦労するわりには、進みも遅いし、顧客の満足度も低い。

コアがはっきりしてくると、設計判断やプロジェクト管理の判断の軸が明確になる。

・なにを優先し、なにを先送りにするか?
・妥協して簡略にすませるか、本腰を入れて取り組むか?
・どこをどのチームが、誰が、担当するか?

こういう課題は、すべて、「コアドメイン」を軸に判断することで、答えが導きだしやすくなる。
もちろん、関係者の同意も取りやすい。

ドメイン層の構造設計


DDDの 16章のテーマは「ドメイン層の構造設計」

エバンスは、どこかの Qcon で「DDD 16章は、あまり活用の機会がないので、それほど重要ではない。本から省いても良いくらい」みたいなことを言っていた。

私は、そうは思えない。
小さな家だって、構造設計はちゃんとしていたほうが良いに決まっている。
もちろん、高層ビルと、自転車置き場では、問題の複雑さや難易度はぜんぜん違う。

でも、自転車置き場だって、ちゃんと構造設計するのと、そうじゃないのでは、利用者の利便性、構造物の価値、耐久性、将来の拡張性など、資産としての価値がまったく違ってくるはず。

どんな小規模なソフトウェアでも、基本的な構造設計は、ちゃんとできるチームでありたいと思う。

ドメイン層のフレームワークは見果てぬ夢か?

Domain-Driven Design(DDD) 16章の最後のパターンは、Pluggable Component Framework パターン。

DDD の例では、半導体製造プロセスの自動化、という問題領域(ドメイン)で、半導体メーカーと半導体製造装置のメーカーの団体 ( SEMATECH) が、 コンピュータ統合生産 ( CIM : Computer Integrated Manufacturing ) 用のドメイン層フレームワーク ( SEMATECH CIM Framework ) を例にあげている。

私は、半導体製造のドメインのソフトウェア開発は、経験がないこともあるけど、ほとんど興味がわかなかった。
この例を読んでも、現実的な解決策、動く実際のソフトウェアのイメージがぜんぜんわかなかった。

ドメイン層以外は、フレームワークを活用してる


私たちは、ドメイン層以外は、オープンソースのフレームワークを積極的に使うようにしている。

◎ IoC コンテナ Spring Framework
◎ UIコントロール Spring MVC, Spring Web Flow, Mobylet
◎ テンプレート式ビュー Velocity
◎ 認証 Spring Security
◎ SQL マッピング iBatis
◎ メッセージング Mule ESB
◎ テスト JUnit, Canoo Web Test
...

ドメイン層以外は、ありものを活用して、簡単に作れるなら、そのほうが、費用対効果が良い。

ドメイン層は、自分たちで、アプリケーションごとに、個別に、モデリングと設計・実装をしている。そこが、いちばんのソフトウェアの価値。
そういう価値を生み出せる、手ごろな製品、ライブラリ、フレームワークとかがないから、コストがかかり、リスクも高い、個別のアプリケーション開発プロジェクトをやっているわけだ。

ライブラリ、フレームワーク、ビジネスパターン


業務アプリケーションは、全体の構造、扱う情報、ビジネスルールの内容、など、なんとなく、共通な部分、同じようなところを感じている人は多いと思う。

でも、ほとんどの業務アプリケーションは、あちこちで、似たようなものを、個別につくっている。

ムダといえば、ムダ。

ドメイン層以外は、フレームワークやライブラリで、再利用することは、ここ10年間で、急速に広がってきた。

でも、ドメイン層の開発だけは、似たようなものを、毎度毎度、新規開発、という感じ。

ビジネスオブジェクトの共通ライブラリ、業務アプリケーションのフレームワーク、というような試みがないわけじゃないけど、あまり一般的ではない。

大昔、IBMが、オブジェクト指向の業務アプリケーションフレームワーク開発を目指した「サンフランシスコプロジェクト」なんていうのがあったけど、どうなったかなあ?

日本でも、ビジネスオブジェクトの再利用で、ソフトウェア開発シーンを劇的に変えるとか、さかんに宣伝していた会社がいくつかあったような気がするけど、最近は、聞かないなあ。

ビジネスパターンや分析パターンと呼ばれる、業務アプリケーション開発に役立つパターンがいろいろあると思うけど、これも、それほど、広く活用されているわけではない。

ビジネスオブジェクトのライブラリも、業務アプリのフレームワークも、ビジネスパターンも、結局、汎用性/再利用性と、わかりやすさ/使いやすさのバランスが、うまくとれていないんだと思う。

ファウラーの「アナリシスパターン」とかは、考え方とか参考なるけど、業務アプリ開発に、そのまま使えて、開発が楽になる、というようなものではない。

DDD にでてくるパターンは、考え方は、とっても大切だし、参考になるけど、現場で、即、役に立って、効果てきめん、というものじゃない。

さて、どうなるか


ドメイン層以外のフレームワーク、アジャイルな開発方法、IDEやテストなどのツール類、などは、ここ10年くらいで、大きく進歩して、一般化したと思う。

これらの技術を使えば、ドメイン層を分離する、というアーキテクチャでの開発は、10年前と比べれば、格段に進歩し、楽になった。ドメインモデルパターンも現実的なアーキテクチャになった。

また、インターネットを使ったシステム間連係(特に、REST スタイルの API )、それから、非同期のメッセージングも、ここ5年くらいで、気軽に使える技術になってきた。
業務アプリケーションの二大関心事である「記録」と「通知」のうち、「通知」という業務のモデルを、自然に、設計・実装できるようになったきた。

もしかしたら、ドメイン層でライブラリやフレームワークを活用する条件が、はじめて整ってきたのかもしれない。

マーチンファウラーの「アナリシスパターン」とか Hruby の「ビジネスパターン」とかを元ネタにした、ドメイン層向けのライブラリやフレームワークが、これからの10年で発展して、一般化するかもしれない。

日付や期間に関するライブラリとか、ファウラーの Event Sourcing パターンを元にした業務アプリのフレームワークとか、自分でも、ちょっとチャレンジしてみようかな、とか思っている。

一方、業務アプリケーションの汎用化は、結局、ソフトウェアをわかりにくく、扱いにくくする、という経験則も、見に染み付いているのも事実。

さて、世の中はどうなるか?
自分たちは、どっちに進もうか?

ドメイン層を実現するのに、手軽に使えて便利な、ライブラリやフレームワークがあれば、ぜひ、使ってみたいと思う。

とりあえず、自分たちで何か作りはじめてみるのも面白そうか?

Thing と Thing-Type に知識を分離する : Knowledge Level パターン

エバンスは、Knowledge Level パターンを、ドメインモデルの構造設計、特に、ビジネスルールの変更に動的に対応できるソフトウェアの構造という視点で、書いているらしい。

私は、どちらかというと、モデリングの基本テクニックとして、ドメインの概念・知識を、

● Thing-Type クラス
● Thing クラス

の2つに分離すると、うまく整理できることが多いよ、というモデリングの基本テクニックとしてとらえている。

性格の異なる知識を、別のオブジェクトに分離することで、片方の知識に変更があった時に、扱いやすくなる、というのは、もちろん大きなメリット。

でも、将来もあまり変化がないだろう知識でも、性格が異なる知識は、別のオブジェクトで管理したほう、ソフトウェアがわかりやすく、扱いやすくなる。

中古車


私が、Thing と Thing-Type に目覚めた(?)のは、中古車をネットで検索するソフトウェアを開発していた時。

個体識別


中古車は、同じ車種であっても、一台一台別のオブジェクト。
出品番号とかで、個別に識別する。

車の識別は、とても面白いテーマ。車のナンバープレート(登録番号)で、特定できるわけではない。中古車市場だと、ナンバープレートのない車もあるし、ナンバープレートは、変更可能。つまり、永続的な識別情報としてはふさわしくない。

車には、法律で刻印が強制された、車台番号というのがあって、例えば、盗難車の捜査で識別情報として使うのはこっち。

車台番号で、特定する個体が、Thing。

車の「モデル」で識別


中古車を検索するときには、メーカー(ブランド)やモデルから探すことが多い。

「トヨタ」の「プリウス」とか、「ホンダ」の「フィット」とか、いう感じ。

モデルが同じ中古車は、車両の状態がだいたい同じなら、走行距離、年式でだいたいの相場が決まっている。

モデルが、Thing-Type ですね。

情報の持ち方


車台番号100番の車(Thing)が持つべき情報としては、走行距離、色、オブションの装備状況とかある。

モデル「プリウス」が持つべき情報が実は難しい。
「プリウス」という名前以外に、すべてのプリウス車に共通の情報が以外と少ない。

「S]「L」「Sツーリングセレクション」、...、てな感じで、モデル名を詳細にすれば、もうちょっと共通化できるんだけど、この詳細なモデル名は、宣伝文句の性格が強く、中古車データベースに登録される時に、ちゃんとした識別情報として登録してもらのは、無理。

で、最初の設計は、基本は、全部、Thing 、つまり中古車の一台一台の情報としてすべてを記録する。

「プリウス」の燃料タイプなんて、ハイブリッド固定に決まっているけど、中古車ごとの情報として、「燃料タイプ=ハイブリッド」というデータを作成しておく。

まあ、最初のバージョンは、この設計で、なにも問題はなかった。

すご腕の店長


このシステムは、最初は、消費者が勝手に探すというより、店舗で、セールス担当者が接客しながら、いっしょに探すという使い方をしていた。

で、導入してしばらくたつと、めちゃくちゃ売上成績の良い店長が出現。

話をはしょると「この店長の売り方ノウハウをシステムに組み込んだら、普通のセールス担当者でも、もっと売れるのでは?」というのが、システム改善の大きなテーマになった。

で、店長の仕事ぶりを蔭から観察させてもらったり、ヒアリングしてみると、店長は、画面に表示される、モデル名、走行距離、色、年式などを材料に使っているけど、「こっちもなかなかいいですよ」という「リコメンデーション」をやっている。

最初は、色がまったく違っていたり、メーカーやモデルが違う車を突然、進めたりする。

私たちの造ったソフトウェアでは、同じ検索条件には絶対ならない車を比較しながら、商談している。

購入希望者と、ちょっと話をして、数台の車を提示して、その反応によって、店長の頭の中には、独自の「おススメの車一覧」がでてくるらしい。

後から聞いた話だけど、その店長は、中古車が登録されるたびに車情報は徹底的に頭に叩き込むし、暇な時に、ちょっと不思議な条件の組み合わせで、中古車検索システムを使ったりしていたらしい。

店長のおススメの秘密


店長の頭の中には、メーカーのモデル名とは別の独自の「車のタイプ」のリストがあって、そのタイプと、個々の中古車を結び付けているらしい。

このお客さんなら、この「タイプ」というイメージマップがある。
この車は、この「タイプ」というイメージマップがある。

それが、本人の思い込みではなく、お客さんのニーズにうまくフィットしているのは、抜群の営業成績が実証している。

まあ、結論からいうと、そのイメージマップを、うまく理解して、ソフトウェアとして実装することはできませんでした。

店長との話を手掛かりに、独自の「モデル一覧」を造って、こういう条件の中古車が、このモデルと一致する、という試作はした。

でも、結局、わけのわからない一覧になっちゃって、開発は、そこで終了。

ただ、人間は、頭の中の、「これとこれは同じタイプ」という判断をしていて、それが、とっても、役に立ち知識で、それをソフトウェアで実現できたら、めちゃくちゃ役に立つソフトウェアができそう、という印象が、強烈でした。

今、考えると、その店長は、自動車関連の雑誌とか、業界新聞とかも、こまめにチェックしていて、「ライバル車 対決特集」とか「ユーザの購入談話」とかのネタをもとに、「顧客」「車のタイプ」「個々の中古車」のマッピングイメージを作っていたんじゃないかと思う。

こっちも、そういう情報を共有していれば、もうちょっと、店長のノウハウをひっぱりだせたんじゃないかと思う。

Thing-Typeへの漠然としたあこがれ


結局、この時は、Thing とThing-Type に知識を分けることは失敗した。
でも、漠然とだけど、Thing の個々の情報とは、別のレベルの「Thing-Type」の知識をソフトウェアに盛り込めば、単純な検索システムではなく、役に立つ検索システムができそうだ、ということが強く印象に残った。

この時から、Thing と Thing-Type に知識を分けることがすばらしい、ということを、素朴に思い込んで、仕事をしてきている気がする。

ビジネスルールが入り組んできたら、Policy オブジェクトに、ビジネスの知識をカプセル化する、なんていう、Responsibility Layers のパターンは、ごく自然に受け入れている。

DDD の例


DDD の Knowledge Level パターンは、具体例として、「従業員(Employee)」に異なった、

・福利厚生(特に年金制度)
・給与制度

を適用する、という人事・給与システムの一部を取り出して、説明している。

最初は、Thing レベルの Employee クラスを、「時給制のEmployee」と「年俸制のEmployee」にサブクラス化する、というモデル。

ここに、職務(Job Title) で識別する EmployeeType クラスを導入することで、Thing( Employee )が持つ情報と、Thing-Type (EmployeeType) が持つ情報に分離する、方向に発展。

さらに、Payroll-Type (給与タイプ)と、RetirementPlanType(年金タイプ)というタイプオブジェクトを導入。

最初は、Employee という Thing レベルのオブジェクトと、年金タイプを直接関連づけていた。

Thing-Type レベルの導入


Thing-Type を導入して、発展させたモデルでは、Employee は、EmployeeType と関連づける。

そして、それぞれの EmployeeType(従業員タイプ) と、PayrollType(給与タイプ)、RetirementPlanType(年金タイプ) を関連づける。

つまり、給与制度、年金制度の選択肢を、Thing-Type のレベルで、記述し、Employee という Thing レベルとは、分離したモデルになっている。

最初の、Employee の給与タイプ別にサブクラス化して、年金タイプと直接関連づけたモデルでは、会社の制度として用意していない組み合わせを定義できちゃった。

タイプ間の関連として定義した最後のモデルだと、この「従業員タイプ」は、この給与制度で、年金制度は、これ、という会社の制度を素直に実現できた。

もちろん、制度の変更も、タイプとタイプ間の関連の変更程度で、わかりやすく、安全にできるモデルになっている。

Thing のサブクラスをThing-Type クラスへ


DDDの例に使っているモデルの before/afterを比べると、従業員のサブクラス( Thing のサブクラス)をやめて、Thing-Type のほうで、タイプ分けをしている。

モデルでは、Thing-Type でも、サブクラスがでてくるけど、実装では、extends ではなく、enum クラスで記述するのがよさそうなくらい、シンプルなオブジェクトになっている。

たぶん、Thing レベルで、サブクラス化しているモデルは、Thing-Type オブジェクトとして、タイプの違いを抽出し、enum クラスで実装、というのが、基本パターンなんだと思う。

あるいは、ドメインオブジェクトのフィールドで、String 定数や、int 定数で、区分分けをして、switch 分で処理しているような箇所を見つけたら、定数定義を、enum クラスとして抽出し、ロジックを、enum クラスに移動するとか、enum クラスを扱う Policy クラスを作って、ロジックは、そちらに移動すると、ドメインオブジェクトの役割分担がすっきりして、わかりやすいコードに改善できるはず。

ドメインモデリングの強力なテクニック:Responsibility Layers パターン

ソフトウェアの分析・設計で、

◎責任駆動設計 ( RDD : Responsibility-Driven Design )
◎レイヤ構造 ( Layered Architecture )

の二つは、ソフトウェアをわかりやすく扱いやすくするための、基本かつ強力なテクニック。

Domain-Driven Design (DDD)の、16章「構造設計」で、この二つを駆使した、Responsibility Layers パターンが登場する。

責任駆動設計


オブジェクトごとに、単純で、明確な役割を持たせるように、設計すること。

たとえば、(日時ではなく)日付だけを 扱う BusinessDate クラスや、DateRange クラス。
日付や期間を扱う時は、こいつらに全部まかせる。

時・分・秒とかは、別の TimePoint クラスとか、Interval クラスとか、Duration クラスとかが、担当する。

「誕生日と年齢」とかは、BusinessDate クラスを内部の保持する、DateOfBirth クラスにまかせる。

郵便番号は、String クラスではなく、PostalCode クラス、電話番号も、Telephone クラスにまかせ、氏名は、PersonName クラス。

こいつらを、顧客番号で識別する、Customer オブジェクトが Aggregate のルートになって束ねる。

Customer オブジェクトは、Entities パターン、それ以外は、Value Objects パターンで、設計・実装。

...

こんな感じで、オブジェクトに単純で、明確な役割を持たすように設計していくのが、責任駆動設計。

顧客オブジェクト自身が、String,Date,int で、20も30もフィールドを持つ設計・実装も可能。

でも、これは、顧客オブジェクトの責任範囲が広すぎる。責任範囲を狭めてあげないと、パンクしちゃいますね。

役割が単純で明確なオブジェクトに分割する、責任駆動設計が当たり前になってくると、ソフトウェアは、格段に、わかりやすく、また、変更も、局所的になって、安心してできるようになる。

レイヤ構造


責任駆動設計だと、オブジェクトの数は、増えてきます。
ひとつひとつのオブジェクトの責任範囲を小さくわけ、分担するわけだから、どうしても、クラスの種類は増える。

当然、パッケージ( Modules パターン)を使ってグルーピングする。

でも、このまま放置すると、パッケージ自体の整理が難しくなってくる。

あるパッケージと別のパッケージが、双方向に、参照(依存)する関係がはじまると、コードは、スパゲッティになり、ぐしゃぐしゃになってくる。

どのパッケージが、誰から参照されているか、だれも、正確にはわからない。
ツールを使って、依存関係をレポートすると、レポート量が多く、内容も複雑で、読む気もしない。

構造設計を軽視すると、オブジェクトやパッケージの数が増えるたびに、破綻のカウントダウンが進行する。

レイヤ構造は、「構造設計」の基本中の基本。

Upper Layer : 上のレイヤは、下のレイヤを知っている(依存する)
Lower Layer : 下のレイヤは、上のレイヤを知らない(依存しない)

パッケージを、それぞれのレイヤに配置して、このレイヤ構造の参照制約を徹底すれば、構造がすっきりとし、安全になる。

参照を制約する


下のレイヤから、上のレイヤのオブジェクト(パッケージ)への参照を禁止するだけで、コードはスパゲッティではなくなる。

スパゲッティ構造から、ラザニア構造になるわけだ。

参照を制約しなければ、どのクラスは、すべての Public クラスの、Public なメソッドやフィールドを、どこから参照してよい、ことになる。なんのことはない、悪名高いグローバル変数の乱用を、オブジェクト指向っぽくやっているだけ。

グローバルの自由な参照こそ、スパゲッティコードが生まれる原因なんだ。

参照の方向や範囲を制限すれば、それだけ、スパゲティコードが生まれにくくなる。
理屈は単純。
実践は、最初は、たいへんかもしれない。

発想の転換とか、チームや個人の価値観や規律とかの問題。技術的な問題ではない。

ソフトウェアがちゃんと動いていても、構造が、スパゲッティでは、ダメだ、という思いを共有し、かつ、そうしないように、日々努力することを自然にできるチームか、どうか。

構造設計が貧弱、劣悪でも、ソフトウェアは動く。動いているなら、それは正しい、という人・チームが多い。多いということは、それこそが、真実なのかなあ...。

ドメインモデルとか、DDD とかの設計の考え方にこだわる(?)のも、少数派であることはまちがいなさそうだしなあ。

まあ、自分は、現場で、ドメインモデルやDDDに取り組んでからのほうが、良い仕事が楽にできるようになったと思っているので、この方向で、もっと腕を磨きたいと思っている。

ドメイン層内部のレイヤ構造の基本パターン


Responsibility Layers パターンに、登場する、5つのレイヤは、ドメインオブジェクトの整理、ドメイン層内部の構造設計の参考になる。

◎ Decision Support 層 ( 意思決定の支援 )
◎ Policy 層 ( ビジネスの決め事 )
◎ Commitment 層 ( 約束ごと )
◎ Operation 層 ( 日々の業務のアクションとその結果 )
◎ Potential 層 ( 業務実施の制約条件 )

という感じで、ドメインオブジェクトを整理すると、わかりやすいよ、ということ。

モデリングとかで、このレイヤ構造を意識すると、ドメインオブジェクトの粒度とか、役割の分担方法とかに、いろいろなヒントを提供してくれる。

実際には、厳密なレイヤ構造(厳密な参照方向の制限)にならないところもあるけど、それは、リファクタリングネタというか、課題としていろいろやってみている。

なお、Business Date とか、Money とかの プリミティブな Value Object は、さらに、この下のレイヤに集めるようにしている。

下から、説明したほうが、わかりやすいかなあ。

Potential 層のオブジェクト



業務を実行するときに、構造的に、静的な制約条件がたくさんある。

DDD のサンプルで使われている、貨物の輸送状況トラッキングだと、Customer(顧客)オブジェクトは、この構造的な制約になる。

Customer オブジェクトは、別のアプリケーションで管理され、識別番号も、そっちで発行・管理されている。

貨物を追跡する時に、「どの顧客」の貨物であるかは、追跡アプリは、外部から与えられた「顧客のリスト」に限定しないといけない。

マスターに登録された顧客(番号)だけ、という制限があるわけだ。

追跡すべき輸送イベントの種類 ( EventType )とか、イベントの結果、変わる貨物の状態の区分 ( StatusType ) とか、Enum 型で表現する、ドメインオブジェクトも、Potential 層の住人。

貨物の追跡アプリで、参照できる地名も、国連のさだめた UN LOCODE というコード体系でのみ、表現している。

UN LOCODE が、この貨物追跡ドメインにおいては、制約になっている。

Potential 層というのは、このように、外部で発行・管理している識別コード体系、とりうる値が有限で固定の、種類(コード)や、区分(コード)でを、知っているオブジェクトを集める場所、ということ。

もちろん、これらのオブジェクトは、上の層は、全く知らない。
(参照しない)

Operation 層のオブジェクト


日々の業務で起きていることを表現するためのオブジェクト。
アプリケーションの中心は、だいたいがこの層のオブジェクト。

基本は、三つ

・Event オブジェクト
・関心事オブジェクト
・State オブジェクト

Event オブジェクトは、貨物を受け取った、貨物を積み込んだ、船が出発した、船が到着した、貨物をおろした、....というように、貨物に発生した事実を、通知・記録するためのオブジェクト。

在庫管理であれば、入庫イベントや出庫イベント、預金通帳なら、入金イベントや出金イベント、受注管理であれば、注文受領イベント、出荷指示イベント、出荷通知イベント、...。

ビジネスのさまざまな活動や起きた事象の中で、「関心の対象」となる、起きた事象を、

・イベントの対象
・日時
・起きたイベントの種類
・その他の補足情報

として、表現するのが、イベントオブジェクト。

DDD サンプルだと、イベントの対象は、「貨物」、イベントの種類は、さっき書いた、「受け取った」「積んだ」「降ろした」「渡した」などの事象。

補足情報としては、「場所」を UN LOCODE で表現。

関心事オブジェクト ( OoC : Object Of Concern ) は、この場合は、もちろん「貨物」。

貨物の輸送状況を知るのが、このアプリケーションの中核の価値。

関心事オブジェクトを見つけることは、普通はとても簡単。

業務的に、

・検索したいオブジェクト
・一覧したいオブジェクト
・詳細を表示したいオブジェクト
・アクションを起こしたいオブジェクト

を特定する。

一覧画面とか、詳細画面とそこに登場する「ボタン」を見れば、関心事が何か、一目瞭然ですよね。

で、関心事オブジェクトは、Entity であり、Aggregate のルートです。

そして、その関心事オブジェクトが、集約しているのが、「状況」を表現した、STATE オブジェクトというわけです。

貨物オブジェクトの現在の「場所」を表現しているのが、STATE オブジェクト。 DDD サンプルだと、Delivery オブジェクトが、現在の貨物の場所を知っているオブジェクト。

業務アプリケーションの基本は、

・イベントオブジェクトを受信し、
・関心事オブジェクトの STATE オブジェクトを適切に更新し、
・イベントが起きたことを記録し、
・イベントが起きたことを通知する

のが基本パターン。

Operation 層は、この基本パターンを表現するための、 Event, OoC, State のオブジェクトを集める場所。

Operation 層のオブジェクトは、下位のレイヤ Potential 層で定義された、コードマスター、種類マスタ、区分マスターなどを参照し、また、そこで定義されたものだけに制約される。

わりと単純なアプリケーションなら、この Operation 層 over Potential 層の二層構造で、実現できちゃうことも多い。

Commitment 層


もうちょっと役立つアプリケーションにするなら、Commitment オブジェクト ( 約束を表すオブジェクト)を登場させる。

DDD サンプルだと、貨物の宛先(=顧客との配送の約束)Specification、輸送のスケジュール(業者内部の予定)Itenary などが、この Commitment オブジェクトにあたる。

ビジネスでは、約束(コミットメント)して、それを、確実に、実行することが基本中の基本。
開発だって、納期を約束して、なにがなんでも、それをまもんなきゃいけない。

朝会の約束したら、8時には、会議室に集まらないといけない。

ビジネスのアプリケーションは、簡単に言えば、

・約束(Commitment ) を記録し
・約束を実行しつつあるイベント(アクション)を記録し、
・それを、現在の状態 ( State ) に反映し、
・約束(予定)との差異をチェックし、
・問題があれば、対応アクションを起こす

ための道具が必要。

Commitment オブジェクトは、もっとも重要な関心事オブジェクト ( OoC ) だというわけだ。

DDD サンプルでは、貨物オブジェクトが、関心事オブジェクトで、その内部で、Commitment (約束・予定)と State ( 現在 ) の状態を持つ設計になっている。

Commitment オブジェクトは、Operation 層の住人(という性格が強い)

在庫管理でいえば、Commitment 層を導入すると、入庫予定、出庫予定、将来の引き当て予約、...というように、アプリケーションの守備範囲が広がる。ここまでサポートしてくれたほうが、もちろん役立つソフトウェアになる。

預金通帳なら、過去の入金・出金に加えて、入金の予定と出金の予定まで管理すれば、今月末の余裕資金とか、がわかるようになる。

いまどきのビジネスソフトは、こういうレベルを期待されているはず。

Commitment 層は、役に立つ、喜んでもらえるソフトウェアのキーフィーチャーといえる。

Policy 層


ビジネスの決め事がちょっとややこしくなると、独立したオブジェクトとして表現したほうが、すっきりする。

ちょっとしたビジネスルールは、Value Object や、Entity オブジェクト、Domain Event オブジェクトにまかせる方法もある。

でも、業務で、次のような言葉がでてきたら、そのまま、Policy オブジェクトにして、それを、Policy 層に集めちゃう。

・Pricing Policy
・OverBooking Policy
・Cancel Policy
・Routing Policy
...

ホテル業務などだと、Over Booking Policy と、Cancel Policy は、基本のビジネスルールですね。
輸送業界でもそうです。

Policy オブジェクトは、手続き型の表現になりがちで、あまりお薦めではないけど、業務で「○○ポリシー」という概念がでてくるなら、それは、文句なしに、Policy オブジェクトとして、素直に、実現する。

あるいは、契約書や申込書の裏に書かれたルール集、携帯電話の複雑な課金体系、審査業務マニュアルのチェック事項集、複雑な表に膨れ上がった割引価格表、...

こういう実体を使っている業務なら、こういうルールのカタマリを、素直にオブジェクトにしたほうが良い。これも、Policy オブジェクトであり、Policy 層の住人。

<注意1>
Potential 層も、Policy 層も、業務のルールや「制約」を表現する点では同じ性格。

違いは、ルール変更の頻度と柔軟性。

Potential 層は、このドメインでは、変更は不可です。静的で構造的な制約。
おいそれと変更はできないものを、ここに置く。

Policy 層のルールは、ビジネスのたんなる(?)決め事であり、場合によっては、特例として、ルール違反でも、OKとする、というような業務運営(Operation) も十分にある。

だから、Policy 層のオブジェクトの実装や、Policy オブジェクトを使ったのルールの強制は、ほどほどに設計する必要がある。

業務上、レアであるが、必ず発生する、特例ケースを、どう扱うかが、難易度は高いけど、業務アプリの設計者の腕のみせどころ、でもある。

<注意2>
頻繁に変える可能性がある区分コードなら、それは、Policy 層に置く。

「○○区分」とかが登場したら、単純に、Potential 層で、Enum で実装、とか、やっちゃいけない。

もしかしたら、今年の夏のボーナスの販売キャンペーンでだけ、使いたい区分かもしれない。

これは、名前は、「区分」でも、静的・構造的な制約でなく、動的・振舞の制約。

ビジネスのルールや区分を、Policy とするか、Potential とするかは、けっこう重要な設計判断。

まあ、やりながら、リファクタリングしていく、というパターンもありますね。

Policy 層は、最初から、「ルールの変更あり」という前提で、作るべし。

Decision Support層


利用者に判断を求めるために、参考情報を提供するためのオブジェクト群の層。

特定の貨物の現在位置は、Operaiton 層のオブジェクトだけで、知ることができる。

貨物全体の流れ、顧客との約束の達成度、ご配送や再配送の発生頻度、...

こういう情報を、わかりやすく集約するためには、分析手法とか、集計方法の知識が必要。
こういう知識を持つのが、Decision Support 層のオブジェクトの役割。

リコメンド機能とかを実現するオブジェクトも、Decision Support 層の住人ですね。

アプリケーション間の関係


Decision Support 層は、そもそも別のアプリケーションに分離して、Operation 系のアプリケーションとは、 Customer - Supplier の関係になることが多い。

また、あるアプリケーションの Potential 層が、他のアプリケーションでは、Operation 層になるのが普通。

DDD サンプルだと、Customer オブジェクトは、Potential 層だけど、隣接して、顧客管理アプリケーションが存在して、そこから、Customer 情報を受け取ることを想定している。

エンタープライズアプリケーションというのは、こうやって、社内それから社外まで含めてさまざまなアプリケーションが、Potential 層 - Operation 層 - Decision Support 層 のアプリ内の位置づけを変えながら、階層的に絡み合っている世界。

アプリケーション連携を設計するときも、

・Operation 層を、別アプリの Potential 層に
・Operation 層を、別アプリの Decision Support 層に

提供する、というパターンが多い。

また、水平連携ということで、

・イベントの発生元の Operation 層が、別のアプリの Operation 層に、それを通知

というのも、非常によく出て来るパターン。

メッセージングが面白い


ここらへんのつなぎを、最近は、

・Mule ESB
・REST スタイルの API
・EDA ( Event-Driven Architecture )
・SEDA ( Staged Event-Driven Architecture )
・EIP ( Enterprise Integration Pattern )
・Domain Event と Event Sourcing パターン
...

とかと格闘(遊び?)しながら、実践でやりはじめたところ。

一言でいうと、DB中心のアーキテクチャから、メッセージング中心のアーキテクチャに発想がシフト中、という感じ。

もちろん、業務アプリで、DB(永続化)の重要性はかわらない。メッセージングが、永続化と並ぶ、二本目の柱として急成長中、というイメージですね。

DB(永続化)+メッセージングは、「記録」と「通知」という業務ドメインの本質を、ITで素直に実現する、単純でわかりやすい構図だと思っている。

なぜ、DBか? なぜ、メッセージングか?

それは、ビジネスでは、「記録」と「通知」が基本だから。

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