ドメイン駆動設計 : 第IV部「おおきな設計」Strategic Design

Domain-Driven Design(DDD) を最初に拾い読みしたとき、いちばん興味を持ったのは、第IV部 Strategic Design だった。

現実の問題は大きく、複雑


ある程度の規模のプロジェクトになると、DDD の「基本のモデリング要素(第II部)」と「ドメインモデルのリファクタリング(第III部)」だけでは、解決できない、扱いにくい問題が山積みになる。

・広大な開発範囲(壁いっぱいに広げても描ききれないクラス図)
・サブシステム分割と統合作業
・複数チームの役割分担
・既存のレガシーシステムとの連携
・他の企業のシステムとの連携
...

これに、開発の契約、出身母体の違うメンバーをかき集めた混成チーム、顧客の部門間の調整、別企業との事業提携の交渉、...。
さまざまな要素が、問題をさらに複雑にする。

開発メンバーの一人として参加するなら、まあ、こういう問題は、実感がわかないかもしれない。

でも、アーキテクトとか、プロジェクトの責任者、開発チームのリーダーとかになれば、こういう、面倒くさい問題の、直接の利害関係者になる。

自分たちではコントロールできない問題領域のはずが、「開発サイドで、なんとかしてくれ」となってしまうことも多い。

こういうのは、「調整スキル」とか「交渉スキル」という、いわゆる「ビジネススキル」の問題として取り組む方法はある。

まあ、そういうスキルは必要だし、役に立つシーンもあるけど、技術者たるもの、こういう問題も「設計」の問題として取り組みたい。

DDD の第IV部「大きな設計」(Strategic Design) は、まさに、こういう「設計」の考え方、やり方を扱っています。

解決の糸口は、やっぱり「ドメインの理解」


エバンスの信念は、こういうスコープが広く、複雑な問題にも「ドメイン駆動」で立ち向かうこと。

ドメインを深く理解することが、こういう問題を解決する、確実で、効果がある方法なんだ、ということですね。

・ドメインの基本の枠組み、基本の軸を理解する
・ドメインに登場する利害関係者の価値観・行動原理を理解する

こういうドメインの理解にもとづいて

・サブシステムへの分割設計
・複数チームの役割分担や協力体制の構築
・既存システムとの連携インタフェースの基本設計
・他企業のシステムとの通信インタフェースの基本設計

をやることで、問題に適切に立ち向かかうことができる。

ドメインを誤解したまま、システム内部の技術的な視点と知見だけで、こういう課題に取り組むと、問題を悪化させる一方。

きれいな絵だけでは役に立たない


エバンスは、この点も、一貫している。

大きな戦略的な設計であっても、それは実際のコード「動くソフトウェア」と密接に関係づけなければ、意味がない。

上流専門のコンサルタントが残す、きれいだけど実際は役に立たない絵を描いてもだめ。

モデリング、設計の意思決定は、必ず「実装」して「コード」として表現すべきだし、動くソフトウェアこそ、設計のよしあしを教えてくれる道しるべ。

第IV部は、「大きく」「複雑」な問題がテーマだけど、設計の考え方や、パターンは、こういう「コードで動かす」哲学を貫いている。

私が、ドメイン駆動設計を重視する大きな理由が、この「実際に動くコード」を大切にするエバンスの発想・考えかたに強く、共感しているから。
モデリングは、コードに直接、結び付くものだし、そうじゃなきゃいけない。

開発の主役は技術者


「現場主義」も DDD の特徴のひとつ。
現場の開発者にとって、わかりやすいこと、やりやすいことに、とても価値を置いている。

もちろん、利用者やプロジェクトのオーナーの期待にこたえるソフトウェアを造ることが一番たいせつな目的。だからこそ、ドメインを理解する「ドメイン駆動設計」なんですね。

それと同時に、「ドメイン駆動設計」は、開発者にとって、

・わかりやすいコード
・扱いやすいコード
・取り組みやすいやり方

にも、大きな価値があることに、強い信念を持っている。

ドメインも実装技術も、両方を大切にする。両方の専門家が集まって、同じ言葉(ユビキタス言語)を使いながらいっしょに活動することで、大きな相乗効果が生まれる。

これが「ドメイン駆動設計」に一貫して流れるエバンスの考え方ですね。

ほんとうに共感します。

継続的に発展させていく


全体像を分析して、最初に大きな構造設計をしちゃって、その構造を固定する。
この up-front (前払い) 方式が、うまくいかないのは、現場でだれもが経験しているはず。

実際にやってみてわかること。新たにわかったことをベースに意思決定すべきテーマが多いこと。
大きな問題とか、システム間連携も、継続的に、段階的に、改良し発展させていくことが大切、という価値観ですね。

「大きな設計」も、足元の現実的で実践的な取り組みから始めて、「継続的に改良・発展」させていくべし、という価値観・信念が一貫している。

第IV部のキーワード


第IV部の三つのキーワード。

・文脈(Context)
・蒸留(Distillation)
・構造(Large-Scale Structure)

文脈(Context)


第14章は、広い開発範囲や、関連システムとの連携で、「大きなモデルの整合性、一貫性を維持する」ための考え方とやり方を書いている。

そのキーワードが「文脈(Context)」。

はっきりいって、わかりにくい言葉。
DDD を最初に読んだときは、ぜんぜんぴんとこなかった。

一方、この章の、サブシステム同士や、システム間の連携のやり方の7つのパターンは、具体的で、とても面白かった。

私が、DDDを「こりゃ面白い、使える」と最初に思ったのは、このシステム間連携の7つのパターンを読んだとき。(そういう課題にちょうど取り組んでいた)

一体化した統合システムとか、標準プロトコル、みたいなきれいな絵もあるけど、エバンスは「実践的には」それが、唯一の解ではないし、最善でもない、という論点。

"Separate Way(別の道)"パターンの説明には、はっとさせられた。
「ほんとうに統合や連携に取り組むことが正解か?」という問いを真正面から、発している。「統合」とか「標準インタフェース」とかは、エレガントな解に見えるけど、デメリットや実現課題も多い。

・「別の道」が、最善という場合も、多いんじゃないの?
・少なくとも、選択肢の一つとして、真剣に検討すべき。

実際に、連携課題を見直して、当面「別の道」を選択して、プロジェクトの状況改善に役に立ったことが何回かあります。

問題の先送り、というよりは、「本来のアプローチ」ではない、という判断ができたから。

そもそも、連携相手のシステムが、ドメインの構造を完全に間違えて実装している。ゆがみきったモデルに合わせるための開発作業は、あまりにも、後ろ向き。費用対効果が悪すぎる。

今、作っているシステムは、ドメインのモデルをうまく表現できるようになってきているので、こちらを完成させて、こちらを拡張していくほうが、費用も少なく、期間を短くできそうなことを、ほぼ確信できたから。

蒸留(distillation)


この15章は、「選択」と「集中」のやり方ですね。

中でも「コアドメイン」パターンは、ほんとうに目からうろこでした。

この本を最初に読んだのは、破綻したプロジェクトの建て直しの現場責任者として格闘していたとき。

・問題点をあげたらきりがない
・やるべきことが山ほどある
・もちろん、人手も時間も足りない
...

このときに「ドメインの中核」を見つけ、そこに資源を集中することを決意したのは、このDDDの15章、特に "core domain" パターンが大きく影響している。

きれいな総論としての「選択と集中」ではない。
もっと、泥臭い、開発の現場の実情を踏まえたエバンスの説明が、新鮮だったし、すっと体に入ってきた。

もちろん「コアドメインに集中する」と決めたからといって、すべてが一挙に解決したわけではない。

でも、そういう、しっかりした軸を持てたことは本当に大きかった。
私自身、いろいろ利害関係者、そして何よりも、現場で戦ってくれている、仲間たちが、進むべき方向を共有できたことで、明らかにプロジェクトの状況が改善した。

構造(Large-Scale Structure)


16章は、大きなドメインモデルの構造設計の話。

単純にいえば、ドメインモデルの内部も「レイヤーアーキテクチャ」が有効だよ、ということ。

いろいろなドメインオブジェクトを複数のレイヤに分けて、

・役割や意図を明確にする
・できるだけレイヤ間を疎結合にする

こうすることで、モデルがわかりやすく、扱いやすくなるよ、という話。

ファウラーの「アナリシスパターン」や Hruby の「ビジネスパターン」にもでてくる「全体の構造」をわかりやすくする時の、基本パターンですね。

ドメインオブジェクトのレイヤ構造の考え方は、小さなモデルでも重要だし効果的だと思っている。

ここらへんは、別の記事で、具体的に取り上げようと思っている。

来年はどんな年になるのかな?


来年もしばらくは、頭の整理や充電にあてる時間がとれそう。いいんだか、わるいんだか。

ここにきて、いくつかのクライアントに出向いて、現場で、基本的な設計や、プロジェクトの進め方をアドバイスすることが続いた。
格安というか、ほとんど無償のコンサルティングですね。

いままでとは違った会社やドメインに接することは、発見や刺激があって面白いことは面白い。
スポットで、少ない情報を元に、出たとこ勝負のアドバイスも、ある意味、腕の見せ所だとは思っている。

そうはいっても、気の利いた、気心の知れたメンバーで、小さなチームを組んで、じっくりと、ひとつのシステムを仕上げることに専念したい気持ちも、もちろんある。

あるいは、未知のメンバーと、新チーム結成、とかも、刺激がありそうだなあ。
隔週で、ドメイン駆動設計の勉強会を開いて、このブログに、まじめにいろいろ書くようになった。
その中で、知り合った人たちとの交流は、ほんとうにいろいろな発見と刺激があった。
勉強会は来年もぜひ続けようと思う。
ブログも状況が許す限り、がんばってみよう。

来年は、仕事のほうは、どうなるのかな。

そういえば、ここ数年、営業して仕事をとったことがないなあ。

基本、

・来るもの拒まず
・なんでもご相談に応じます

てな感じで、なんとかやってこれた。

来年もこんな調子で、いつものごとく、ある日、突然、火を吹いたプロジェクトとか、短期決戦の案件が飛び込んできて、「なんとかしてくれ」「なんとかしましょう」モードになっちゃいそうな気もする。

「ドメイン駆動設計」にこだわるようになってから、どんな案件、相談も、なんか、同じ考え方、やり方で、それなりに、いけそうな気がしている。

「ドメイン駆動設計」が、未経験な領域とかでも通用するのか、効果があるのか、新しい案件で、トライアルしてみたい、というのが今の素直な気持ちかな。

それでお金がついてくれば、いうことないけど、まあ、今までと同じように、割りの合わない仕事を、「面白そう」と言うだけで、やっちゃうんだろうなあ。

今の私に必要なのは、気の利いた技術者仲間ではなく、そろばん勘定がしっかりした番頭さんなのかな。
でも、やっぱり、設計をみんなでわいわい、がやがや、やるのが、一番ですけどね。

ドメイン駆動設計は、III部から始めるのが良いかも

ここしばらく Domain-Driven Design(DDD) の III部 "Refactoring Toward Deeper Insight" を読み直しながら、自分の頭の中の整理のためにも、いろいろ書いてきた。

現場で、DDD を始めるには、このIII部から、はじめるのがいいんじゃないかと思うようになった。

コードレベルで実践できる


"Toward Deeper Insight" とはなっているけど、III部のテーマは、まぎれもなく「リファクタリング」。

実際のコードを、どうやって改善するか、という技術者にとっては、具体的で、わかりやすいテーマ。

エバンスは、

・リファクタリングにも、いろいろレベルがあるよ
・ファウラーの「リファクタリング」はマイクロ・リファクタリング
・「ドメイン駆動設計」では「ドメインモデルの改善」という視点を追加する

というようなことを書いている。

出発点は、マイクロ・リファクタリング。
これは「ドメインの知識を掘り下げる」ことに、関心がない開発者でも、興味をもって取り組めるテーマ。

