システムのデッサン : レイアウトをちゃんと考える

システムをデッサン(素描)する時の、基本ダイアグラムは、

■振る舞い系
コンテキスト図(概要のユースケースモデル)
アクティビティ図(業務プロセスとプロセス間のやり取り)

■構造系
概念モデル(概要のクラス図、パッケージ図)
配置モデル

などがある。

振る舞い系のレイアウト


振る舞い系は、基本的に、時間の経過とともに、振る舞いが変化することを表現している。

だから、レイアウトの基本は、時間の流れ順。

・上から下へ
・左から右へ

が普通のレイアウト。

ユースケースモデルであれば、アクタの登場順、ユースケースの発生順が基本のレイアウト。

アクティビティ図も同じですね。

システム全体のデッサンよりも詳細な設計用のダイアグラムだけど、ロバストネス図、ステートマシン図、シーケンス図なども、振る舞い系のダイアグラム。

基本のレイアウトは、時間順に、上から下、左から右。

これ、あたりまえのようで、描いているうちにいいかげんになることが結構ある。

特に、システムの全体像をデッサンしているときは、基本要素を発見したり、入れ替えたりしているうちに、レイアウトが時間軸じゃなくなることも多い。

図法として、振る舞いは、時間軸が基本レイアウト、という原則は、みんなで意識しておいたほうが、図を描いたり、レビューする時に、楽になるし、つまらない誤解も減るはず。

構造系のレイアウト


構造系のクラス図やパッケージ図のレイアウトは、私は、ドメイン駆動設計(DDD:Domain-Driven Design) の、Responsibility Layers パターンを基本にしている。

基本は、3段構成。

いちばん下が「リソース」あるいは「ポテンシャル」レイヤ。
「商品」とか「顧客」とか「店舗」とかのクラス(概念)が並ぶ。
ここのレイヤのクラスは、追加や変更は発生するが、それほど、頻繁ではない。

真ん中は、オペレーションレイヤ。
ビジネスのオペレーションのイベントと、それに伴う、状態(ステート)の変化を表現するためのクラス(概念)が並ぶ。

「受注」「出荷」「請求」「入金」などのイベントと、そのイベントが発生した時に、更新しておかなければいけない、注文ステータスとか、入金ステータス。

ここは、頻繁に追加・更新が発生する。

いちばん上が、ポリシーレイヤ。
業務を遂行するための規則や約束事を表現するクラス(概念)群を集める。

「価格ポリシー」、「キャンセルポリシー」、「契約」、「予定」など。

レイヤ構造なので、上のクラスが下のクラスを参照する、のが基本構造になる。

左右のレイアウトについては、問題領域によるけれど、私の場合は、

・左から右へ、時系列に(特にオペレーションレイヤのイベント)

を基本にしている。

配置図など、システム的な構造図についても、依存関係を基本に考えている。
もっと具体的にいうと、サーバーの終了・起動の順番を考えている。

上のほうのサーバーは、下のほうのサーバーを意識せずに、任意に終了・起動できる。

下のほうのサーバーを停止するには、まず、上のサーバーを停止する。

アプリケーションサーバーが上、データベースサーバーが下、ということ。

モデルとコード



こういうレイアウトの原則は、システムの全体像を考えたり、議論するときの便利な道具になる。

対象業務やシステム構成について、どのように理解しているかの、認識の違いを発見しやすくなる。

表面的には、同じ図でも、時間軸やレスポンシビリティによる構造を意識して描くのと描かないのは大違い。

私の経験では、図を描くのを時間のムダという人にかぎって、図の表現方法、図法に無頓着な人が多い。

私は、文章や図を論理的に書くスキル、あるいは「書こうとする」マインドは、よいプログラムコードを書くスキル・マインドと連動していると思っている。

コードがちゃんと書ける人は、文章や図も論理的にかけるはず。
文章や図を論理的に書く人は、コードも論理的にかけるはず。

システムのデッサン<実践編> 視点を定める

デッサンの「視点」は、ぶれちゃいけない


まずいデッサンのひとつに、視点がぶれまくったデッサンがある。

たとえば、自動車をデッサンするときに、視点を、

・右ななめ前方45度
・5メートル離れて
・立った時の目の高さ(少し見下ろす高さ)

に定めたとする。

ところが、デッサンをしていくうちに、たとえば

・もっと右よりの視点
・もっと下の視点
・もっと近づいた視点

から見た内容も、いっしょに描いてしまう。

結果として、デッサンがだいぶ狂った絵になる。

視点がぶれたデッサンと、視点がしっかりしたデッサンは、自動車であれば、おそらく素人でも区別がつきそう。

システムのデッサンの場合は、視点がぶれているかどうかの判断は、素人はおろか、システム設計を職業としている私たちでさえ、たぶん、意見が一致しない。
(あまりにひどいものは別でしょうが)