短時間の、ちょっとした作業で、コードが、わかりやすく、きれいになることを実感できるネタがいっぱいころがっている。

技術者とって、とっつきやすい。

「ユビキタス言語」とか「モデル駆動設計」とかのドメイン駆動設計の根本の理念(こだわり)とは、だいぶはずれる。

でも、現場でスタートするには、現実のコードを、ちょっと改良する、マイクロリファクタリングから始めるのが、実践的で効果的だと思う。

Value Objects パターンから


コードの部分的な改良を、ばらばらにやっていても、ドメイン駆動設計、というか、オブジェクトの設計能力が向上するには時間がかかりそう。

もうちょっと、ターゲットを絞って実践するのが良いと思う。

具体的には「Value Object」。

ちょっとしたデータとロジックをカプセル化した、小型の不変(immutable)オブジェクト。

マイクロリファクタリングの技法やサンプルを使いながら、Value Object の設計・実装を実践すると、だいぶ、設計能力が向上できそう。

ターゲットは、

・String のインスタンス変数の文字列操作をする箇所
・int, BigDecimal とかで計算処理する箇所
・Date, Calender とかで、日付計算する箇所
・Collection を使って集合操作や for 文の処理をしている箇所

などが、切り出しやすく、分かりやすいと思う。

依存性の少ない「 Standalone Class 」にするためにも、Java の基本API だけに依存する部分をターゲットにするのが良い。

名前にこだわる


Value Object の設計・実装は、リファクタリングの技法を使いながら、技術の視点・発想で進めることができる。

これだけでも、だいぶ、開発者の設計能力が洗練されてくると思う。

でも、「ドメイン駆動設計」へのアプローチとして考えると、まだ足りない。

そこをカバーするために、 Value Object の設計にあたって、

・クラス名
・メソッド名
・変数名

に、こだわって「レビュー」する。

ここで、「業務の概念(用語)」をコードで表現するという、発想を持つことを、チームの成長のテーマとして取り組む。

「自分だけ」で名前を決めるのではなく、利害関係者、可能であれば、ドメインの専門家かそれの代理役の視点で、「名前をレビュー」することを、意図的に仕掛けるのが良い。

ここで、業務の用語にこだわることを、チームの文化にしていく。
ドメイン駆動設計の「ユビキタス言語」の実践の土壌ができるわけだ。

DDD の「ユビキタス言語」パターンを、読んだからといって、個々の開発者が「そうか、これだ」と思うことは、あまり期待できない。概念的で漠然としすぎている。実感がわかない。

それより、実際にコードを書きながら、今、格闘しているクラス、メソッド、変数の「名前にこだわる」という実践を、ペアとかチームでやれば、もっと、具体的に、「ユビキタス言語」への芽生えが生まれる。

実際にやってみると、「業務の用語」への発想の転換は、やはりたいへん。
もともと見てきたコードがそうなっていないだから、まあ、当然といえば当然。

でも、現場で地道に継続すれば、確実にこの発想の転換は進む。
最初は、一人くらいが、ちょっと目覚めかかる。
そのうち、ペアの相方と、そういう指摘がではじめる。

まあ、私の場合は、ほんとうにジュニアの開発者たちに、コード書きのイロハから教えたようなところがあって、現場でチームの文化として「業務の用語」にこだわる感覚がでてくるまでには、3年くらいかかったような気がする。

もちろん、今でも、現在進行形です。
昔に比べれば、より高度なテーマが増えてきた。
でも、やっぱり「業務の用語」じゃない「テクニカル」な名前、「処理手順」や「技術手段」を意味する名前が、いつのまにか、「ドメイン層」にもまぎれこんでくる。

こういうことを、日々発見し、改善を続けることが「ユビキタス言語」パターンの実践だし、「Isolating Domain 」の実践なんでしょうね。

( Isolationg Domain も、現在進行形ですね )

Value Object が揃ってくれば


名前がだいぶ「業務の用語」らしく見える、小型で不変の Value Ojbect がドメインモデルの部品として揃ってくると、モデリングと設計に、目に見える変化がでてくる。

「考えるレイヤ」が、一つ上になる、感じ。

Java の基本API の発想とか、UI や DB アクセスの発想が、出てこない「オブジェクト」のモデリングや設計が始まる。

一斉に、全面的に、というほど、劇的に変化するわけではないけど、「ドメインだけで考え、話す」時間が増えることは、明らかに実感できる。

朝から晩まで、ドメインモデルだけ、というのは不健全。実際にそういうこともあったけど、「一日一回はコードを書け」運動で、バランスを取るようにしている。

重要なのは、

・ドメイン駆動設計モード
・テクニカルモード

を意識して、使い分けたり、切り替えられるようになることだと思います。

最初は、テクニカルモードだけのチームでも、そのモードの一部である、マイクロリファクタリングや Value Object の設計・実装をしながら、「業務の用語」にこだわる「ドメイン駆動設計モード」を体験するようにする。

こういう体験を通して、2つのモードをバランスよく身につけ、モードを臨機応変に、実践的に使い分ける能力が、個人としても、チームとしても、身についてくる。

ドメインを深く理解するためのリファクタリング

Domain-Driven Design(DDD)の III部は、「ドメイン駆動設計」のリファクタリングがテーマ。
開発者が、問題領域をより深く理解し、それを、より正しく、コードで表現するための、

・考え方
・やり方

を「リファクタリング」というキーワードで、いろいろなパターンや例を8章から12章までの5つの章にわたって説明している。

III部の最後の章、13章は "Refactoring Toward Deeper Insight" 。これは、III部のタイトルをそのまま使っている。III部を総まとめした内容。

ドメイン駆動設計のリファクタリング


ドメインを深く理解するためのモデルとコードのリファクタリングは「伝統的なテクニカルなリファクタリング」の考え方、やり方に、次の三つのポイントを重ね合わせたもの。

(1)「ドメイン層」の活動である
(2)(従来のリファクタリングとは)異なる点にも注目する
(3)ドメインに精通した人との絶え間のない対話を続ける(開発チーム内部に閉じない)

基本の考え方、やり方は、従来の「リファクタリング」がベースだけど、「ドメイン駆動設計」という視点・価値観をきちんと持ってとりくもう、ということですね。

リファクタリングのきっかけ


ドメイン駆動設計で、リファクタリングすべききっかけは、多岐にわたる。

ぎこちないコード


「従来のリファクタリング」のきっかけは「コードのいやな臭い」ですね。

これは、ドメイン駆動設計のリファクタリングでもいっしょです。

・コードがぎこちない
・コードがわかりにくい
・コードの変更がたいへん

こういうのは、もちろん、リファクタリングすべき明らかなサイン。

あと、ドメイン駆動設計は「モデル駆動」なので、コードがぎこちないだけではなく、モデルがぎこちないことを、開発者が感じる機会が多い。「ぎこちないモデル」「わかりにくいモデル」も重要なリファクタリングのサイン。

モデルのぎこちなさは、おそらく、重要な概念(ドメインクラス)が抜けているとか、ドメインオブジェクト間の関係になにか、致命的な間違いがある証拠。

コードは整然としている。でも...


コードがすっきりと整然としていても、ドメイン駆動設計としては、リファクタリングすべき兆候がある。

・ドメインの専門家の言葉とギャップがある
・新しい要件が、すんなりと、既存のモデル・コードに、置き場所が見つからない

開発者が、コードがきれいになったと感じていても、こういう「ギャップ」や「違和感」を発見したら、それは、はっきりした「リファクタリング開始」のサイン。

きっかけを見つけるのが、いちばんたいへん


こういうリファクタリングのきっかけを見つけることが、もっとも難しい。
でも、きっかけが見つかりさえすれば、ドメインに深い理解(deeper insight)に向かって、いろいろなやり方がある。

探検チーム


リファクタリングのサインが、問題も解決方向も明らかで、2,3時間で決着がつくような場合は、通常のリファクタリング作業をすれば良い。

もうちょっと問題が手ごわそうなとき。

エバンスのお薦めは、一時的な「探検チーム」を結成して、取り組むこと。

メンバーのピックアップ


直接担当している開発者以外に、そのドメインに詳しい開発者やモデリングスキルが高いメンバーをテンポラリに召集する。

問題領域の微妙な概念の問題が潜んでいる、と判断できる場合は、ドメインの専門家にも参加してもらう。

取り組み方


30分から長くても90分程度のブレストを実施。
場所は、カフェとか別の場所も良い。道具は、手書きのUMLがあれば十分。

ブレストやって、アイデアは固まってきたが、すっきりしなかったら、一旦寝かせる。
数日、置いてから、再検討すると、良い結果がでることも多い。

問題解決の切り口が見つからなかったら、問題を狭めてみる。
全てのケースではなく、特定のケースだけで議論するとか、問題をややこしくしている部分だけ、とりあえず切り離してみる。

異なる視点からの参加


他のチームのメンバーが参加することは「ユビキタス言語」を進化させる、良い機会になる。
同じ関係者だけだと行き詰まっている問題も、外部の人間が参加することで、新しい視点で解決の糸口が発見できることも多い。

私は、可能であれば、そのドメインの経験者よりも、「モデリング」とか「設計」の能力が高い人を、参加させたいと思う。

「モデリング」や「設計」能力が高い人は、まったく、未知のドメインであっても、よいアドバイスや発見をしてくれることが多い。

モデルや設計のぎこちなさは、ドメインの具体的な知識がなくても、発見可能。
そして「モデリング」や「設計」に優れた人は、解決策のいろいろな引き出しを持っているし、その問題で使えそうなネタも、直感的によいモノを選び出してくれる。

もし、そのネタが、結果として、現在の問題に適切ではなくても、別の視点からの提案は、良い解決策発見の効果的な「触媒」になることが多い。

そういうレベルの技術者を、定常的にチームに抱えることは難しくても、30分から90分程度のワークセッションに参加してもらうだけなら、いろいろやり方がありそうです。

Prior Art ( 既存の作品 ) の活用


そのドメインの問題を、整理したり、解説したりした既存の「作品(Art)」を利用するのが、良い解決策になることも多い。

(ソフトウェアではなく)その問題領域そのものの、入門書や解説書。
例えば、会計の知識は、その分野の、良い書籍を手に入れるのが一番の近道。
それをやらずに、業務の専門家との対話だけで、理解しようとするのは、あまりにも非効率。

その分野に関連したパッケージソフトや、ASPなどが参考になることも多い。
実際に触れなくても、パンフレットの機能体系とか、ソフトウェアの概要説明とか、ヒントはいろいろ手に入る。

分析パターン本やデザインパターン本ももちろん、利用価値はある。

いずれも、ただ漠然と読むのは、たいへんだし、面白くないけど、「リファクタリングのきっかけ」が見つかって、特定の具体的な問題の解決のヒントを探す、という文脈で読むと、良い発見ができるものです。

開発者のための設計もたいせつ


DDD 10章の "Supple Design(しなやかな設計)" のテーマですね。

ソフトウェアはもちろん、利用者に価値を提供すべきもの。
同時に、開発者にとっても、良い設計が大切。

分かりやすいコード、変更しやすいコードにこだわること、特に、依存性を減らし、副作用を減らす設計に改善するためのリファクリングが重要。

「ドメインの深い理解」を目指したリファクタリングが、結果として、「しなやかな設計」を導く。
逆に、「しなやかな設計」が「ドメインの深い理解」を促進する。

「ドメインの深い理解」と「しなやかな設計」は、双方向の相乗効果をもたらす。

これが、ドメイン駆動設計、特に、10章の "Supple Design" のメインテーマですね。

リファクタリングをいつやるか?


多くの開発プロジェクトでは、既存のコードの変更となる「リファクタリング」は

・変えることによるリスク
・変えることに必要なコスト