こういう基礎的な設計技法すら、確立していない状況を悲観していてもしょうがないので、これからのどんどん発展可能、と前向きにとらえて、勉強したり、考えたことを、発信していきたいと思っている。

システムデッサンの視点(案)



車とか、物理的な存在であれば、視点は、前後・左右・上下の3つの軸(6方向)のどこかに、具体的に設定できる。

システムの場合、まず、この視点を定める軸がはっきりしない。

視点を定める軸が、共通理解になれば、ある程度、デッサンの基礎を固めることができそうな気がする。

「システム構築のアーキテクチャの原理」とか RUP (だったかな?) 4+1 ビューとかを参考に、私の考える、6つの方向(視点の設定軸)

(1)機能 : システムが果たすべき役割(目的、価値)
(2)情報 : システムが扱う情報
(3)並行性: 並行して行われる業務プロセスと業務プロセス間の通信
(4)開発 : モジュール構成、設計規約、コーディング規約
(5)配置 : ハードやミドルウェア
(6)運用 : 移行、監視、ユーザサポート、障害対策と対応

6つの視点を同時に描けるわけではないので、いくつかの視点ごとに、デッサンすることになる。

もっとも単純なのは、それぞれの設定軸ごとに、6つ描くこと。
でもこれだと、それぞれは、平面的な像になってしまう。

今、模索しているのは、いくつかの定番的な視点設定をすること。

たとえば、

A.機能中心で、情報と並行性が視野に入る角度
B.情報中心で、機能と並行性が視野に入る角度
C.配置中心で、運用と開発が視野に入る角度
D.開発中心で、機能と情報が視野に入る角度

みたいな感じ。(まだ、思いつきレベル)

あとは、距離感。
デッサンで、どの程度、詳細に描くかということ。

ひとつのデッサンは、A4一枚で描ける内容が良いと思っています。

上記の4つの角度で、それぞれA4一枚、都合、4枚を描くところからはじめる。

この記述レベルだと、要点とか、全体の輪郭が大切。
詳細とかは、別の方法で、記述することになる。

要点や輪郭の描き方については、別の記事であらためて書こうと思っています。

----------------------------------
それぞれの角度からのデッサンの仕方
----------------------------------

機能中心で、情報と並行性が視野に入る角度



図柄としては、コンテキスト図ですね。
コンテキスト図については、前に書いた、コンテキストのモデリング を参考にしてください。

機能は、別の言い方をすると、

・システムの果たすべき役割
・システムの目的
・システムの価値

です。

関係者が「価値があること」と認めるものは何か?という設問への答えが、「機能」なんだと思います。

私が最近、やっている人材募集分野のシステムだと、

(求職者が)仕事を探して、応募して、就職できるシステム
(求人企業が)人材を募集して、採用できるシステム

が、システムの基本機能になる。

もちろん、もうちょっと、具体的な価値の議論が必要。

・どういうふうに仕事が探せると価値があるのか?
・どういう募集ができると価値があるのか?

などですね。

コンテキストモデリングで最初にやるのは、「価値を判断する登場人物たち」、つまり、アクターを描くこと。

あとは、今回開発の対象とするシステムの機能機能(基本ユースケース)をいくつかと、価値(新システムができること)に大きく影響する、外部システムをあらいだす。

この「機能」の目線を中心にして、「情報」と「並行性」も視野に入れてデッサンする。

「情報」は、機能の記述の中に、目的語的に、自然に登場してくる。
それ以上は、この角度からは追わない。(視点がぶれないように)

情報中心の別の視点(後述)で、追いかけるようにする。

並行性については、コンテキスト図で比較的はっきり見える部分と、コンテキスト図では埋もれてしまう部分がある。

・はっきり見える部分

アクター間、外部システム間、外部システムと本システム間が並行動作した時の、同期の必要性。

コンテキスト図では、関連線で、同期(通信)の必要性が示唆される。

・はっきり見えない部分

アクタとして抽象化された役割の実体が複数いて、同時に作業する場合。
この場合、アクタどうしで通信(同期)が重要なのであれば、おそらく、別のアクタとして描き直して、関連線として、明示すべきかもしれない。

たとえば、求人情報の登録や取り下げが、本社の人事部でも、店舗の店長でもできる、というようなケース。 なんらかの同期(通信)が必要。

もっとミクロのレベルでは、本社人事部の担当者同士の同期というような課題もでてくるけど、A4一枚のデッサンで描くべきテーマではない。
(もちろん、設計の過程で、明示すべきテーマ)

情報中心で、機能と並行性が視野に入る角度


概念モデルですね。

私は、概念モデルは、絵柄としては、クラス図よりも、パッケージ図を描くようにしている。