を考えれば、躊躇するしかない。

たとえ、開発者として、

・まちがったモデルを抱え続ける危険
・その場しのぎのコードの追加の危険

を十分に認識していても、実際のプロジェクトで、リファクタリング実施を正当化し、承認を得るのがむずかしい状況がほとんどでしょう。

リファクタリングの活動は、押さえ込まれるか、あるいは、隠れて非公式に実施するという、きわめて、不健全な状況になりがち。

勇気をもって、取り組むべきとき


そういう状況の中でも、次のような場合は、勇気をもって、なんとか、調整して、リファクタリングに公式に取り組むべき。

・チームの現在のドメインの理解と既存のモデルが一致しなくなったことが明らか
・隠れていた概念を、発見して、その概念を明示できるオブジェクトや関係を発見した
・中核のロジックで硬直したしまった部分を、Value Object など証明済みの技法で「しなやかに」変えることが確実にできるとき

どの場合も「問題点」と「解決策」が具体的であることが特徴。
こういう場合であれば、関係者と問題を共有して、解決することのメリットを共有できる可能性が大きくなる。

いつでも、なんでもリファクタリングはダメ


開発者が、感覚でわかっていても、うまくそれを利害関係者に伝えられないときは、現実的には、リファクタリングに踏み切るべきではない。

実際のプロジェクトでは、「リファクタリング」の名前を使って「どんな変更」を「いつでも」やるべきではない。

たとえば、

・リリース前日のリファクタリング
・「テクニカルには優れた技巧」だけど、ドメインモデルの表現に新しい価値をもたらさない
・ドメインの専門家がぴんとこない「深い」「エレガント」なモデル
...

こういうことはやるべきではない。

むずかしいけど...


結局「リファクタリングの実施のタイミング」も、「初心者向けの単純ルール」「唯一の正解」なんてない世界。

「リファクタリングをする」あるいは「リファクタリングをしない」を、絶対的にルールにしてはいけない。

かといって、リファクタリングの実施について葛藤しなくて良いレベルに「安住」してはいけない。

リファクタリングのきっかけを見つけ、かつ、実施すべき条件が揃っていれば、多少の困難を乗り越えて、関係者の了解の元での「リファクタリング」をする姿勢は、常に持ち続けるべき。

「良い機会」より「危機的状況」に見える


8章の「ブレークスルー」でエバンスが書いているように、地道な小さな基本のリファクタリング、設計の改良を続けていると、大きな変化の波が突然やってくる。

大きな変化は、不連続かつ予測不能のタイミングで起きる。

このブレークスルーの始まりは、「設計改善の機会」というより「プロジェクトの危機」として見えることのほうが多い。

開発チームのドメインの理解のレベルが新しい段階に到達した。
そうすると、浅い理解で取り組んでいた既存のモデルやコードが、貧弱でなさけないものに見えてします。

昨日までは、それなりにちゃんとした進捗で、成果を出していると思っていた開発プロジェクトなのに、進化した今日の視点だと「ろくでもないガラクタ」があちこちにあるように見えてしまう。

その時どうする?


エバンスは、その時、どうする、ということは書いていませんね。
モデルと設計を、着実に洗練できる新たな活動のスタート、という前向きな表現で、III部を締めくくっている。

たしかに、その通り。でも、現実のプロジェクトで、それは「危機的な状況に見える」といっているのに、これは、あまりにも能天気。

開発プロジェクトの現場をよく知っていて、かつ、現実的な判断を重視するエバンスとしては、さすがに、安直な「こうやればみんなハッピー」みたいなことは、書く気になれなかったのかな?

この「危機的状況」での判断と行動は、プロジェクトの大きな分岐点。

・わかっているが、リスクを考え、大規模なリファクタリングは避ける
・周到に準備、検討をして、「深い理解」にもとづいたソフトウェアに発展させる
・ある部分にフォーカスして実施。ある部分は放置。
...

単純な正解なんてあるわけありませんよね。

開発の責任者の判断力や指導力・調整力にゆだねる部分も大きい。

開発チームや利害関係者が共有している「マインド」が、決定要因かもしれない。

ビジネス面(サービスの開始時期とか、受託開発の契約とか)の制約条件がすべてを決めてしまうかもしれない。

私自身は、マインドは「思い切ってチャレンジ」をいつも第一の選択肢にしている。
そして、そのチャレンジができるように、チーム全体の設計改善のやる気や能力の開発とか、余裕日程の確保とかを、地道に仕込むことをこころがけている。

実際は、第一の選択肢ですんなり行動できることは少ない。
でも、マインドはいつも「良いモデルにブレークスルーできたら、ドメインをさらに深くできたら、コード改変に思い切ってチャレンジ」を持ち続けたいと思っている。

実際のプロジェクトで、「なんどやっても、そうはいかない」という経験を繰り返しても「でも今度こそは」という姿勢でやっている。その思いを持ち続けるほうが、私の性分として、自分の力が湧いてくるんですよね。

もとバランスの取れた判断すべきなら、私より、もっとうまくやってくれる人がたくさんいますから。

まあ、問題は、私のやり方が、開発メンバーにとって、ハッピーかどうかが、かなり怪しいことかな?

ドメイン駆動設計と「デザインパターン」の関係

GoFの「デザインパターン」は、ドメイン駆動設計と、どう関係するか?

これが、Domain-Driven Design(DDD)の 12章 "Relating Design Patterns to the Model" のテーマですね。

読み替えが必要


エバンスは、

・「デザインパターン」は、ドメインモデリングにも参考になる
・しかし、利用にあたっては、「別の考え方」をする必要がある

と言っている。

GoFの「デザインパターン」は、汎用的だけど、「テクニカル」な実装の問題の解決に重点がある。
原典が、元々、そういう視点。そして、解説本やサンプルになると、さらに「実装技術」に偏った内容が多くなる。

ドメイン層のモデリング、設計にも利用は可能だけど、「テクニカル」な側面、「実装」内部の問題は、切り離して、「概念」レベルのパターンとして利用すべき。

ドメイン層の表現手段として役に立つことはある。
それと、「デザインパターン」そのままに設計・実装するかは、別の問題。

こういう内容を、

・Strategy パターン
・Composite パターン
・Flyweight パターン

を例に説明している。

Strategy パターン


適切な「輸送ルート」を見つける「ロジック」を例に、説明している。

「輸送ルート」は、「時間が最短」で見つける方法と、「費用が最小」で見つける方法がある。
「乗換案内」とかもそうですね。

複数の「ルート」案を比較するロジックとして「時間で計算」と「費用で計算」という二つの方法がある。

これは、概念的には、 Strategy パターンの適用分野。

GoF「デザインパターン」では、Strategy パターンは、動的に、ロジックを入れ替えることを重視した説明になっている。

エバンスは、そういう側面より、「複数のロジックを別のオブジェクトに分けて表現」するとわかりやすくなる、という点を重視している。

実際、モデル図でも、本来の Strategy パターンとは、違う使い方をしている。

元々のパターンでは、 Context オブジェクトが、Strategy への参照を保持する構造。

エバンスの例では、「ルートを見つける」メソッドへのパラメータとして、Stragegy オブジェクトを使うだけ。「参照」ではなく「利用」という関係に変えている。

このほうが、モデルも実装も単純で、少なくともサンプルの「適切な輸送ルート」という問題では、このほうが、わかりやすい。

また「動的」な追加みたいなことは、重視していない。
業務ルールはほぼ固定だけど、「複数の計算方法がある」ことを、明示する手段として Strategy パターンを参考にしてみた、という感じですね。

別に Strategy パターンでなくても良くて、ファウラーの「リファクタリング」9章「条件記述の単純化」のやり方で、うまく表現できれば、それでも良い。

Composite パターン


ビジネス領域でも、Composite パターンが適用できそうな課題はいくつかある。
DDD の例では、「輸送ルート」全体は、個々の「輸送ルート」の合成、という例であげている。

つまり「全体」も「部分」も「輸送ルート」として扱える、ということ。

製造業の部品表(BOM) とか、組織構造とかも、「部品」が集まって「部品」、「組織単位」が集まって「組織単位」という構造になっている。 Composite パターンが利用できる「可能性」がある。

でも、エバンスは、

・ほんとうに、どこをとっても「全体」と「部分」は同じインタフェースで扱えるのか?
・無限に広がるネスティングが、ほんとうに必要か?

をちゃんと検討すべきだといっている。

Composite パターンは、とても汎用的だから、ある意味、なんでも表現できちゃう。

でも、Composite パターンで表現することが、今の問題領域(ドメイン)の構造を、適切にわかりやすく表現する手段なのか、ちゃんと検討したほうが良い。

DDD の12章の例でも、「全体ルート」とそれぞれの「部分ルート」は、全て同じインタフェースで扱うという、Composite パターンよりも、

・倉庫からの出荷
・アメリカ国内輸送
・外洋の航海(サンフランシスコから横浜とかね)
・日本国内輸送
・届先への配達

というように、「役割」が異なった部品に分解するモデリングを説明している。

ニュアンスとしては、Composite パターンの利用には消極的ですね。

自己参照テーブル


Composite パターンを、テーブルで表現すると方法として、自己参照テーブルがある。

Oracle のサンプルテーブルの EMP テーブルが、このパターンの例ですね。

従業員の上司は別の従業員という構造を、ひとつの EMP(従業員)テーブルで、表現している。

従業員レコードが、別の従業員レコードを参照するので、「自己参照」テーブルという。

「自己参照テーブル」は、とても汎用的で、利用可能な範囲は広い。

でも、ある特定の問題領域のソリューションとしては、「汎用的」すぎるケースがほとんど。

Compoiste パターン、自己参照テーブルは、「無限」のネスティングができる設計パターン。

でも、それが「ドメイン」の構造の、もっとも適切な表現がどうかは疑問。
おそらく、階層数を限定したり、階層ごとに別の振舞を持ったり、もっと特殊化した構造のほうが、個別の問題領域では適切なモデルになると思う。

DDD の Specifications パターンは、Composite パターンの実装例がでているけど、個人的には、制限があっても、もうちょっとシンプルな実現方法のほうが、良いと思っています。

Flyweight パターン


Value Object の生成には、Flywieght パターンが使えるかもしれない。
でも、これは、「実装」とか「性能」の扱いの問題で、「ドメインの概念」ではない。

エバンスは、 Flyweight パターンを、「ドメイン層のモデル」の参考にはならない、「デザインパターン」のわかりやすい例だといっている。

Flyweight パターンの考え方が、ドメインモデルの参考になるシーンは、私もぱっとは思いつかない。

「デザインパターン」は「ドメインのパターン」ではない


ようするに、GoFの「デザインパターン」は、「ドメインのパターン」そのものではない、ということ。

「デザインパターン」の解説やサンプルは、どうしても「テクニカル」な側面に寄ったものが多い。

「ドメインの概念」のモデリング・設計の参考になるものもあるけど、そうでもないもの多い。
概念(考え方)を参考にした場合も、「実装」を「デザインパターン」と同じにする必然性はない。

ドメイン駆動設計に「デザインパターン」を参考にすることは、エバンスの書き方は、否定的ではないけど、「消極的」な印象です。

私も、「分析パターン」はしょっちゅう参考にしているけど、「デザインパターン」をドメイン層のモデリング・設計の参考にしたことは、ほとんど記憶にない。

自分でフレームワークぽいものを書いていたときは、デザインパターンはいろいろ参考にしていた。
最近は、ドメイン層以外は、既存のフレームワークを使っちゃう。
あるいは、ドメイン層以外の問題で、独自に書く部分は、若手の技術指向バリバリの連中が書いた部品を使うだけなんで、デザインパターンとは、疎遠になっている。

たまには、テクニカルな課題にフォーカスして、性能とことん追求で、コードを書いてみたいとか思いますけど、私自身が、実プロジェクトで、それをやることは、もうないんだろうなあ。