たとえば、顧客クラスと商品クラスではなく、顧客パッケージと商品パッケージ、という感じ。

顧客という概念を分析していくと、その中に、より詳細な情報が登場する。
だから、初期のデッサンでは、情報をいきなりクラスとして表現するより、「情報の入れ物=パッケージ」として、表現して、だんだん、入れ物の中を増やしていく感じで描くスタイルが、実践的だと思っている。

概念モデルは(絵柄はクラス図でも)、クラスモデルでもデータモデルでもなく、概念のモデル。

関心のある情報の「名前」の列挙、という感じですね。
概念モデルが、次のステップでは、クラスモデルとデータモデルに分かれて発展していくことになる。

もちろん、クラスモデルと、データモデル間のマッピングも重要な課題。

よくあるのが、既存のデータベースがある場合。
こういう場合は、テーブル定義を単にリバースエンジニアリングするだけでなく、概念モデルに整理しなおすとよい。

既存の、現実のテーブル定義は、業務の概念(関心事)を適切に表現していることは、きわめて少ないので、概念モデルとデータモデルはまったく別、と考えていたほうがまちがいがない。

情報中心の角度(概念モデル)では、「機能」や「並行性」も、「情報」(概念)として描く。

・機能を実現するのに必要な情報
・並行性を実現するのに必要な情報

こういうことを視野に入れて、関心のある情報は何か?への答えを描いていくのが概念モデル。

配置中心で、運用と開発が視野に入る角度


絵柄としては、もちろん配置図。

配置図は、まずは、「稼働中」の狭い視野で描く。

それから、

・移行の対象になるのは?
・更新の対象になるのは?
・依存関係は?(ノードの停止・起動の順番は?)

という視野を広げて、記述を膨らませる。

基本の目線は、あくまでも、「稼働中」の配置。
ただ、それだけだと、ある一瞬のシステム構成のスナップショットでしかない。

システムの構成は、初期の構築、移行、アプリケーションの更新、ハードやミドルウェアの更新などで、刻々と変化していくもの。

それを、ある一瞬を切り取った静的な視点で描くだけでは不十分。

実際の書き方としては、稼働中を目線にした配置図に、構成が変化するという目線で、気になることを、ノートで追記していくようにしている。

もちろん、A4一枚のデッサンなので、描くべき内容は、要点と、輪郭だけにすることがポイント。

開発中心で、機能と情報が視野に入る角度


開発者の視点なので、開発者は、自分の関心事を、並べ立てれればよい?

まあ、そのはずなんだけど、実際には、開発者に、開発者の視点で、A4一枚でシステムをデッサンしてもらうと、稚拙な絵がでてくることが多い。

簡単にいうと、

・視野が極端に狭い
・視野が極端に偏っている

絵がでてくる。

もっとも、ある程度の開発者であれば、システムがわかっていないわけじゃなくて、絵にするテクニックが未熟なだけ。

テクニックさえ覚えれば、開発者にとって、この角度からシステムをデッサンすることは、そんなに難しいことではない。

基本テクニックは、とても簡単。

コンポーネント図とパッケージ図を描くこと。
クラス図とか、個別のクラス名がでてくるレベルの絵を書いちゃいけない。

ここは、テクニックというより、発想の違いかもしれない。

狭い視野だと、自分が開発しているのは、クラスであり、ここの定義ファイル。
つまり、エディタで開いて編集しているものが、自分の開発対象。

オープンソースのフレームワークを使う場合も、狭い視野だと、使用する個別のクラスやAPIが関心事。

そうではなくて、 jar 単位とか、パッケージ単位で、ものごとを考えるようにする。

そういう発想さえ持てれば、システムの全体像を、コンポーネント図とパッケージ図で描くことはそう、むずかしいことではない。

A4一枚で描く内容の粒度・詳細ささえ、コツがのみこめれば、簡単なはず。

おっと、忘れてはいけない重要なポイントがある。

開発者の目線を中心にするけど、かならず、「機能(目的、価値)」と「(関心のある)情報」という視野まで広げること。

そうしないと、ほんとうに技術的な関心事だけがならんだ、ふくらみのない絵しかでてこない。

車の例でいうと、真下から、ボディの裏だけを、平面的な描いたような絵になる。
(技術オタクであれば、これでも、とっても興味深い絵なんだろうけど)

機能目線からのデッサンの中心課題、情報目線からのデッサンの中心課題。

それらが、開発者目線のデッサンの、一部として登場しなきゃいけない。

もちろん、中心目線は、開発者の関心事、技術テーマ。
ただし、その周辺には、きちんと、機能と情報についての用語を使うこと。

基礎のスキルを磨く


いちばん、いいのは、これが良いデッサンです、というのを、まず、お手本にすることだと思う。