分析パターン : これだけは覚えておこう

DDD 11章 Applying Analysis Patterns (分析パターンの応用)では、例として、ファウラーのアナリシスパターンの6章「在庫管理と会計」をヒントに、モデルを改良する話しが載っている。

エンタープライズアプリケーションでは、「在庫管理(企業資産の管理)」は、いつも重要な関心事だし、事実を記録するときに「会計」の考え方とやり方は、基本中の基本。

でも、正直言って、ソフトウェア技術者がファウラーの「アナリシスパターン」の6章を読んで、「なるほどそうか」と、ピンとくるとは思えません。

もうちょっと、単純な原則があると思っている。

私が、自分で考えるときとか、若手の技術者に説明するときに、よく使っている、単純な分析パターンを4つ紹介したいと思います。

・記録は不変
・予実の管理
・連絡
・情報の集約

この4つをちゃんとやってくれるソフトウェアは、利用者にとって、役に立つし、ありがたいソフトウェアになる(はず)。

仕事仲間や、仕事の相手が

・きちんと「記録」して
・「予実管理」がしっかりしていて
・「連絡」がゆきとどいて
・要点をうまくまとめた資料を作ってくる

そういう人だと、すばらしいですよね。
ビジネスシーンで「役にたつソフトウェア」というのは、こういうビジネス活動の基本を、代理で自動的にやってくれたり、面倒なところをうまくサポートしてくれるソフトウエアなんです。

この4つのパターンは、ビジネス活動というドメイン(問題領域)の、基本事項を抜き出したもの。

記録は不変( immutable )パターン


エンタープライズアプリケーション基本の関心事は、「起こったこと(イベント)」を正確に記録すること。

「受注」「出荷」「入庫」「請求」「入金」「支払」...

分析パターンの言葉だと「イベント」とか「トランザクション」ですね。

二つの日時で記録


イベントは、「いつ(When)」を記録することが必須。

しかも、

・いつ発生したか?
・いつ記録したか?

が異なる場合も多い。
両方を記録するのが基本。

「誰が」と「何を」


「誰が」を明らかにするために Agent ( 組織、個人 ) への参照を持つ。
「何を」を明らかにするために、 Resource ( 商品、サービス、場所、道具、... ) への参照を持つ。

「イベント」オブジェクトは「関連」を表すオブジェクトです。

「顧客」と「商品」の関連として「注文」イベントが起きる。

「記録は不変( immutable )」パターン


そして、ビジネスのイベント記録の原則は、不変 ( immutable ) です。

一度記録したら、その記録を「削除」したり「変更」することを禁止する。

データベースで言えば、insert 文はOKだけど、update 文、 delete 文は ダメ、ということ。

insert だけで「削除」を表現するには、

・「取消」レコードを insert

する。「取消」レコードには、「元」レコードの参照番号が入っている。

「変更」は、

・「取消」レコードを insert
・「変更後」レコードを insert

する。

紙の伝票で「赤黒処理」と呼んでいるやり方ですね。

ソフトウェアの世界だと、Value Object が、immutable(不変)型ですね。
元のオブジェクトは変更せず、新しいオブジェクトを作ることだけを許すわけです。

締め切り前の修正


実際の業務では、ありとあらゆる修正を、すべて「不変(immutable)」で処理するわけではありません。

「確定」前であれば、上書き修正したり、物理的に廃棄(削除)できるのが、普通です。
単純な入力ミスは、必ず起きるので、「確定前」のデータは、簡単に修正・削除できるようにする。

問題は、何をもって「確定」とするかですね。いわゆる「締め」の問題。

・日単位の締め ( 例えば、 17:00 締め切り )
・月単位の締め ( いわゆる、「締め日」 )
・プロセスの手順単位の締め ( 受付完了後はだめ、承認後はだめ、とか)

「記録は不変」の原則は、より実践的には

・「確定前の修正の許容」
・「確定後の修正の禁止」

をきちんと分けて実現する。

こういう「起こったことを正確に記録」することが、エンタープライズアプリケーションの中核の機能になる。

「記録は不変」パターンは、会計システムや基幹システムだけでなく、「会議室の予約」とか、「レビューの記録」とか、いろいろな問題領域で、いつも考慮すべき、課題です。

ここがしっかりしたシステムは安心して使える。

安易にデータを update するシステムは、怪しい。
論理削除フラグを update するのも、 update なので、やっぱり怪しい。

こういう怪しいシステムを作ると、利用者側は、敏感に気がつく。そして、不安になって、

・紙ベースとか、別の方法でも記録する二重作業を続ける
・入力ボタンを押す前に、画面の前で、何度も確認をする。
...

こういう利用者の姿が日常的なら、そのシステムは「ろくでもない」のは明らか。
利用者は、システムを利用するために、かえって仕事が増えている。

「予実の管理」パターン


昔のエンタープライズアプリケーションの関心事は、起こった事実、「過去の記録」だけでした。

例えば、銀行だと、

・口座に入金があった
・口座から出金した

という「過去」を正確に記録することが、最重要の問題。

「過去の記録」指向のシステムは、ある意味、今では、システム化はおわっちゃってる。
今は、「予定」という「未来」のイベントを管理することに、重点が移っている。

先を読むためのシステム


在庫管理だと、昔は「入庫した」「出庫した」の記録だけ、というシステムでもよかった。

今は、「引き当て(出庫の予定)」と「入庫予定」をあわせて管理して、

・(現物はないけど)出荷可能
・品切れを「予測」して、必要量を発注
...

というような、「先を読んだ」アクションをするためのシステムが求められている。

・「予約」した
・「約束」した
・「予定」した
...

という「未来」についての情報を記録して管理できるのが、役に立つシステムになる。

実績で消しこんで、to-do を管理


予定の記録だけでは、実際には役に立たない。

「予定」したが、まだ「未処理」。これを知ることが、たいせつ。

ソフトウェア開発だと、「チケット(やるべきこと)」を発行して、作業が完了したら「クローズ」する。
この方法で、まだ未完了の「to-do」を管理する。

・「予定(やるべきこと)」を記録
・終わったら、「完了」を記録
・(差分の)「未処理」を管理

これが、「予実管理」パターンです。

・○○予約
・アクションアイテム管理
・to-do リスト
・未処理リスト
...

こういう「やるべきこと」情報を、適切に扱うのが、「予実管理」パターン。

「予定」と「実績」から、「未処理」を導出する。

「予定」の記録も不変( immutable )にする


予定なので、予定の変更とか、予定の取消とかは、当たり前の世界です。

でも、原則は、「不変」にすること。

「予定」データを物理的に上書き変更するのではなく、一度、作成した「予定」は、事実として記録しておく。
キャンセルとかも、「予定」した事実と、「キャンセル」した事実として記録する。

そうすると、「予定の変更」履歴が残る。
この情報は、業務の効率化とか、予定変更の傾向を分析して、今後の予測を支援するようなアプリケーションとか、より高度なソフトウェアに進化する可能性がでてくる。

物理削除や全面上書きのほうが、合理的なシーンもある。
でも、ソフトウェア技術者が考えるより、はるかに多くケースで「記録は不変」「予定の記録も不変」の原則が正しい。

ソースのバージョン管理システムも、「概念的」には、過去のすべてのバージョンを、そのまま保管していますよね。

「連絡」パターン


ビジネスでは、「連絡」しあうことが大切。「記録」と「連絡」が2大関心事。

イベント発生を「記録」するときに、あわせて、「通知」が必要なのではないか?という発想を持てば、業務のニーズや約束事を、さらに深く理解できる。

ビジネスイベントの発生には、必ず「利害関係者」がいます。
「ビジネスイベントの発生」を「利害関係者」は知りたいと思っている。

イベントが発生したら、「利害関係者」への通知することが、暗黙のルールであったり、「気配り」という差別化のチャンスになる。

先ほどの、予実管理パターンだと、「未処理が残っていたら、アラートしてくれる」「予定日が近づいたらリマインドしてくれる」とか「連絡」パターンを実践するシーンは多い。

「連絡」も体系的に取り組む


エンタープライズアプリケーションの根幹は、

・永続化(記録)
・通信(メッセージング)

の2つです。

実装レベルでは、永続化:データベース、メッセージング:非同期メッセージングとかですね。

ビジネスのレイヤで言えば、

・ビジネスイベントの記録
・ビジネスイベント発生の連絡

になります。
(連絡の実装手段は、概念的には、非同期メッセージングだけど、電子メールとかが多い)

情報システムの開発では、「永続化」は、わりと体系的に検討される。
「データデモリング」とか、「情報アーキテクチャ設計」という概念がある。

「連絡」は、個別のメール通知機能とか、詳細レベルの議論に埋もれちゃって、体系的に扱うことが少ない。

でも、ビジネス活動では、「連絡」というコミュニケーションは「記録」とならんだ中核の活動です。

ビジネス層での「ネットワークアーキテクチャ」として

・ネットワーク構造 (関係者とその接続関係)
・連絡時のプロトコル(形式や手順)

を、「業務の言葉」で、体系的にモデリング、設計することが大切。
ドメイン駆動設計の重要な課題のひとつです。

「連絡」モデルが洗練されるほど、利用者にとっては、ソフトウェアの価値が高まります。

なんかあったら連絡して!


何かあったら、連絡してほしい、というニーズ・ありがたさは、「連絡が欲しい」側にたてば、すぐにわかりますよね。
RSS は「変化があったら教えて」パターンの具体例ですね。
メール到着を教えてくれるエージェント機能もそう。

システムが、利用者の代わりに、利用者の関心事を監視して、イベントが発生したら、自動的に連絡してくれる。
そういう気の利いたアシスタントがいたら、うれしいですよね。

「連絡パターン」は、「気の利いた連絡がほしい」というニーズを、モデリングして、設計・実装すべし、という考え方です。

「情報の集約」パターン


ビジネスで起こる様々な事象を「記録」して、必要な人にこまめに「連絡」すると、膨大なデータが発生する。

CPU、メモリ、ディスク、ネットワークの単価が急速に下がり続けているので、大量のデータを扱うことは、ハードウェアレベルでは、対応しやすくなった。

問題は、その情報を扱う、人間側の能力とコストの問題。

自分に関連する細かい情報をすべて追跡するのは、人間の能力を超えている。
というか、コストパフォーマンスが悪すぎる。

人間は、とても高価だけど、とても、価値のある判断や行動ができる特別な存在。
情報システムは、そういう人間の役にたつことが目的の道具。

昔は、単純で定型的な処理を自動化するだけでも、「価値のあるシステム」だった。

・勤務時間を集計して、給与額を計算する
・売上データを集計して、売上総額を計算する
・入庫と出庫を増減して、残高を計算する
...

日々発生するイベント記録(トランザクションデータ)を集約して、「給与額」「売上総額」「残高」という、単純な情報に加工することが、重要な「システム価値」だった。

昔に比べ

・電子的に記録する(できる)データが飛躍的に増えた
・扱える情報の型式は、数字だからか、文字に、そして、画像や音声に拡大している
・あいまいな情報とか、個人の好みとか、も電子データとして扱う範囲が広がっている

データ総量は、天文学的なスケールで増大している。

こういう大量の情報を、どうやって集約してみせるかが、システムの価値を決める。

大量のデータを、「少ない」情報に、コンパクトに集約することが、システムの価値。

統計


100個の数字を、1つの数字であらわす、というパターンですね。
単純なものでは、「合計」とか「平均」。
いまでも、情報集約の基本はこれ。

もちろん「偏差値」とか「変化率」とかも、このジャンル。

最近は「変化」は数字よりも「グラフ」でビジュアルに見せることがあたりまえになってきた。

要約


100個の数字を、1つ数字で表す計算方法は、いろいろ確立している。

文字情報は、そうはいかない。
利用者のニーズにあわせて、大量の文字データを「要約」する設計が、システムの価値を左右する。

たとえば、「一覧」画面で表示する各項目の情報は、「詳細情報」の要約。

Google の検索結果は、該当ページの内容を、数行に要約していますよね。
また、Web アプリケーションでは、要約から詳細へのリンク、という設計・実装が普通ですね。

その場合も、要約の中のさらに、どの部分をアンカーにするかの設計の選択肢がでてくる。

「要約」は、情報の集約パターンとしては、かなり難易度の高いテーマです。

選別


大量データから選別して、小数のデータに絞り込むのも「情報集約」の基本パターン。
ほんとうに欲しいもの、重要なものだけに絞ってくれる価値ですね。

「検索」サービスが、典型ですね。

アマゾンの「お薦め」とかも、これかな。膨大な数の類似書籍から、小数に絞ってみせることで、役に立とうとしている。

検索機能の設計も「役に立つ」ソフトウェアの大きな設計テーマです。

並び替え


Google の検索は、「順番」をつけることで、大量の関連情報を、わかりやすく集約しているサービスの例ですね。

トップあるいは最初の画面で表示されるものに価値を感じている利用者が大半ですよね。

表示の「順番」の設計の巧拙は、想像以上に、システムの価値を左右する。

グルーピング


何かのテーマ別にグルーピングしてくれると、情報を扱いやすくなることが多い。

ファイルを、フォルダー構造で管理するパターンですね。
メールやメッセージの「スレッド」管理とかも、この一種。

役に立つ、素敵なソフトウェアは、この「グルーピング」のロジックが気が利いていることが多い。

過去のメールを単純に日付単位にグルーピングするより、

・今日
・昨日
・一週間以内
・一ヶ月以内
...

という「意味」のあるグループになっているほうが、使いやすですよね。
(一週間以上前のメールが日付単位でグルーピングされていても、普通はうれしくない)

利用者が自由にフォルダ作って管理、という機能は、実際には、面倒くさいことが多い。
実装上は、汎用にしておいてもいいけど、アプリケーションとしては、「こういうグルーピングがあったら便利」という「事前に定義したグルーピング」を提供することを追求したほうが、良いサービスになることが多い。

「なんでも自由にできる」ことが良いソフトウェアになるとは限らない。

ダッシュボード


ダッシュボードという機能(画面?)があります。

いろいろなテーマ・角度から情報を集約して、

・新着情報
・累計などの統計データ
・(動的に変わる)関連情報へのリンク
...

などを集めた画面ですね。

いろいろな「情報集約」パターンを、さらに「集約」した、画面ですね。

大量のデータを扱うようになると、忙しいビジネスマンにとって、よいダッシュボードは、ほんとうに価値のあるソフトウェアになります。

ろくでもない、なんちゃってダッシュボードもよく見かけますが...

分析パターンというほどりっぱなものではないけど...


ここで、紹介した4つのパターン

・記録は不変
・予実の管理
・連絡
・情報の集約

は、エンタープライズアプリケーションのモデリングや設計をしている時に、私がなかば無意識に使っている基本パターンです。

いままでの経験の中から、「喜んでもらえる」役に立つソフトウェアのポイントになる箇所だと思っている。

それなりにうまくできたと思ったソフトウェアの評価を「だいなし」にしてしまったアンチパターンの裏返し、ともいえるかな。

・データはなんでもかんでも、変更・削除可能
・起きたこと(過去)の記録しかできない(予定は人間が管理して予測)
・ログインして自分で調べにいかないと、状況がわからない
・データをエクセルで加工しなおさないと使えない
...

こういう、ろくでもないシステムを作らないための、自戒を込めた設計ガイドです。

分析パターンはドメイン駆動設計のヒント

昨日の記事、自分で読み返した。「分析パターン」をネガティブに書きすぎた。
自分は、もっと、分析パターンを積極的に使っている。

そういう前向き(?)な内容で、改めて、分析パターンの利用について。

Entities パターンのヒント


Domain-Driven Design(DDD)の Entities パターンで実現するドメインオブジェクトって、もうちょっと具体的に言うと、何があるんだろう?

・エンタープライズアプリケーションで、「識別」したいものは何?
・識別の単位は?(みじんぎり、それとも、どーんとひとかたまり?)

初期のモデルのネタ探しとか、開発中に、モデルに違和感がでてきた時の、別案さがしとかに、分析パターン本は、役に立つ。

クラス名のヒント集として使える。

Hruby の「ビジネスパターンによるモデル駆動設計」


Entity を、さらに三種類に分けている。

Resource, Event, Agent の三つ。 ( REA パターン )

Resourceは、経済的に価値がある何か。当然、ビジネスでは「管理」する対象。
「製品」「サービス」「お金」「労働力」「ツール」など。

Agent は、経済活動をする主体。
「顧客」「ベンダー」「従業員」「企業」など。

Event は、リソースの価値が増減したことの記録。
「販売」「出荷」「支払」「入金」とか。

重要なビジネスの関心ごとなので、それぞれのオブジェクトに「識別情報」をつけて、追跡する必要がある。

Agent が、Resource を対象に、何かアクションを起こす ( Event )。

これをデータ化して、追跡するのが、エンタープライズアプリケーションの基本構造、という考え方。
本の中では、もっと具体的に、

・注文、出荷、返品、...
・融資、保険、賃貸、保証、...
・生産、輸送
・サービス提供(サービスの生産と消費)
・人の管理
・教育、税金
・マーケティングと宣伝
・廃棄物
・電力
...

など、いろいろな問題領域を、 REA モデルで表現するパターンを取り上げている。

それぞれの領域の

・使用する Resource オブジェクトの例
・登場する Agent オブジェクトの例
・発生する Event オブジェクトの例

がいろいろ載っている。

DDD のEntities パターンに対応するパターンとして、「Identification(識別) パターン」がでてきます。「名前」による識別、識別番号の発行、外部発行の識別番号の利用、などが説明されている。

「識別」がビジネスの重要な関心事である、という点、中身の具体的な議論も、かなり近い。
(ビジネスパターンの筆者は、本を書くにあたって、DDD を参考にしたことを明言しています)。

ファウラーの「アナリシスパターン」


Entities パターンに直接対応するのは、5章の「(ドメイン)オブジェクトへの参照」ですね。
内容はとうぜん「識別」です。「名前」とか、識別体系の考え方のヒントがいろいろある。

第2章「責任関係」は、ビジネスパターンの Agent (経済活動の主体)として、「企業」、「部門」、「個人」などを Entity の候補として説明している。

Hruby の「ビジネスパターン」にも「責任パターン」がでてきます。問題意識はいっしょですね。

面白いのは、「役職」オブジェクトの導入。「個人」ではなく「営業部長」というオブジェクトを作ると解決する問題もいろいろあるよ、という内容。

こういう感じで、

第4章「企業財務の観測」
第6章「在庫管理と会計」
第7章「会計モデルの利用」
第8章「計画」
第9章「金融商品の取引」
第10章「金融派生商品」

など、それぞれの問題領域ごとに、Entity の候補になる「モノ」とか「コト」を表すパターンの説明が続く。

Hruby の「ビジネスパターン」は、会計モデルがベースなので、ファウラーの「アナリシスパターン」の4章、6章、7章と、問題意識は同じ。
問題の捉え方とか、モデルでの表現は、共通するところと、全くことなるところがあって、なかなか興味深い。

「アナリシスパターン」は、章のタイトルだけ見ると、特殊な問題領域に見えても、読んでみる価値はある。

例えば、10章の「オプション取引」は、「予約」とか、「権利の取得」と「権利の行使」という、いろいろな問題領域に登場し、ちょっと扱いにくそうなテーマのドメインオモデリングのヒントがいろいろ載っている。

ニコラの「ストリームラインオブジェクトモデリング」


この本は、Entity は、7種類だけ、という、だいたんな、モデリング論。
ビジネスの関心事は、突き詰めると、7つだけ、という考え方。

・人
・場所
・モノ
・モノの集合体
・トランザクション
・トランザクションの集合体
・前のトランザクションをフォローするトランザクション

Hruby の「ビジネスパターン」だと、Agent が、人。
Resource は、場所、モノ、モノの集合体。
Event が、トランザクション、という対応ですね。

それぞれのオブジェクト間の関係(協調パターン)も、12種類に限定できる、と言い切っている。

7種類の Entity (ドメインオブジェクト)を、12種類の協調パターンで関係づければ、良いドメインモデル が簡単(?)に、できるよ、というモデリング論ですね。

パターンカタログというより、モデリングの方法論であり哲学、という感じ。
私の使い方は、パターンカタログであり、ヒント集です...

DDD の Conceptual Contours (概念の輪郭)パターン


DDD の9章では、このパターンの実践方法は、主に、業務の専門家との対話とリファクタリングになっている。

分析パターン本は、ビジネスの概念・関心事は、こういうオブジェクトで表現する、というネタが満載。

Hruby の「ビジネスパターン」だと、主に「会計」を切り口にした「ドメインオブジェクト」を具体的にいろいろ説明している。

「期日」「説明」「通知」「転記」「分類」など、エンタープライズアプリケーションの基本課題についての、ドメインモデリングのネタがいろいろ登場する。

ファウラーの「アナリシスパターン」も、先ほどの「役職」そのものをドメインオブジェクトにするとかのネタがあちこちにちりばめられている。

ニコラの「ストリームラインオブジェクトモデル」は、ビジネスの概念の形は、7種類の Entity と、12種類の協調パターンで、表現できるよ、というところまで振り切っちゃっている。

「ビジネスパターン」も「アナリシスパターン」も「ストリームライン」も、エンタープライズアプリケーション分野での経験・知見をかき集めて、整理してものだから、ビジネスドメインの「概念の輪郭」をシャープに描いたオブジェクトが満載されている。

DDD の Conceptual Contours(概念の輪郭)パターンのヒントの宝庫ですね。

あと、Value Objects パターンの実践ネタとして、「アナリシスパターン」の付録Aの「基本型」(Money, Date, DateRange, ... ) は、参考になります。

ただし、分析パターンは、汎用的に抽象化されているので、注意が必要。
今、開発しているソフトウェアの問題領域には「最適」ではない。

パターン本で見つけたヒントを手がかりに、現在の問題領域に「特殊化」したモデリング、設計・実装が必要ですね。

DDD 9章 Making Implicit Concepts Explicit (あいまいな概念を明確にする)


エバンスがDDD で「どうやってオブジェクトにすればよいか、わかりにく概念」として「制約」とか「手順」とをあげている。

DDD では、どうやって、モデリングし、設計・実装するかの具体例がほとんど書いてない。

分析パターン本は、あたりまえだけど、ビジネスのルール、制約や業務手順のモデリングのヒントが満載。

Hruby の「ビジネスパターン」


この本では「制約」を「方針レベル」として9つのパターンで説明している。

・Policy (決め事を表現するオブジェクト)
・Type, Group, Linkage, Responsibility, Custoday (オブジェクト間を関連づける概念のオブジェクト化)
・Commitment, Contract, Schedule ( 将来の行動についての制約を表すオブジェクト)

また、業務の手順というか、ビジネス活動の行動を「振舞パターン」として12のパターンでモデル化している。

・識別する、分類する
・場所の指定、期日の指定
・転記、勘定、請求権、照合 (会計活動)
・説明、注釈、価値の表現
・通知

こういうビジネス活動の振舞を、どんなドメインオブジェクトで表現するかのパターン集です。

ファウラーの「アナリシスパターン」


「手順」については、第8章の「計画」で、さまざまなモデリングパターンが登場する。

・予定した行動
・実施された行動
・実施されなかった行動

という視点で、「ビジネス活動」をモデリングするパターンをいろいろ取り上げている。

制約の実装については、14章で、触れている。

ニコラの「ストリームラインオブジェクトモデル」