思うが、「これが良いデッサンです」というのが、あれば苦労しない。

人様に、威張って、お見せできるものではないけど、このブログでは、できるだけ、実際のデッサンを発信していけたらいいなと思っている。

お互いのデッサンを見せ合うことで、得るものもあるだろうから。

「仕事」を探す、URI 設計。 qeury 文字列方式は使わないぞ!

採用支援サイトの設計で、仕事を探す、検索機能の URI 設計を、やってみた。
基本は、「 query 文字列を使わない URI 設計 」のこころみ。

主に参考にした本は、

・Restful Web サービス
・Web を支える技術

実装技術としては、Spring 3 MVC の URI テンプレート機能を使う。 モデリングといいながら、@Controller の @RequestMapping の実装コードを、かなり意識している。

モデルとコードは、コインの表と裏のように結びついているし、距離も近いもの、という主義なので、だいたいこんな感じ。 Enterprise Architect で、 UML 風の絵を描きながら、頭の中は、結構、コードが飛び交っている。

基本の階層


求人案件の基本の分類整理軸は、悩ましい問題。
求人サイトでわりと多いのが、職種分類の階層。

http://example.com/job/{職種の大分類名}/{中分類名}/{小分類名}/{募集案件名}

(以下、http://example.com は省略)
( {パス要素} という記法は、Spring 3 MVC の URI テンプレートの {RequestVariable} の記法を使っている。)

例えば、

/job/クリエィティブ/web関連/webデザイナー/ソーシャルゲームのグラフィックデザイナ

という感じ。

下位のパス要素を記述しない場合は、

/job/ だけなら、職種の大分類の一覧
/job/クリティティブ/ なら、職種の中分類の一覧
...

という感じで、より、特定の仕事リソースに近づいていく。

画面でいえば、仕事リソースは、仕事の詳細表示画面で、そこで表示するパン屑リストが、この URI そのまま、という感じ。

リソースの一意識別


実際には、上記の「ソーシャルゲームのグラフィックデザイナ」の求人案件は、この URI では、一意に識別できない。

同じ職種名の案件が他にもある可能性がある。
かといって、職種名の下に、さらに階層があるかというと、ちょっと違う感じ。
職種名は、求人企業が任意に指定しているので、それが、分類の階層構造の一部というのは、たぶん、モデルとしてまちがい。

いちおう、今の設計案は、

/job/クリエィティブ/web関連/webデザイナー/ソーシャルゲームのグラフィックデザイナ.2996411

というように、最後の要素は、

{募集案件名}.{案件管理番号}

にしようと思っている。

RequestMapping のほうは、 /job/{zone}/{segment}/{category}/{jobtitle}.{id} と記述しておけば、それぞれのパス要素を、その変数名で簡単に取り出せる。

かなり乱暴だけど、

/job/*/*/*/*.{id} というマッチングで、 id だけ変数として、コントローラで処理することもできる。

ここらへの実装上の記法は、まだ、トライアル段階のところがあって、どう記述するか、手探り。

基本的には、いろいろな URI テンプレートののリストを、Spring が、 パターンマッチングをして、「特定できる順」に、一致させてくれるはず。

ただ、パターンを駆使して、解決をフレームワークにまかせる記法は、あいまいだったり、トリッキーで、障害の種だし、また、可読性も悪く、変更の副作用が怖い。

だから、できるだけ、明示的に書くことを重視しようと思っている。
( 変数として未使用でも、 * ではなく、{zone} のように、明示しようということ)

リソースの複数の分類体系


仕事は、データベース上では、実は、求人企業を親として、その下にぶら下がっている。
上記の、職種分類体系で、整理して持ているわけではない。

データベース上の構造をそのまま素直に URI にすると、

/job/{求人企業}/{求人案件名}.{求人番号}

になる。

ここで、第一階層の要素が、/job/ だと、さっきの、職種分類の /job/ と同じになってしまう。
複数のパス階層が並立する場合には、 /job/ だけでは、まずい。

で、考えたのが、

職種分類の階層は、 /job-category/
企業を親にする階層は、/company/

というように、使い分けることにした。

http://jobs.example.com/job-category/{zone}/{segment}

というように job は、サブドメインに持っていった。
仕事を探すサイト、が明確になったので、こっちのほうが、適切。

job-category とか、company とか、検索の切り口を、サブドメインにしてしまう、というのもちょっと考えた。

ただ、サイトとして、job-category.example.com だと、(政府の統計局とかの)、職種分類体系の検索サイトのような意味になりそう。 仕事を探す、というシンプルな目的とは、ちょっとずれる感じ。

company.example.com だと、さらにはっきりして、これだと、仕事探しではなく、企業情報リソース満載のサイト、という感じ。

というわけで、検索の視点の違いを、サブドメインで分けるのは、却下。
( Spring の URI テンプレートで、サブドメインの違いで処理を分けるというは、実装がややこしくなる、という実装面の問題もある)

ナビゲーションモデル


/company/{企業名}/{募集案件名}.{案件管理番号}

これは、データベースの構造のまま。
実際には、求職者向けのサービスとしては、こういう構造では提供していない。

/company/ で、ずらっと、求人企業が並ぶ。そこから、特定企業を選ぶと、
/company/Example株式会社/ というURIがリクエストされ、その企業の求人案件が並ぶ。

という画面は、普通なない。

/industory/{業種}/{企業名}/{募集案件名}.{案件管理番号}

というような感じで、「業種」から、企業を探す、というのがありそう。

あとは、

/area/{地域}/{都道府県}/{市区町村}

という勤務地を軸にした体系もありそう。

ナビゲーションの切り口は、職種分類、業種・企業、勤務地など、複数ある。
URI もそれぞれに応じた、体系にする。

ただし、最後の {募集案件名}.{案件管理番号} は、実体は一つにしておきたい。
同じ仕事(リソース)に、URI (一意識別情報) が複数あるのはおかしいでしょう、という、そもそも論。

実際には、一覧表示画面に、返す 正式(?)のURI は、

/company/{企業名}/{募集案件名}.{案件管理番号}

に統一しようと思っている。

/area/{地域}/{都道府県}/{市区町村}

のリクエストに対するレスポンス(リソース表現)は、 /company/{企業名}/{募集案件名}.{案件管理番号} のリストになる、ということ。

もうひとつの方法として、レスポンスは、

/area/{地域}/{都道府県}/{市区町村}/{募集案件名}.{案件管理番号}

という URI のリストにして、 この URI を受けとった、コントローラで、

/company/{企業名}/{募集案件名}.{案件管理番号}

に リダイレクトさせる、という方法も考えている。

ここらへんも、どちらが、より、開発しやすく、変更に強いか、という、現場での検討・評価が、まだなので、これから考えていこうと思っている。

後者のリダイレクト方式のほうが、意味的には、わかりやすいかなあ?

複合検索条件


今までの内容は、ツリー構造の分類体系を辿るパターン。

実際には、キーワード検索とか、複合条件の絞り込みとか、いろいろでてくる。
まだ、設計が固まっているわけではないけど、ワード検索だったら、

/keyword/{ワード}

とかにしようと思っている。

/keyword/ だけだと、検索キーワードが人気順にでてくる?

あるいは、

/keyword.10/ という URI で、上位の10件を表示、というような方向。

複合条件のほうは、セミコロンを使った、マトリクス指向の URI にしようと思っている。

首都圏の web デザイナーの仕事、月給は、月30万円以上、とかであれば、

/job/zone=首都圏;jobtype=webデザイナー;earnings=月30万円-

という感じ。 
最後の ハイフンは、範囲指定の常套(?)手段。 この場合は、下限だけ指定している。

spring 3 MVC のフレームワークがあって、spring エキスパートがいるので、このような URI の解析もさらっと実装してくれる(はず)。

そう思いこんで、私が、勝手に、こういう設計を先走っている。
(アンチパターンですね。危険ですね。設計は、関係者で、しょっちゅう、雑談的に意見交換することがたいせつ)

まあ、最悪、 ここらへんは、query 文字列方式に戻ればよい、という、リスク管理(?)をしながらやっているつもり。

いけそうかな?


現在の採用支援サイトの企画内容だと、こんな感じの URI 設計で、いけそうな気がしてきているところ。
今日一日で、がーっとやった仕事なので、ちょっと怪しいけど。
(でも、この日のために、前から URI 設計ネタはいろいろ仕込んできたつもり)

あとは、もっと具体的な仕事探しの機能と、実装技術で、この設計方針を確認しながら、成長させていこうと思っている。

今のところ、URI の要素には、積極的に日本語を使いたいと思っている。
「名前でリソースを表現する」には、やはり日本語が一番だから。

エンコーディングの関係で、問題がでるかあな? これも、早めに実験してつぶしておきたいリスク。

SEO 的には、こういう URI 設計、プラス効果があるのかな?
query 文字列方式は不利、という話は聞いたことがあるので、query 文字列なしのこっちの方式のほうが、よさげな気がするが、SEO は、門外漢なので、わかりません。 専門家に一度、相談しようと思っている。

あたかも静的ページがあるかのように、分類ツリーを網羅したサイトマップとかは、分類マスターから、簡単に自動生成できそうだな。
これは、素人考えでは、 SEO 的に意味がある気がする。
ロボットからみたら、大量の、完全に静的なページのツリー構造なので、query 方式よりも、検索の対象にうまくなってくれそうな気がする。
もちろん、これも、 SEO の専門家のアドバイス待ち。

リソース指向は面白い


もともと、自分は、データベース屋あがりなので、リソース指向は感覚的にあっている気がする。
CRUD と、 PUT/POST/GET/DELET とかは意味が違うけど、「定義済の少数の操作セット」という思想は、まったく同じ。

ただ、ちょっと前までは、 リソース指向の URI が良いな、と思っていても、実装のことを考えると、ちょっとなあ、と思っていた。

Spring 3 MVC で、REST スタイルがかなり実装しやすくなったのが、大きな転機。
URI をリソース指向でちゃんと設計すれば、それを、素直に、簡単に(?)、実装できそうな気がしている。

まあ、いつものことだけど、自分たちにとっては、初物で、実証済、経験済の技術ではないので、やってみると、いろいろあるとは思う。

でも、なんとなく、今回は、ちょっとしたターニングポイントの臭いがしている。
自分の勘が、どこかで、そういっている。

ドメインモデル貧血症

ドメインモデル貧血症をもう一度、考えてみる。

まず、ドメインのオブジェクトとその関連が、きちんと設計されていることが前提。
問題領域の言葉がそのままドメインクラス名になっている。言葉と言葉の関連も、きちんとモデリングされ、Java の参照や、SQL文として実装されている。

少なくとも「情報」とその関連を、きちんと分析して実装していることが、議論の大前提になっている。

ドメインモデルもなければ、ドメイン層もない設計は、そもそも議論の対象外。

貧血症かどうかは、振る舞いの問題。ドメインクラスが、どんなメソッドを実装しているかが、病状の診断基準というわけだ。

代表的なのが、validateion のロジックの置き場所。

Validator クラスに外出しする設計なら、貧血症。
ドメインクラスが、validate() メソッドを実装していれば、ドメインリッチ。

parse() や format() を外出しにしているのも、典型的な貧血症。
Java の Date クラスなんかが典型ですね。DateFormat クラスがわざわざ別にある。

ドメインリッチの良い例が InternetAddress クラス。
インターネットのメールアドレスに関する知識を豊富に実装しているから、ドメインリッチ。

・形式が、RFC822 に適合しているかをチェックする validate() メソッド。
・複数のアドレスの文字列表現を読み取る parse() メソッド。
・RFC822 準拠の形式で、 unicode 文字列で表現するための フォーマットメソッド。

InternetAddress クラスが、メールアドレスに関する豊かな知識の置き場所になっている。

住所の PostalAddress クラスとか、電話番号の PhoneNumber クラスとか、同じようなネタはいっぱいありますよね。 住所についての知識、電話番号に関する知識を、同じクラスのメソッドに実装するのが、ドメインリッチな設計。

Money クラスも、値を持つだけでなく、千円単位とか百万円単位とかの表現の知識を、 parse() と format()で実装する。

もちろん、金額計算も、add() とか、multiply() とかを実装する。 BigDecimal よりも、Money のほうが、ずっと、ドメイン駆動のオブジェクトになる。

ここらへんのドメインリッチの感覚をチームで共有すれば、ドメインクラスの設計が見違えるほどドメイン駆動になる。

とりあえず、validate() 、parse(), format() メソッドあたりから始めると、わかりやすいのかな?

XP で、XML やテーブルはどうなるんだ?

最近、私が関わっているシステムは、外部システムとの連携が重要課題。
実装技術は、 XML over HTTP 、まあ、単純に XMLファイルを HTTP で送ったり、受信する。

ドメインモデルを元に、

・ Java
・ XML
・ テーブル

を設計して、実装している。 Java と テーブル定義のDDL は、モデルからコード生成している。
XML は、モデルを参考に、直接コーディング。(ちょっと怪しい)

モデルがあって、複数の言語で、実装する、というのは教科書的(?)にはとても正しい。

で、ふと思ったのが、XP では、どうやっているんだろう。
あるいは、テスト駆動開発でも良いのかな?

まわりに、実践している人がいないので、本やインターネットの情報から推測するしかないんだけど、テスト駆動で、Java のクラスを作るのはなんとなくわかるけど、XML定義や、テーブル定義は、いったいどうやっているんだろう。

Java のソースコードが設計で、それを元に、XML定義やテーブル定義をやるの?
なんかちがう気がする。

大きな一枚岩のクラス vs. 小さなクラスのチーム

大きな一枚岩のクラスと小さなクラスのチーム


一つの大きなクラスにまとめるか、情報をもうちょっとグループ分けして、小さなクラスに分けるか?

ドメイン駆動設計は「小さなクラス」に分ける。

いや、ドメイン駆動設計だけじゃない。オブジェクト指向設計では、というか、ソフトウェアの設計の基本原則が、関心事の分離。とにかく分ける。

左は、大きな一枚岩の会員クラス。

会員を識別する情報(Entity) 、連絡するときの情報(Value)、住所の情報( Value ) という三つの関心を一つのクラスに押し込でいる。
典型的なアンチパターン。
「会員に関連する」というだけで、会員がらみの情報(属性)がこの入れ物に次々と追加され、肥大化していく。
検証ロジックや分類ロジックも膨らんできて、あっというまに見通しの悪い密林クラスの誕生。


右は、小さなクラスに分けて、それを1チームとして連携するパターン。
これだと、住所の持ち方や使い方を考えるときに、連絡先とか、会員番号とかの心配をしなくて良い。
ロジックも、住所に関するロジック、連絡先に関するロジックと、自然に分割整理できる。
図ではクラスにしていないけど、電話番号とか、Eメールアドレスも当然クラスです。( String 型ではなく、EmailAddress 型とか PhoneNumber 型 )

電話番号の入力形式や、表示形式の知識は、PhoneNumber クラスの parse() メソッドや、format() メソッドに収める。

で、これらの小さなクラスが集まって、「会員」を表現していることを、関連でモデリングする。

一枚岩のクラスよりも、豊かにドメイン知識を議論して、モデリングできる。

ドメイン駆動設計の第一歩や、こうやって、関心事ごとにクラスを分ける。関係する事柄は、関連で明示すること。

画面では、だいたい、小さなクラスの単位で、枠線を引いたり、背景色を工夫して、情報のグルーピングを明示していますよね。
その表示の構造と、クラスで表現する構造は一致しているべきなんです。

とても、簡単なことなんだけど、私にとっては、実はコペルニクス的転換というか、大きなパラダイムシフトでした。大きな一枚岩クラスでテーブルやクラスを作ることが当たり前だと思っていた。
小さく分割する、という選択肢はまったく持っていないかった。

分割することに慣れちゃうと、とても、昔の大きな一枚岩クラスにもどれないです。
問題を、小さな単位に分割すると、一見、面倒なようで、実際は、とても楽になる。

小さな問題は、すぐ解決できちゃうので、気が付くと、たくさんの問題を短時間に解決できちゃう、ということを何度も経験している。
関心事の分離は、問題解決のちょっとしたマジックです。


ドメイン駆動設計・開発の実践

InfoQ に最近掲載されたドメイン駆動設計の記事。

ドメイン駆動設計・開発の実践

記事の内容は、実際の開発プロジェクトで、ドメイン駆動設計を採用する場合の、さまざまな課題、パターン、アンチパターンを取り上げている。

主に、プロジェクトの技術リーダーやアーキテクト向けの内容。

・ドメイン駆動設計のアーキテクチャスタイル、デザインパターン
・コードの自動生成、リファクタリング
・テストの自動化
・継続的インテグレーション
・配置とリリース
・モデルの改良サイクル

・アジャイルな開発のやり方
...

Domain-Driven Design 自体は、モデリングの考え方、やり方にフォーカスしている。
この記事は、その外側にある、さまざまな現実の開発プロジェクトの課題を具体的に取り上げている。

また、アーキテクチャについても

・永続化
・キャッシング
・トランザクション管理
・セキュリティ

など、本格的なアプリケーションでは必ずおきる問題も取り上げている。

あと、Spring フレームワークなどを活用した Java ベースの本格的なソースコードをダウンロードできる。
Spring, Dozer, Spring Security, JAXB, Arid POJOs, Spring Dynamic Modules, Hibernate, ... とまあ、いろいろ駆使している。

ダウンロードはしたけど、さて、この忙しい時に、手を出すか、どうか、まよっている。面白そうなんだけど、はまってしまいそう。


昔は、DOA。今は、ROA。

DOA:データ指向アプローチ

最初にモデリングを覚えたころは、DOA ( Data Oriented Approach :データ指向アプローチ )。
T字型ERモデルなんかもちょっとはまっていた。

当時は、Oracle でコンサルタントで、Oracle データベースと、Oracle Developer2000 を使って開発。

Oracle の場合は、 DOA といっても、 Database Oriented Approach 、つまり、すべてデータベースを中心に考える設計思想。

テーブルを設計して、データ型や参照制約、必須属性などを綿密に宣言しておく。
そうすると、画面は、データベース定義内容からリバースエンジニアリングで生成できちゃう。

ドロップダウンリストなんかも、まず、テーブルを設計して、開発ツールで、テーブル名や Select 文を定義すると、できあがり、という感じ。

すべての情報操作は、テーブルに対する CRUD である、というのが基本思想。

ROA:リソース指向アプローチ

自然な流れというか、今は、ROAにどっぷり。
リソースはテーブルだけでなく、HTMLドキュメント、XMLドキュメント、さまざまなファイル、などなど。

メソッド名は CRUD とは似た感じで、

GET
PUT
POST
DELETE

の4つが基本。

ROA の場合、 新規作成は、PUT と POST がある。

PUT は、識別番号を、リソースを送る側が指定して新規作成。
POST は、リソースを受け取った側が、識別番号を発番して、新規作成。

データベースでも、一意識別キーは、重要な関心ごとだけど、一意識別番号の出所や管理責任は、実はあいまい。アプリケーションまかせ。

ROA の PUT と POST の使い分けのほうが、ドメインのモデルの枠組みとしては、進歩していると思う。

オブジェクト指向

DOA や ROA は、ドメイン駆動設計とは相性が良いと思う。

ドメインのオブジェクト、たとえば、customer や product を、

DOA : customer テーブル、 product テーブル
ROA : http://business.com/customer/1012, http://business.com/product/2546

てな感じで実装する。

DOA のテーブルや ROA のリソースは、振る舞いのない、静的な情報なので、オブジェクト指向とはいえないけど、ドメイン駆動設計のリポジトリの実装には、ぴったりとはまってくるわけです。

ドメイン駆動設計とは要求開発である

ドメイン駆動設計では、反復的に、インクリメンタルに、ドメインの知識を掘り下げて、洗練させていく。

問題領域の専門家と、開発者が、同じ言語を使って、コミュニケーションしながら、その言語を使って、設計して、その言語でそのまま実装する。(ユビキタス言語)

伝統的なやり方だと、プロジェクトの前半は、要求仕様の定義と固定。後半は、実装とテスト。

ドメイン駆動設計が前提にしているアジャイルなやり方はこうではない。

毎日が、要求仕様の検討であり、設計であり、実装とテストでもある。少なくもと、週に一回くらいは、デモできるバージョンをリリースする。

これを毎日、毎週、繰り返しながら、要求を掘り下げていき、また、実装を洗練させていく。

確立した要求は無い。最初から無いし、最後まで確定しない。
あるバージョンが完成したら、それ自身が、改良と発展の土台になり、新たな出発点。

モデリング、設計、実装をなんどを繰り返しながら、真の要求を具体的に発見していく。

「要求」とは、事前に確定して、ドキュメント化されたものではなく、問題領域の専門家、利用者、開発者がひとつのチームで対話をしながら、生み出していくもの。

チームが開発しているのは、プログラムやデータベースだけではなく「要求」そのものをいっしょに開発している。

ドメインオブジェクトのモデリング・設計とは、まさに要件定義の作業だということ。

こういうやり方が、どんな案件でも最善とは限らない。

でも、私が参加している
・ビジネスモデル、成功パターンをいつも模索し続けているベンチャー系の企業
・インターネットでのサービス提供を本業としてしている企業
の案件の場合、要求を開発しながら、ソフトウェアを開発する、というのが、本流だし、それしか、選択肢はない。

関連の設計と実装

Domain-Driven Design の5章で、モデリングの基本ツールとして、関連を取り上げている。

パターンとしてカタログに一部になっていないけど、モデリングの基本事項は、まず、関連の説明から始まっています。

簡単に言えば、できるだけ関連を描かないのが基本思想。

・ほんとうに関心ごとの関連だけを描く
・双方向より単方向にする
・1:N 関連より、1:1 関連にする ( 限定子 )
...

こうすることで、関連モデリングが、ドメインの知識を豊かに表す手段になる。

モデルを実装する方法、設計についてもいろいろ興味深い議論が書かれている。

単方向の実装は、set への参照。まあ、これは自然ですね。
限定子を使ったら、 Map への参照。 Key で一意に特定するんだから、実装は、Map だということですね。
SQL で実装という選択肢も、検討している。

ここらへんの議論は、Fowler も、いろいろ取り上げている。

・アナリシスパターンの 14.1 関連の実装 ( Implementing Associations )
・PoEAA の 12章 オブジェクトリレーショナル構造パターン

クラス図では、箱と箱をつなぐ単純な線だけど、一本の線の引き方で、クラスの設計、テーブルの設計、SQLの設計と、さまざまな課題がでてくる。

基本は、ドメインの構造を、できるだけ素直に実装するのが正解(のはず)。
ただ、システムの規模が膨らんで、データ量や同時並行処理などの問題が大きくなると、性能やロックの問題も含めて、かなり厄介な設計問題になる。

でも、Evans のドメイン駆動設計での説明を読んでいると、ドメイン側の要求でもないのに、不必要に、実装を複雑にしたり、重くしてきたことに気づかされた。

関連を丁寧に分析・モデリングする。
重要な関心ごとの関連だけに集中する。
関連の実装パターン(基本パターン)を忠実に採用する。

ことで、問題はだいぶ改善しそうです。

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