ビジネスルールを、オブジェクト間の関係として、分類。

これも、5種類に類型化

・型ルール
・多重度ルール
・プロパティルール
・状態ルール
・競合ルール

この本の考え方は、こういう「オブジェクト間の関係」に関するルールも、すべて、Entity オブジェクトのロジックとして記述することが特徴。

例えば、「顧客」と「注文トランザクション」と「商品」に関する、ビジネスルールは、オブジェクトを生成して参照を保持するときに、お互いオブジェクトが、その妥当性をチェックする、という実装スタイル。(どういう関係パターンの時、どのルールは、どちらのオブジェクトの責務にすべきか、ということも、パターンとしてひとつの表にまとまっている)

・型は妥当か
・多重度は妥当か
・値の範囲とか形式は妥当か

DDD でいうところの Services パターンは、使わない。必ず、Entity に持たせる。
Value Objects パターンにあたる、考え方もないですね。

「関連」とビジネスルール


多くのビジネスルール(制約)は、オブジェクト間の「関係」についてのルールだといえる。

ファウラーは「アナリシスパターン」で、関係のモデリングと実装についても詳しく論じている

14章の1節「関連の実装」は、「関連」をオブジェクトの参照として実装する方法がテーマ。
方向性、多重度の違いによって、どんな実装方法があるかを分類して解説している。

15章「関連パターン」は、「関連」を「ドメインオブジェクト」としてモデリング・実装する、いろいろなパターンの解説。

Hruby は、主に「方針レベル」の9つの構造パターンとして、「関係」を表現するドメインオブジェクトを説明している。 DDD だと、Services パターンとも関係する。

ニコラの「ストリームラインオブジェクトモデル」は、関連オブジェクトを使わない方法に振り切った考え方。

個人的には、関連自体をドメインオブジェクトにして、そこにいろいろなドメインの知識をおくほうが、わかりやすいことが多いと思っている。「関心事の分離」の原則とか、「疎結合」の原則にあうことが多い。

ニコラの「ストリームラインオブジェクトモデル」は、パターンの整理とか、ヒントとしては、とても参考になる。

でも、制約を、すべて、Entity オブジェクトにカプセル化する、という実装方法には、かなり違和感がある。

ニコラの本には、サンプルコードもたくさんのっているんだけど、ロジックが直感的にわかりにくいし、変更があった時も、安全で簡単だとは思えないんですよね。

Hruby の「ビジネスパターン」を「アスペクト指向」でのサンプルコードが詳しく載っている。
こちらも、コードを読んでも、わかりやすいとも、変更しやすいとも思えなかった。

両方とも、パターン本としては、良いヒント集だと思うけど、実装コードの例としては、私には、ぴんとこないコードが多い。

ヒントだけど、「答え」ではない


この記事で取り上げた3冊の分析パターン本は、私は、ヒント集として、現場でかなり使っています。
いろいろな問題にぶつかると、読み直す。
読み落としていたことを発見したり、当時は理解できなかったことが、いつのまにか理解できるようになっていることも多い。

ヒント集としては、ほんとうに重宝している。手放せない。

でも、あくまでも「ヒント」であって「答え」ではないんですよね。

ドメイン駆動設計に分析パターンを利用する

実際のコードで、小さなリファクタリングを繰り返しながら、ドメインの理解を深めていく。

このやり方が基本だと思うし、確実に効果はある。

でも、このやり方だけでは、現実的には、時間が足りない。

経験豊富な開発者であれば、得意の分野であれば、プロジェクトの最初から、相当にレベルの高いモデルとコードから、スタートできる。

そういう経験豊富な開発者の頭の中にある、モデルや設計を、流用できれば、初期モデル、初期の設計を、ある程度のレベルのところからスタートできる。

これが、Domain-Driven Design(DDD) 11章 "Applying Analysis Patterns(アナリシスパターンを適用する)" のテーマですね。

私が利用しているビジネスパターン


エンタープライズアプリケーションの概念モデルは、あきらかに、類似性があります。
例えば、会計とか契約とかに関係するビジネスルールや業務のやり方は、どんな企業でも基本はいっしょ。

「受注」・「出荷」・「請求」という、業務の流れ、一連のトランザクションも、基本は、一緒。

どの企業も「顧客」を相手に「商品」を提供している。

もちろん、個別の案件ごとに、さまざまな特別な事情があるので、まるっとコピーすれば一丁あがり、というわけにはいかない。

でも、モデリングの出発点として、定評のある概念モデルのパターンを利用するだけでも、モデリング初期の低レベルの試行錯誤は、ずいぶんと減らせる。

私が、現場で実際に使っている、ビジネスドメインの概念モデルのパターンカタログ。

ビジネスパターンのカタログ


現場でそのままは使えませんね


この リストであげた本は、何回も読み直しているし、実践でも、いろいろ参考にしている。

でも、書籍のパターンを概念モデルとして、そのまま使ったことはないです。

「参考になる」けど「そのままでは使えない。使うべきではない。」というのが、私の正直な感想。

現場で使えていない理由を考えてみると...

抽象的すぎる


とってもシンプルになっているんだけど、簡略化されすぎて、現場の具体的な課題との差が大きすぎる。

この課題には、このパターンが応用できるんだ、と気がついたのは、プロジェクトが終わって、パターン本を読み直してみたときだった、という経験が何回もある。

現場で、モデリング・設計で格闘している真っ最中に、ぱらぱらとカタログ見れば、欲しいモノがすぐみつかる、というわけではないですよね。

こういうパターンのレベルまで、現在の設計を「簡略化(抽象化)」してみて、比較してみることは、意味があるかなあ。

汎用的すぎる


いろいろ変更要求が発生しても、この設計にしておけば、変更がしやすいだろうなあ、と思うパターンはいろいろある。

でも、いま取り組んでいる課題の「答え」として、やりすぎのケースがほとんど。

・「法人」と「個人」は、「パーティ」という汎化した概念で同一に扱える。

理屈はそうだけど、実際のアプリケーションで、汎化した「パーティ」としてモデリングして設計・実装することが、わかりやすく、変更が安心してできるか、というと、かなり疑問。

ある程度の規模の事業であれば、法人向けと個人向けは別の事業のことが多い。
法人向け事業へのアプリケーションを作る時に、個人向け事業のアプリケーションへの汎用性まで取り組むのは、どう考えても、余計な関心事まで手を出しすぎ。

クラス名やメソッド名も、一般的に通用するように、かなり概念的な名前が多い。
個別のプロジェクトのユビキタス言語としては、だいたい不適切な言葉が多い。

ドメインの専門家は、現場で、そこまで、一般化した用語は使っていない。

直感的じゃない


メタ情報を持つクラスを導入したり、継承関係を駆使したパターンは、じっくり考えてみないと、理解できないことが多い。

直感的に、なるほど、と思うビジネスパターンは、あまりない。
パターンの構造は、一見シンプルでも、「どういう問題」を「どう解決する」かが直感的じゃない。

これが、一番の問題かな。

現場で必要なのは、関係者が「なるほど」と納得する、わかりやすい、単純明快なモデル。

ビジネスパターンで提示されている概念モデルは、理解している人には、わかりやすいけど、直感的ではないんですよね。

ビジネスパターンの使い方


私自身の、ビジネスパターン本の読み方、使い方。

「問題の説明」を読む


どう解決するかの前に、そのパターンの動機となっている「問題」の説明を丁寧に読む。

ここで、ピンとこなかったら、そのパターンはざっと流し読み。

問題がピンとこないのに、解決策が理解できるわけはない。

問題がピンときたら、そのパターンの説明はじっくり読んでおく。(プロジェクトの最中よりも、できれば、事前に)

現場で、問題に出くわしてから、読み直す


問題がピンときても、解決策のパターンが、簡単に理解できるとは限らない。
というか、ほとんどが最初に読んだ時は理解できていない。

ただ「問題」は理解できているので、「現場で類似の問題」に出くわしたときに、どこを見ればよいかはすぐわかる。

そういう具体的な問題の解決策として、パターンの説明を読み直してみると、理解できたり、モデルや設計の改良のヒントが見つかったことは何回もある。

でも、それでも、パターンとして図示されたモデルをそのまま使ったことは、ほとんどない。
用語が汎用的すぎるのも、ひとつの理由かな。

パターンの説明の中に書かれた、「考え方」と、小さな「具体例」が、参考になることが多い。

そういう経験を何度もしてきたので、今は、

・問題は、一通り読んでおく
・問題がピンときたら、パターンの説明もちゃんと読んでみる
・現場で関連しそうな問題に出くわしたとき、パターンの「考え方」と「小さな具体例」を読みなおす
・パターン全体は、そのまま使わない

というのが、私の基本的な使い方ですね。

仕込んでおく、勉強を続ける


私は、技術者として、ドメイン駆動設計の実践にこだわっているし、日々勉強だと思っているので、ビジネスパターンの本は、機会を見つけては、なんども読み直すようにしている。

全体をざっと読み直すこともあれば、特定の部分だけ、じっくり読み直すこともある。

現場のモデリング、設計課題がいちおう解決しても、時間があれば、できるだけ、「別のやり方もあるのでは?」という視点で、ビジネスパターンのカタログを漁ってみるようにしている。

そうすると、前に読んだ時は、気がつかなかったこと、理解できなかったことをいろいろ発見できる。
具体的な問題をいろいろ考えて、手を動かして、現場での経験・知識が増えれば、それだけ、パターンを理解できる範囲が広がる、ということなんでしょうね。

開発チームでビジネスパターンを利用する?


個人ではなく、実際のプロジェクトで、開発チームとしてのビジネスパターンの利用はどうだろう?

私がかかわっている開発チームでは、「ビジネスパターン」の用語が、モデリングや設計の言葉として、使われることはほとんどないですね。

モデリングや設計に行き詰まったメンバーに、こういう考え方もあるよ、ということで、パターンの利用例を説明したりすると、「なるほど」という感じで、その問題に対して、設計が改善できたことは何度もあります。

実際に困っているので、具体的なモデル、コードの形で説明すれば、直感的に理解してくれるし、実際に、ソフトウェアがわかりやすく、扱いやすくなることが多い。

でも、極端に言えば、それっきりなんですよね。
私からみると、同じ種類の問題で、同じパターンでの解決ができそうに見えても、同じ問題には見えないらしい。

それでも、説明するときに「パターン名」とか、参考書籍や該当ページを、さりげなく、繰り返し使うようにしていると、ビジネスパターンについて、メンバー間で共通の知識が少しずつ増えてきている手ごたえはあります。

パターンカタログの価値は、「パターン名」にあるのかもしれない。

「パターン名」が、開発チームのユビキタス言語になってくれば、もっとレベルの高いモデリング、設計・実装を、楽しくできそうなんだけどなあ。

ビジネスパターンを具体例で、現場ネタで


このブログでは、ドメイン駆動設計について、できるだけ、現場ネタや具体例を書こうと思っています。

パターン本は、汎用的だし、とても抽象化(単純化)されている。
そのままでは、現場の課題に、直感的に使えない。

そういう抽象化されたパターン本と、現場で発生する具体的な問題を、直感的に結びつけて利用するスキルアップのために、自分自身の訓練のつもりで書いている。

書き始めてみて、たくさん得るモノがあった。自分の頭がだいぶ整理できてきたし、現場の課題に、即座に応用できる範囲も広がったように思う。

ブログで公開すると、いままで縁の無かった人と、ドメイン駆動設計や、ソフトウェア開発のさまざまなテーマについて、情報交換できる機会が増えたのも大きな収穫。

ドメイン駆動設計のパターンを、この調子で、一通りやってみて、次は、Hruby のビジネスパターンとか、Fowler のアナリシスパターンとかをネタに、続けてみようと思っている。

しやなかな設計 ( Supple Design ) はボトムアップで

Supple Design (しなやかな設計)のパターンと設計スタイルは、主な適用範囲は、狭い範囲ですね。

ビジネスロジックのちょっとしたかたまりを、Money とか、 BusinessDate とか、PersonName とか、役割が単純で、独立した、プリミティブなドメインオブジェクトにカプセル化する作業。

こういう単純だけど、役割が明確なドメインオブジェクトが揃ってくると、全体のコードがわかりやすくなる。
その結果、もっと、大きなモデリングや設計の課題に取り組みやすくなる。

レイヤ構造


Supple Design を地道に実践していくと、ドメインオブジェクトの群れが、レイヤ構造になってくる。

上から、


アプリケーションサービス層
  ドメインモデルを使う側、クライアントコードの置き場所

ドメインモデル層
  問題領域の知識が豊富 ( knowledge rich )なドメインモデルの本体

ドメインの基本用語層
  ドメインの基本用語を表す Value Object 群

プログラミング言語層
  int, String, BigDecimal, コレクションなどの開発言語の基本API 群


という感じで、構造がはっきりしてくる。

Supple Design(しなやかな設計)は、上から3番目の「ドメインの基本用語」を、おもに、 Value Object として整備する設計パターンですね。

レイヤは、上が下を使う。上から下への単方向の依存性。

依存性をできるだけ排除することを意図した、Standalone Classes パターンで、設計・実装したドメインオブジェクトは、必然的に、「下」のレイヤの住人になります。

便利な基本用語を揃える:ボトムを充実させる


プログラミング言語が、便利なAPIを用意してくれれば、設計・実装が楽になる。
貧弱なAPI しかない言語は、つまらないコードを自分で書かなきゃいけない。

同じように、ドメインモデルの一番下の層に、「日付」「金額」「名前」「数量」といった、基本の部品を用意すると、ドメインモデルの設計・実装が、楽になる。

Java は、エンタープライズアプリケーションの実装言語としてみると、こういうビジネスの基本概念は、言語APIとして用意されていない。

汎用的な Calender, BigDecimal, String, int などがあるだけ。

この言語のAPI だけで、ドメインの記述を始めると、ドメインの本質の問題ではない、日付操作のコードとか、それをテストするコードを、あちこちで書く必要がでてくる。

でも、ドメインの基本用語が、小さくて、わかりやすく、安心して使える Value Object として揃っていれば、設計・実装は、ずいぶん楽になる。

問題領域の、もっと本質的な課題に、時間とエネルギーを使えるようになる。

そのためにも、Supple Design を地道に実践して、プリミティブなドメインオブジェクトを着実に充実させていく。
ボトムが充実してくれば、上での作業は、ずっとやりやすくなる。

コードからボトムアップ


私は、プリミティブな Value Object の充実は、コードのリファクタリングから入るのが、実践的で良いと思っている。

前のプロジェクトで、ファウラーの「アナリシスパターン」の付録Aに列挙された「日付」とか「時点」とかの「基本型」を参考に、事前に、基本のドメインオブジェクトのライブラリみたいなものを作ろうとしたことがある。

結果は、明らかな失敗。

・使いもしないクラス、メソッドの設計・実装・テストに貴重な時間を使ってしまった
・使われたクラスも、実践で必要なメソッドは、当初の想定より、もっと特殊なものが多かった

必要なものを、必要な時に、必要なだけ作る、「後払い」のアジャイルの考え方でやればよかったのに、典型的な「前払い方式」の設計・実装作業をしてしまった。

本から持ってきた、一般的なクラスとメソッドを深く考えずに実装したので、ほとんど役に立たなかった。
結局、生き残ったコードは、リファクタリングの結果生まれた別のコードばかり。

問題領域やドメインオブジェクトの設計の、経験やスキルに依存するんだろうけど、私たちのチームの場合は、プリミティブなドメインオブジェクトを「前払い」方式で整備するやり方は、失敗だった。

役に立つ、プリミティブなドメインオブジェクトの作り方は、

・ドメインロジックを書いた実際のコードをリファクタリングしながら
・小型の Value Object を導き出していく

のが、良いと思っています。

リファクタリングのスキルアップ


とはいっても、そもそも、リファクタリングの意識とスキルがないチームでは、どうしようもない。

最初は、ファウラーの「リファクタリング」を何冊か用意して、「読んどいて」とやってみたけど、チーム全体としては、まったく効果がなかった。

特定の人が、特定のサンプルに興味を持つくらいが関の山。
チーム全体としては、リファクタリングの動機付けも、習慣づけも、スキルアップもなにも起きなかった。

結局、私が、リファクタリングを、とにかく一所懸命勉強しておいて、コードレビューの時に、具体例を見つけながら、リファクタリングの初歩の初歩を小出しにする活動を地道に続けた。

「リファクタリング」という言葉すら使わず、こう書いたほうがわかりやすいでしょ、という感じで、メソッドを抽出したり、ちょっとした名前変更をしたり、ガード節で、if 文をちょっと単純化したりを地道に繰り返した。

徹底的なボトムアップ戦略ですね。

自分の書いたコードが読みやすくなる実例を目の前にすると、少しは、そういう書き方に興味を持ったり、実践するようになってくる。

それでも「リファクタリング」を熟読して、実践する技術者は、多くはないのが私たちの現実。

日本語の本があって、具体的なコード例が載っている、「リファクタリング」ですらこんな状態。

ましてや、英語で、概念的な話しが多い、Domain-Driven Design(DDD)の 10章 Supple Design のパターンを、自分で勉強しなさい、というのは、期待するほうが、無理なんだと思う。

現場の実際のコードで、丁寧にコードレビューをして、いっしょに、コードの改善活動を、地道に続けるのが、結局は、いちばん確実な方法なんだと思っています。

「ペア・リファクタリング」の薦めですね。相手が何人もいると、かなり、エネルギーが必要ですが...

しなやかな設計 : 小さく、はじめてみる

Domain-Driven Design の10章 Supple Design ( しなやかな設計 ) は、ドメイン駆動設計を実践していくための、設計・実装の基礎テクニック集なんだと思います。

・ドメインをより深く理解して、ほんとうに役に立つソフトウェアを開発する。
・隣接ドメインを含めて、より広い範囲の問題に取り組む。

この章の基礎テクニックを習得して、日々の設計・実装で、ふつうに使えるようになると、ドメインをもっと深く理解し、もっと広い問題に取り掛かる、土台がしっかりしてくる。

ソースコードが改良され読みやすくなり、開発者のドメイン駆動設計の実践スキルがしっかりしてくる。

どこから手をつける?


エバンスは、10章の最後で、広い範囲を、一気に手をつけると、エネルギーが分散してしまう。まず、狭い範囲に絞って、そこで、じっくりと「しなやかの設計」の基礎テクニックを実践してみることを薦めています。

ちょっとした「計算ロジック」をターゲットにするといいよ、と書いていますね。

確かに、計算ロジックは、「値」と「値」を計算して、その結果が「値」になるので、Value Objects パターンの実践の良いネタになりますね。

この発想で「しなやかな設計」に取り組んでみる候補は、コードの中の

・String や StringBuilder とか使っている、文字列操作
・int, double ,BigDecimal とか使っている、数値計算
・Date, Calendar とか使っている、日付計算
・List, Set, Map とか使っている、集合演算

から、手をつけるのが良いと思います。

こういう小さな部分の書き換えを積み重ねると、ソフトウェア全体が、硬直したぎこちない状態から、扱いやすい「しなやかな」ソフトウェアへの進化がはじまる。

UI やデータアクセスと、ドメインのロジックが、うまく分離できていないコードでも、こういう「演算」ロジック部分だけを、小さなドメインオブジェクトを作って、ちょっと書き換てみる、というのは手がつけやすい。

分離できていないコードを「ORMフレームワークで、ドメインとデータアクセスの分離じゃあ」とか言い出すと、問題が大きくなりすぎちゃう。

文字列の操作


String データと String データを組み合わせて、新しい String データを作るコードは、それこそ、どこにでも転がっていますよね。

たとえば、

String familyName
String givenName

から、

String fullName

を作るとかいうやつ。

こういう文字列の連結コードを、たとえば、PersonName オブジェクトにカプセル化する。

class PersonName
{
 String familyName ;
 String givenName ;

PersonName( String familyName, String givenName )
 {
  ...
 }

 String fullName()
 {
  // StringBuilder で、姓+空白+名 を作って return
 }
}

このオブジェクトを作るのが、10章の基礎テクニックの実践になっている。

変数名として、うっすらと見えていたドメインの概念「氏名」が、ドメインオブジェクトとして、くっきりと形になりました。

Conceptual Contours パターンです。

PersonName#fullName() は、意図が明確で、直感的にわかりますよね。

Intention-Revealing Interfaces パターンです。

PersonName オブジェクトは、Java の基本APIしか使っていません。
他のドメインオブジェクトに依存しない、Standalone Classes パターンになっていますね。

fullName() メソッドは、内部で使っている、String も、StringBuilder も、不変(imutable)型のオブジェクトなので、副作用の心配がない、Side-Effect-Free Functions パターンになっています。

数値計算


エンタープライズアプリケーションで、Java 使うなら、数値計算の基本は、BigDecimal とか、BigInteger。

BigDecimal には、四則演算、スケール指定、丸めルールとか、さまざまなメソッドが用意されていますね。

BigDecimal を使って、たとえば、金額を計算しているコードを見つけたら、「しなやかな設計」をさくっと実践。

Money オブジェクトを作って、BigDecimal 使った計算を、カプセル化しちゃう。
まず、クラス名が、BigDecimal という広い意味から、Money というドメインの関心事に限定される。 BigDecimal が提供する、さまざまな、コンストラクタやメソッド群のうち、今の問題に必要なコンストラクタ、メソッドだけに限定する。

たとえば、今は、整数だけで、足し算だけできればよいなら、Money の公開インタフェースは、

class Money
{
 Money( int initialAmount )
 Money add( Money amount )
}

という感じで、めちゃくちゃ単純になり、意味も直感的にわかる。
Intention-Revealing Interfaces パターン ( わかりやすい名前 )ですね。

BigDecimal は、ぼんやりとした広い概念。
Money は、「お金」というビジネスドメインの重要な関心事を、くっきりと形にしている。 Conceptual Contours ( 概念の輪郭 ) パターンですね。

Money オブジェクトの add() メソッドは、

・パラメータが Money
・戻す値も Money

という、 Closure of Operations パターンの、わかりやすい例になっている。

( BigDecimal も、Closure of Operations パターンの設計になっている )

日付計算


もうなんども書いている。
使いにくく、状態を持った(=副作用が心配)ろくでもない Calendar クラスを、BusinessDate とかにラッピングして、日付の足し算や引き算をカプセル化しちゃう。

日付の操作をすると、Calendar のインスタンスは、自分自身を書き換えちゃう。副作用をなくす、Side-Effect-Free Functions パターンの正反対。

自分を書き換えちゃう、こういう API をラッピングして、

BusinessDate dayAfterOneWeek = date.addDays( 7 )

とうように、Date に閉じた操作を、コードで実際に使ってみると「閉じた操作( Closure of Operations ) パターン」の良さが実感できるはず。

DateRange( BusinessDate from , BusinessDate to )

のような、「期間」を扱うオブジェクトとか、IntervalByDay 「日数」を扱うオブジェクトとかも、あると便利。

集合操作


List とかをコード中に見つけたら、迷わず、

PersonList オブジェクト

を作っちゃう。

シンプルにわかりやすくする


コレクションフレームワークのAPI群は、汎用的なさまざまなコンストラクタ、メソッドを提供しています。

でも、List でやりたいことは、ドメインのニーズに特化した、限定された操作。

だから、 PersonList にラッピングして、

・操作を限定する
・一般的なメソッド名から、ドメインの関心事のメソッド名に特化させる。

こうやって、操作をシンプルに、わかりやすく宣言することで、コードの意図が明確になる。

Intention-Revealing Interface ですね。

安全にする


List を、インスタンス変数で持つと、あちこちのメソッドで、更新できちゃう。

問い合わせメソッドの戻り値として、List をそのまま戻すと、問い合わせた側で、List を変更できちゃう。

これは、副作用が怖い、危険な設計。

Side-Effect-Free Functions パターン、つまり「副作用をなくす」設計にするのは、PersonList にがっちりとカプセル化してガードしてやる必要がある。

・更新操作は禁止。
・集合演算の結果は、別の PersonList オブジェクトを返す。
・問い合わせメソッドの戻り値は、「更新できない( unmodifiable )」に変換して戻す。

コレクションフレームワークを活用する


コレクションフレームワークは、集合演算がいろいろ用意されている。

だけど、API をろくにしらべずに、平気で、 for 文を使いまくる開発者が結構いるんですよねえ。

・別のコレクションの要素を for 文で add する > addALL()
・要素を見つけるのに、for でループ > contains()
・重複チェックで for > Set にすれば、簡単にユニークになるのに
・並べかえループ > Collectionsの sort() とか reverse()
・乱数使って、for でランダムに並べかえ > Collections の shuffle()
...

あと、key-value ペアの集合を、Map でさくっと操作すればよいのに、配列やList を二つ使って格闘したりする。

List とか、見つけたら、とりあえず、PersonList にしちゃって、関連するロジックは、すべて、こっちに移動。

で、for とか使っているところは、まず疑ってかかる。

コレクションAPI でなんとかなっちゃうはず。
単純に、一発で、解決する API があることも多い。
そうじゃない場合も、2ステップで、API を組み合わせれば、OKというのがほとんど。

コレクションの要素オブジェクトの設計を改善することで解決することも多い。
あるいは、簡単な、前処理とか、後処理をやれば、メインの処理は、驚くほど単純、ということもよくある。

いずれにしてもコレクションとループ操作は、副作用が怖く、バグが潜みやすい場所です。

・コレクション専用のオブジェクトのカプセル化して
・コレクションAPIを活用して、for 文をつかわない

ことで、わかりやすく、変更が安全な「しやなかな設計」に近づけることができます。

しなやかな設計の土台がため


こういう感じで「演算」系の

・文字列操作
・数値計算
・日付計算
・集合操作

を見つけたら、10章の6つの基本パターンを手がかりに、役割の明確な、小さな Value Object を設計・実装していく。

そうすると、残った側のコードは、

・ぜんたいの見通しがよくなる(構造が単純になってくる)
・how が Value Object 内に隠蔽され、主要部分は、What を宣言するスタイルのコードが増えてくる
・基本的なドメインの用語がクラスとして揃ってくるので、コードが、ドメインの用語中心になってくる

こうなってくると、いよいよ、

・最初は理解できていなかった、そのドメインの中核の概念の発掘
・隣接ドメインを含めた、より大きな複雑な課題への挑戦

がはじまる。

一段と高いレベルのドメイン駆動設計の実践ですね。

宣言的スタイルのエクササイズ

やっぱり宣言的スタイルでしょう


エバンスは、ドメイン駆動設計の10章で、「宣言的スタイル」の良さを説いている。
ケントベックも「実装パターン」の「原則」の一つとして、「宣言的な表現」が良いと言っている。

私自身は、SQL 文や、XML のように宣言型の言語 ( if や for のない言語 ) が好きなので、こういう人たちが、「宣言的がいいんだよ」と、書いているのを見つけちゃうと、「そうそう、やっぱり宣言的スタイルだよねえ」と、勝手に納得しちゃっている。

あまり、深く考えたことはないけど、Java とかも、できるだけ、how 指向ではなく what 指向、つまり、宣言的なスタイルのコードの方が、読みやすいし、変更もやりやすいと思っている。

手続き大好きの人が多い?


そんな、「宣言スタイル大好き」派の私からみると、多くの開発者は、手続き型に書きたがるなあ、というのが実感。

たぶん「宣言的」な書き方をする経験がないので、そういう発想もないし、そっちのほうが、良いのでは、と考えたり、感じる機会が少ないんだと思う。

プログラミングを覚える過程で、徹底的に、手続き的な書き方、if 文や for 文の使い方を叩き込まれてきているので、あたりまえなんでしょうけどね。

宣言的スタイルのエクサイズ


命令を並べる手続き型に慣れきった開発者向けに、「宣言的スタイル」の感覚を身につける、エクササイズを考えてみた。

自分が、宣言的スタイルに目覚めた経験や、若手の技術者に、手続き型以外の発想を、覚えてもらう、トレーニングとして、使ったりした内容。

テーブル設計、制約、SQL


エンタープライズ・アプリケーションでは、データベースの設計・実装は、必須のスキル。
そして、リレーショナルデータベースとSQLは、典型的な「宣言」指向の世界。

テーブル設計、制約、SQLには、「宣言的スタイル」のエクササイズネタは、ごろごろ転がっている。

テーブル分割


テーブルにぐちゃっとカラムを並べない。

今日、ある案件で見せてもらったテーブル定義書は、一つのテーブルのカラム数が、なんと300。
これ、データを利用するシーン、データの発生や変更のタイミングなど、いっさいお構いなしに「店」の情報というだけで、ぜんぶ、放り込んじゃっているんですよね。

こういうテーブルは、ほんとうに「宣言的スタイル」の良い練習ネタ。

カラムをグループに分けて、グループごとに名前をつける。(別テーブルにする)
これが、情報のカタマリを「宣言」するということ。

1テーブル300カラムも、開発者は「情報のカタマリ」を、いくつかの項目グループとして認識しているはず。

でも、それに名前がついてない。
そういう暗黙の概念に「名前」をつけるのが「宣言」スタイルの練習になる。

そうやって、グループに分けて、良い名前がつくと、扱いやすくなることが実感できるはず。

制約


テーブル分けたら、関連するテーブルに、徹底的に「外部キー制約」をつくっていく。
この情報と、この情報が、リンクしていることを、明示的に「宣言」する。

SQL の JOIN 句で、必要に応じて、関連を記述するのもいいけど、「データベース上の制約」として、関連(構造)を、明示的に「宣言」する。

外部キー制約がしっかり設計・実装されたデータベースは、力づくの操作がやりにくくなるけど、データ構造が安定して、扱いやすくなる。

データの不整合とかに悩まされることが減り、プログラムで、トリッキーな応急処置もいらない。

あと、すべてのカラムは、 NOT NULL 制約が、原則。

オプショナルなカラムがあったら、それは別テーブルにして、「存在する」ときだけレコードを作るようにする。

こうすることで「カラム」は「データが100%存在」することを宣言することになる。

SQL


SQL は、力のある開発者は、複雑な副問合せ、WHERE句の中の AND/OR 群、CASE 文、IN 句などを駆使して、結構、複雑なロジックを記述できちゃう言語。

でも、これ、アンチパターンなんですよね。 SQL 本来の宣言的なスタイルから、だいぶ離れちゃっている。

SQL は、できるだけ単純にする。

副問合せが必要なのは、たぶん、区分を表すカラムや、その区分マスターが足りない。
AND/OR を組み合わせて複雑に記述しているのも、たぶん、区分とかの設計・実装不足。

極端な例だけど...

WHERE age >= 25 AND age <= 35

という記述より、

年齢区分テーブル
・年齢 ( 15,16,17,....,99 )
・区分 ( 若手、ベテラン、シルバー、...)

というテーブルを作って、age をキーにして、外部キー制約を宣言する。

そうすると、先ほどの条件文は、

SELECT
...
FROM 応募者
INNER JOIN 年齢区分 ON 応募者.年齢 = 年齢区分.年齢
...
WHERE 年齢区分.区分 = "若手"

という、書き方になる。

どうやって判断するかの how ではなく、何に関心があるかの what を「宣言」するスタイルに変わったでしょ?

あと、年齢も、15歳以上で99歳以下という年齢範囲ルールも静的に「宣言」することになる。

IN 句とか、CASE 句も、テーブルとして、表現するやりかたがたくさんあります。
ビジネスルールとその判断ロジックは、テーブルと参照制約で「静的に宣言する」のが、データベースらしい設計だと思う。

まあ、実践で、ビジネスルールを、こういうテーブル指向の設計・実装で、どこまでやるかは別として、「宣言的スタイル」の良いエクササイズにはなる。

テーブル設計スキルの幅も広がるので、一石二鳥ですね。

ant


ant は、どうしても、シェルスクリプト的に書きがち。
でも、XML 記述を採用しているわけだから、開発者の意図は、「宣言的」に書いて欲しいはずなんですよね。

ant は、target が「何」であるかを「宣言」して使うツール。
どうやって実現するかの、how を、手続き的に書くツールではない。

ant の宣言的スタイルの使い方は、「ThoughtWorks アンソロジー」という本の「antのリファクタリング」が参考になります。

あと、ぱっと見、わかりやすいチェックポイント。

アンチパターン:<echo> タスクの連発

「なにがなんでも 命令型派、手続き型派です」の決意表明ですね。
ant でメッセージ表示したい時は、タスクではなく、各要素の name 属性、description 属性を、丁寧に、わかりやすくきちんと書く。

で、画面やログへのメッセージの表示は、ant の実行時のオプションで指定する。

ant というか、宣言的なスタイルで記述する言語は、「属性」を詳細に記述する ( WHAT を宣言する )。
動作、処理手順とかの HOW は、自分では書かないのが基本。

WHAT を厳密に書く。
HOW は書かない。

<echo> タスクより、name属性、description属性を使う発想にシフトするのが「宣言的スタイル」で書くということ。

条件分岐も、<condition>タスクと if 属性でがんばるコードを時々見かける。

target の depends 属性を使える場所でも、if 属性使いたいがるのは、相当な重症。

モデル駆動設計的にいうと、ant の設計は、処理フロー図ではなく、コンポーネント図の世界。
振舞設計ではなく、「構造」の設計をする。

コンポーネント( target ) を洗い出す。
その依存関係を静的に宣言する。

処理の手順の設計・実装ではないんです。

手続き型から、宣言型への発想の切り替えの訓練には、ant は、なかなか良いネタだと思っている。

フレームワークの設定ファイル


最近は、いろいろなフレームワークがあって、多くは、構成定義などを、XML で記述するようになっている。

こういう構成ファイルを、きちんと理解して、書くのも、「宣言的スタイル」の良いトレーニングになりますね。

やってもらうと「なにがなんでも手続き派」がいて、if 文的な書き方ができる機能を見つけると、それにとことん執着する。ちょっとびっくりするくらい、手続き的に書くための機能やサンプルを見つけてくる。

あと、XML要素を記述する「順番」を「(自分の想像する)処理の順番」と一致させたがる。
XML 記述は、記述する順番には影響されない、という基本が、理解できていない。

そういう人は、XML ファイルの分割も苦手ですね。
宣言を部品化して外だし、という発想ではなく、「サブルーチンコール」イメージなんで、ファイルを分割する単位が見えないですよね。
XML 記述は、手続きを書いているのではない。だから、「手続きの切れ目」とか、そもそもない。だけど、頭は、「手続き指向」だから、分割の切れ目探しに四苦八苦することになる。

バランスとろう


力のある技術者は、だいたいが、命令型の記述のスキルが高い。if や for を使ったフローの制御も、ちょっと複雑でも、さらっと読めちゃうし、かけちゃう。

それはそれで、いいんだけど、SQL や XML 書くときまで、なんでも、命令型にしか、書かない/書けないというのは、スキル、発想のバランスを欠いている。

命令型と宣言型の発想・スキルを、バランスよく持って、臨機応変、適材適所で使い分けるのが、レベルの高いエンジニア、ということなんだと思います。

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