「仕事」を探す、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 をリソース指向でちゃんと設計すれば、それを、素直に、簡単に(?)、実装できそうな気がしている。

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

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

RDRA リレーションシップ駆動分析から、いよいよ実装へ

求人と採用支援システムの開発案件で、3週間ほどかけて、基本的な要件を定義してきた。

基本の手法は、RDRA ( リレーションシップ駆動分析 )。
モデリングツールとして、Enterprise Architect 、コミュニケーションツールとして、オンラインは、37 signals のベースキャンプ、オフラインは、もちろん、ホワイトボード。

簡単な振り返りと、今後の進め方を、ここで立ち止まって、整理しておこう。

(1) RDRA:システム価値を明らかにする


コンテキストモデルで、アクタと外部システムを洗い出すところからスタート。
要求モデルは、ちょっと、つっこみが足りない。

総論というか、一般的な「ニーズ」で、このシステムのこだわりポイントとか、キモになるポイントの具体的な検討がもっと必要。

もっとも、「検索の軸」それと「選考業務支援の軸」について、それぞれの選択肢の中から、こだわりポイントがはっきり選べたので、方向感はでてきた。

また、サイトの運用についても、初期の段階の方針も決まったので、システム要件としては、だいぶ明確になった。

概念モデルも、この段階では、まあ、いい感じで、描けたと思う。

まあ、求人・採用ドメインで、いろいろな案件を、5年間も手を変え、品を変えやってきているので、この程度のことは、さくっとできないとまずい。

(2) RDRA:システムの外部環境の確認する


基本的な業務の流れは、比較的、単純だったので、この段階のモデリングは、さらっと、流した感じ。

ただし、「選考プロセス」が、かなりの問題。
大きな手順は、応募>書類審査>面接、なんだけど、ケースバイケースで、業務のやり方は、かなりバリエーションがでてくる。

ここは、「プロトコルモデル」と「イベントモデル」で、分析・モデリングすることで、なんとか、道筋が見えてきた。

「求職者」と「採用担当者」という、「人」と「人」との間の連絡プロトコルという視点で、モデリングをはじめて、ようやく突破口を見つけることができた。

<反省点>
この時点で、画面とか、サービスクラスやシーケンス図という、実装レベルに入りこみすぎて、2日程度、時間を浪費した感じ。

やはり、「関心事」の分離は、モデリングのやり方の鉄則。

RDRA や、ICONIX という方法論の良いところは、「このステップでは、この関心事に注力する」「この関心事は、先々、ここでやればよい」という、具体的なガイドラインがあること。

しかも、RDRA も ICONIX も、形式的ではなく、「必要なことを、必要な時、必要なだけ」やればよい、という、軽量化され、ひきしまった手法なので、実践的。 コストパフォーマンスが良い手法。

(3) RDRA:システム境界


先ほどのプロトコルモデルなども参考にしながら、全体のユースケース、キモになりそうな画面などの洗い出しを、今日の午前中で、いちおう達成した。

概念モデルは、初期に洗い出したもので、この段階までは、ほぼそのままでやれた。


A4の1枚に収めた、ユースケースモデルの全体図(パッケージ図)をみると、「選考業務の支援」だけが、突出して、ユースケースが多いのが一目了然。

この部分の概念クラスモデルは、かなり、検討の余地がある。

いずれにしても、今後の開発の主要課題のひとつが、この「選考業務の支援機能」のモデリング、設計・実装にあることは明確。

ユースケースモデルでは、仕事を探すためのユースケースパッケージは、現時点では、シンプル。これは、「軸になる検索・ナビゲーション」だけに、絞ってあるから。

プロジェクト全体では「検索・ナビゲーション」については、いろいろ、要望があとからでてくることを想定している。

この、「検索・ナビゲーション」の「後から要望」に、どう対応していくかも、プロジェクトのまわし方としては、大きなポイントだと思っている。

技術課題


携帯サイトおよびそのSEO対策に関する、要求と実装技術が、技術面では、大きな課題。
キャリアや端末ごとの端末特性の違い、セッション管理や文字コードなど、PCブラウザとは、ことなる世界。

ここは、テスト環境やテスト方法の問題もあり、経験者にサポートしてもらえる体制にはしているが、見えていないことが多く、かなりのリスクポイントだと思っている。

チームビルディング


携帯サイト固有の問題以外は、基本的なアーキテクチャや、モデリングの考え方は、ある程度、実績があるもの、その延長上のものを使う。

Spring 2.5 系から、 3.0 系に移行するところ、特に、 JSR-303 対応の アノテーション方式の Bean Validation と、Spring 3 MVC を使った、REST スタイルの Web MVC の実装は、このプロジェクトで、初めて、実戦配備する。

この点は、いままでも、いろいろ相談にのってもらっていた、Spring のエキスパートを確保できたので、まあ、リスクは小さいと思っている。

一番のリストは、開発チームが、今回はじめて、召集した、寄せ集めチームである点。

こちらは、今まで積み重ねてきた、手法や方式の延長上で、やっているけど、今回、初めて参加するメンバーたちに、その内容をキャッチアップしてもらうのが、目先では、かなり重要なリスク要因だと思っている。

キャッチアップにてこずるようだと、スケジュール面と、たぶん、品質面、それも、「変更容易性」に、だいぶインパクトがありそう。

リスクとの戦い方の方針


RDRA で、要件をある程度、固めたことで、ようやく明らかになった、上記の4つのリスク課題について、基本的な方針。

選考業務のモデリング、設計・実装


RDRA レベルの要件定義がいちおうできた。
ここから、先は、ICONIX の手法で、詳細を詰めていけば、なんとかなりそう。
担当者が私になるのが、リスクといえばリスク。(いろいろ兼任しちゃっていて、ここに集中できなそうだから)

RDRA の成果で、ユースケースモデルは、だいたい固まった。
それをさらに詳細化した、画面の紙芝居(画面・帳票モデル)と、要求事項を情報源にして、初期のドメインモデルと、ロバストネス分析から入る。

シーケンス図に進めためには、ドメインモデルやサービス層のクラスの設計パターンを、もうちょっと、詰める必要がある。

ここは、マーチン・ファウラーの Event Sourcing パターンと、エヴァンスの DDD ( Domain-Driven Desing ) のパターンを参考にして、アーキテクチャを固める必要がある。

とくに、「イベントオブジェクトの生成」「イベントのハンドリングサービス」「イベントに付随するデータの扱い(イベントデータ)」あたりの設計が、キモになりそう。

仕事の検索・ナビゲーション


ここは、要求事項をひっぱりだしながら、個別に、対応していくしかないと思っている。

手法としては、基本的には、データモデリングに、振り切ってしまおうかと思っている。
検索やナビゲーションの要求の実現手段としては、結局、

・検索キーの特定
・検索の高速化手法(アプリケーションレベルでのインデックスの設計・実装)
・多対多関係の解決(交差エンティティの設計・実装)

という、データベース系の、設計・実装が中心になるから。

ドメインモデルの観点では、「 Repository インタフェースの設計 」が関連するくらい。

ドメインモデルの実装オブジェクトのメモリー上での操作よりも、データアクセスレベルの SQL での解決が基本になると思っている。

ここは、いろいろノウハウもあるので、要求がいろいろでてきても、対処はできそう。
(開発パワーの余力が問題)

携帯サイト固有の技術課題


これは、基本的には、課題は、列挙できている。
というか、携帯サイト用のフレームワーク mobylet の仕様を理解して、使いこなすことが、唯一の解決策、とみている。(個別の調査・開発していては、まにあわないので、フレームワークのサポート範囲で、最大限の効果を狙う)

mobylet の機能リストの中ら、要求の重要度と、技術的な難易度(自分たちの不安の度合い)を、にらみながら、やばいネタ順に、やっていくしかないと思っている。

問題は、ここの担当メンバー。 かなり、レベルの高いメンバーをアサインすべきだが、ここにいつから、どの程度、集中できるかが、現時点では、明確でないのが、いちばんの不安。

逆にいえば、携帯の領域以外の、他の技術方式のスキルを、他のメンバーに、いかに、はやくスキルトランスファーできるかという、次の課題と密接に関連している。

スキルトランスファーとチームビルディング


現在、ドメインモデルと、データモデル、データアクセス(O-Rマッピング)という基本部分のスキルトランスファーを進めているところ。

モデリングのパターンや考え方と、Spring / MyBatis / JUnit DBUnit の実装技術と、両面から、実際にやってもらっている最中。

経験は豊富だし、発想も柔らかいメンバーなので、キャッチアップは、まずまず順調。

問題は、Spring MVC と、Spring Web Flow という、UI レベルの技術方式のトランスファーがこれからの点。

ここらへんは、全体モデルの一部をうまく取りだして、シンプルな構造と仕様にした、習得重視にミニプロジェクトを、8月の2週間くらいで、やれば、なんとか、なるんではないかと推測している。

そこがうまくいけば、先ほどの、携帯サイト固有技術の課題に、アーキテクトを振り向けられる。

うまくいかない、雨の日ケースの想定と対応


ある程度の経験と勘で、リストを織り込んだ上で、上記の戦い方で、なんとかなるかと思っている。

ただ、いろいろ、雨の日コースも想定しておこうとは思っている。

いざという時のためには、やはり、やばそうなところを、最初に集中して叩き潰したほうが良いとは思う。
目先、まわりから、目に見える成果が少ないけど、システム開発の勘所みたいな箇所が、確立したほうが、結局は、プロジェクト全体が安定するから。

なかなか成果が見えないことに対する、説明責任、関係者に信頼してもらえるようにするもの、私の大きな責任になりそう。

また、兼任の仕事が増えた。 一人がいろいろ兼任で担当する、という計画自体、かなり問題なんだけど、この程度のやり方でやらないと、プロジェクトはまわりませんからね。

オブジェクト指向とは、モノ指向であり、目的指向である

今、採用支援システムと、国際物流システムという、異なったドメインの初期のモデリングを、掛け持ちでやっている。

採用支援システムのほうは、どちらかというと、「人」と「人」との連係をうまく支援するためのシステム。
「仕事」がそのつなぎ役のオブジェクト。

国際物流システムのほうは、さまざまな外部システムとの「システム間連係」が、重要なテーマ。
「貨物」という実体を、情報化して、関連システム間で、効果的に情報を交換するためのシステム。

2つの案件は、ドメインも、システムの性格もかなり異なるので、頭の切り替えがたいへんだけど、やってみると、モデリングや設計の考え方や基本テクニックを、整理する、良いチャンスだと感じるようになってきた。

個々の部分最適のテクニックではなく、より、一般的に使える考え方や、テクニックを習得するよいチャンス。
自分のモデリングスキルを、向上できる機会に恵まれた感じ。

オブジェクト指向


あらためて、オブジェクト指向的な発想を重視すべきだと、思うようになった。

それも、「そもそも」的な意味でのオブジェクト指向。

オブジェクトは、「的」というのが本来の意味だと思っている。(なにかを投げつける、その対象物)
実体のある「対象物」という意味を重視すると、「モノ」。
実体がなくても、目指す対象、という意味を膨らませると、(概念的な)「目的」。

システムのモデリングや設計という文脈にあてはめると、 how より what、 手段より目的、を重視することが、オブジェクト指向ということ。

ソフトウエア開発は、全体でみれば、「どうやって実現するか」という、how 指向であり、手段指向の世界だと思う。
本質的には、オブジェクト指向ではない。

だからこそ、how より what、 手段より目的を、重視する「オブジェクト指向」に価値がでてくる。

ITは、how と 手段の集合体。それを活用するためには、what や、目的から出発するのが良い結果を産む。

IT に限らず、how より what、手段より目的を重視せよ、というのは、ビジネススキルという一般的な意味でも、とっても大切なはず。

ビジネス一般でも、how 中心、手段中心ということが、多いのが実情。IT の世界では、それが、さらに強くて、弊害が、はっきりあらわれている。 できあがってみたら、目的とはかけ離れたシステム、事業に価値をもたらさないシステムが、なんと多いことか。

事業にとって価値のあるシステム開発するなら、what や 目的を「指向」する、というより、what や 目的で、how/手段を「駆動」する、という、もっと積極的な考え方がよさそう。

オブジェクト指向を進めて、オブジェクト駆動

「モノ」を定義する。
「目的」を考える。

これを駆動力にして、いろろな how / 手段 を引きだしから、引っ張り出してきて、組み立てていくのが、ソフトウェア開発のやり方として、成功パターンになりそう。

まずは宣言


how より、 what ということは、コードのレベルで考えれば、XML, SQL , アノテーションなど、「宣言」型の記述方法が中心になる。

UML などの「図」法も、宣言型に近い。 シーケンス図とか振る舞いモデルの図も、振る舞いを「宣言」する感じ。

文章や、プログラミング言語は、手続き型。

手続きスタイルの、ソフトウェア開発がなくなるわけではないけど、大きな方向としては、「手続き」型より、「宣言」型で、考えたり、記述することが増えてきている。

what 駆動、目的駆動という視点からは、 what や 目的を「宣言」できれば、開発完了、になるのが理想。

少なくとも、まずは、 what / 目的 の記述に注力する。
そこがある程度、固まってきてから、はじめて、 how / 手段 の検討に入る、ということ。

逆にいえば、 how や 手段 が不明だったり、できそうかどうか、とかは無視して、まずは、 what / 目的を明らかにしてみるべし、ということ。

what 駆動、目的駆動でやるには、 how や 手段の知識は、ノイズだったり、余計なバイアスだったり、発想の足かせになる。

技術者として、 how や手段の知識は、財産。その財産から、いったん離れて、 what 駆動、目的駆動に注力するのが、良いモデリング・設計の基本だし、また、それが奥義なんだと思う。

オートマトン


「オブジェクト」は、本来は、「自律的」という意味は、なかった。(今でも、一般的な言葉としては、「自律」という意味はないはず)。

ソフトウェアの技術体系の基本モデルのひとつに「オートマトン」がある。
プログラミングとか、情報システムの根底には、この「オートマトン」モデルがある。

オートマトンは「自律的に動く」ことが、その基本の発想(定義?)。

オブジェクト指向を「プログラミング」という文脈でとらえた時、あたりまえのように「オートマトン」「自律的に反応する」という発想になる。

オブジェクト指向プログラミング(OOP) は、自律的に反応する「what」に注目する、という「オブジェクト指向」+「オートマトン」という合成物。

「オブジェクト指向」そのものには、「自律的に動く」という意味合いは、ない。

オブジェクト指向で、分析・設計するということは、いったんは、「オートマトン」、つまりプログラミングのモデルから離れて、「モノ」の定義、「目的」の定義を、重視するのが良いモデリング・設計のコツなんだろうと、思い始めている。

オブジェクト指向の分析の結果を、現在のオブジェクト指向系といわれる言語で実装するのが良いかどうかは別の問題。

私の感覚では、 XML は、宣言型で、 what 指向なので、オブジェクト指向風の言語。
Java は、アセンブラ、Cという由緒正しい(?)、マシン操作の手続きを記述するための言語。

Java のように、汎用的な言語の場合には、書き方によって、手続き重視でもかけるし、宣言重視でもかける。

ドメインモデルを、Java で実装する場合、Bean Validation のアノテーションなどを使いながら、かなり、宣言的に書けるようにはなってきている。

アグリゲートのルート、というような構造の宣言も、 XML マッピング用のアノテーションを導入すると、記述できる。

自然な書き方かどうかは、かなり疑問だけど、使えるものを使う、という発想で、開発言語として、Java を使いつつ、ドメインモデルを宣言的( what 指向 ) に実装しようと、いろいろやってみている。

状態遷移(プロトコルモデル)の実装 【パターン】

採用支援業務の「選考状況」の管理を分析している。
RDRA(リレーションシップ駆動分析)のプロトコルモデル(ステートマシン図)と、イベントモデル(イベント図)を使いながら、だいぶ、分析レベルのモデルとして骨格がはっきりしてきた。

業務の主要な関心ごとが、「状態」の視点と、「アクションイベント(状態遷移のトリガー)」の視点から、立体的なモデルになってきた。

この「状態(state)」と「イベント」のモデルを、「イベントソーシング」スタイルで、実装する設計を始めてみた。

初期の設計モデルは、こんな感じ。

構造


選考管理の主要クラス

UIから、わたされた、採用担当者のアクションを、サービス層の「選考アクションサービス」クラスが、処理する。

サービス層のクラスは、ファサードにして、実際のビジネスロジックは、ドメイン層の、

・選考プロシジャ   (業務ルール)
・選考状況リポジトリ (記録)
・選考メッセージング (通知)

3つのクラスに委譲する。

業務のオペレーション、つまり「起きたこと」は、 「選考アクション」イベントオブジェクトで表現する。

ファウラーの Domain Event パターンをそのまま使っている。
イベントオブジェクトは、イベントタイプオブジェクト(選考アクションタイプ)と、サブジェクト(関心ごと)である「選考コンテキストの現在の状態」を参照する。

振る舞い


選考管理の振る舞い

選考アクションサービスは、採用管理者が指示した「候補者」をキーにして、「現在の選考状況」を取りだす。
「コンテキスト」パターンにしているのは、選考履歴とか、選考の関係者とか、選考書類とか、その他のさまざまな情報の参照ポイントにするため。

「選考状況」をユーザに戻す(画面に表示する)時に、「選考プロシージャ」オブジェクトに、「選択可能なアクション」を問い合わせる。

状況ごとに、可能なアクションは、異なる。「選択可能なアクションリスト」を、画面では、「アクションメニュー」として、表現する。

ユーザがあるアクションを選択すると、再び、「選考プロシージャ」オブジェクトに問い合わせて、そのアクションのタイプを実行するための「ひな型(プロトタイプ)」として「選考アクション」オブジェクトを作成する。

選考理由とか、選考結果とか、必要な情報を入力するためのオブジェクト。

画面のフォームにマッピングして表示。
ユーザの入力内容はオブジェクトにバインドした結果を、「選考アクションサービ」が受け取る。

「選考アクションサービス」は、「選考プロシージャ」オブジェクトに、アクションの妥当性検証と、ドメインオブジェクトの現在の状況の変更とか、履歴への追加とか、さまざまな反映処理を、「委譲」する。

検証&反映が、無事に終わったら、「記録」すべきこと、「通知」すべきことの「業務のルール」を、「選考プロシージャ」オブジェクトの問い合わせる。

問い合わせ結果に応じて、リポジトリクラス(永続化インタフェース)を使って、適切に記録。
メッセージングクラス(通知インタフェース)を使って、しかるべき相手に、「変更が起きたこと」あるいは「処理が終わったこと」を通知。

検討課題


「選考プロシージャ」オブジェクトが、「選考業務」の知識を表現している。
その知識の表現手段として、列挙型の「状況タイプ」「アクションタイプ」を用意する。

この設計で、変更が容易に安全にできるかの検討がもうちょっと必要。

・状況をもっと、細かく管理したくなった場合になにが起きるか?
・現在は許可している遷移を、不許可にする場合、なにが起きるか?
・許可していない遷移を追加した場合は?
・永続化した過去の選考履歴と、変更後の整合性は?
・ユーザの画面操作だけでなく、REST スタイルの API や、非同期メッセージング用のサービスとして、そのまま使えるか?
...

まあ、初期のモデルなので、実装を進めながら、ここらへんに対応できる、しっかりした設計・実装に育てていければと思う。

今のところ、足がかりモデルとしては、悪くないと思っている。

業務のモデリング 【プロトコルモデリング】

採用支援システムを、RDRA(リレーションシップ駆動要件分析) のやり方で、実践中。

RDRA の基本のやり方


1.システムの価値を関係者で共有する
2.システムの外部環境(利用者の使い方や関連システムとの通信要求)を把握する
3.システム境界(画面、API,メールやファイル転送などの通信)インタフェース定義
4.システム(ドメインモデル、データモデル、機能モデルなど)

の4ステップ。

ウォータフォール(後戻りしない)式ではなく、先に進みながら、前のステップとの整合性を検証し、必要であれば、前のステップに立ち戻って、モデルの改善、を継続的に行う。

私たちの場合は、システム規模が小さく、関係者も少ないので、このまま設計・実装まで、ICONIX プロセスを使ってなだれ込む。

システム価値を明らかにする最初の段階で、主要な概念を洗い出した、概念モデルを作って、それを、そのままドメインクラスの実装まで一気に持ち込む。

実際、分析の初期の段階から、概念モデルを元に、ドメインクラス、テーブル、O-R マッピングを実装を、並行してはじめている。

ドメインクラスの設計の議論と、システムの主要概念の議論をいっしょにやっている。

いちばん最初にコードにするのは、「ドメイン層のクラス群」。 ドメイン層のクラスが、全体の実装を駆動するので、「ドメイン駆動設計」のスタイルを、 RDRA + ICONIX のやり方を参考にやっている。

システムの価値


そのシステムが、誰にとって、どんな価値を持つかを、みんなで共有するために、絵を描きながら、話をする。

主要な絵は、

・コンテキスト図
・要求モデル
・主要な概念モデル(これを、ここでやるのは、自己流。本来の RDRA ではない)

採用支援システムの場合、募集責任者、採用責任者、そして求職者がいて、「求人案件」が主要な概念。
この分野ばかり、5年以上やってきているので、この段階までは、わりとすんなり進む。

ただし、「このサイトの独自性」という意味づけ、価値観の共有が、まだ、あやしい状態。
来週からさ来週にかけて、ここらへんの共有度をたかめていきたい。

コンテキスト図や主要概念モデルだけだと、総論というか、議論に具体性が欠けるきらいがある。
要求モデルになると、今度は、枝葉の議論がはじまりがち。

「システム価値」の初期のモデリングは、ある程度のところで、切り上げて、次に進みながら、また、システム価値に立ち戻る。 いま、ちょうど、「初期の価値モデリング」から「次に進めてみる」あたりの段階。

システムの外部環境


次は、システムの外部環境のモデリング。

業務モデル(アクターごとにレーン分けしたアクティビティ図)とか、利用シナリオ(使うシーンを文章で書いてみる)という技法が中心。

この段階で、概念モデルは、かなり、具体的なドメインモデルの設計に近づいてくる。

やりはじめてみたが、どうも、うまくいかない。

「採用プロセス」といういい方は、あるけど、実は、「プロセス」と呼べるほど、構造化できないことが多い。
求職者と採用責任者という「人と人」とのやりとりとか、「人の感覚的な判断」とかが業務の根底にある。

業務モデル(アクティビ図)のように、時系列に、淡々と業務が進むわけではない。

面接の日程調整、面接日になってのドタキャン、他の候補者との比較のための保留状態...

いわゆる業務フローと呼べるようなステップ構造ではない。

で、トライアルしたのが、「イベント」モデルと、「プロトコル」モデルという、「状態遷移(ステートマシン)図」の技法。

神崎さんの RDRA では、「業務モデル」ではなく、次の「システム境界」を明らかにする技法として、登場する。
しかも、外部システムとのシステム間インタフェースの把握が主目的のモデル。

まあ、ここも、私の自己流で、「役に立つ」こと重視で、「採用業務」のモデリング技法として、「イベント」モデルと「プロトコル」モデルを使ってみた。

これがなかなかいい感じ。

考えてみれば、採用プロセスは、「求職者」と「採用者」の間のメッセージ交換でなりたっているので、「イベント」と「プロトコル」のモデリングが、ぴったりはまった感じ。

プロトコルモデル(ステートマシン図)で、まず、主要な「状態」、採用側が、関心のある「状態」を洗い出しながら、その状態間の遷移をイベントして、洗い出す、というステップではじめた。

最初は、状態とかサブ状態がかなり入り組んだモデルになりはじめた。
直感的におかしい。(業務では、そんなに細かい状態に興味はないから)

で、見直してみると、多くのサブ状態は、単純に「イベント」の発生として、モデル化したほうが、実際の業務に近いということがわかった。

しかも、そうやってモデリングしてみると、「イベント」が、見事に、「画面からのアクション」または「メールの送信/受信」のモデルになっていった。

これは、大きな収穫。業務を把握した手ごたえ。
いろいろモデリングのブレークスルーの瞬間は、稀だし、貴重なんですよねえ。

このモデルベースで、初期バージョンを開発して、実際に使ってもらいながら、「状態」や「イベント」の追加や変更を、安定してやり方でできそうな感じがしてきた。

基本の構造モデルが明確になると、ここを土台にして、ソフトウェアを繰り返し、発展、育成させていける予感。

実装レベルでも、前の記事に書いた「イベントソーシング」スタイルを、実装する技術パターン(アーキテクチャ)が、見えつつある。

なんか、いい感じになってきた。

モデリングツールの威力


私は、どちらかというと、最初のラフスケッチは、手書き(裏紙、ホワイトボード)派なんだけど、このイベント/プロトコルのモデリングでは、モデリングツールの威力を思い知らされた。

使っているもモデリングツールは、 スパークスシステムズジャパンのEnterprise Architect 。

もう3年以上つかっているけど、実は、ステートマシン図は、昔、手触りを確かめた程度しか、触っていなかった。
制御系のモデリング用かな、という感じで、それ以来、ぜんぜん使っていなかった。

今回、使ってみて、びっくり。

まず、「ステートマシン図」「状態遷移図」「イベントモデル」の三つのビューを、一つのモデルから、簡単に作れることに驚いた。

ステートマシン図と状態遷移図は、片方の変更が、双方向で自動的に反映される。
最初は、逆に、予想外の変更が起きて、ちょっととまどった。 状態を、ドラッグアンドドロップで、簡単にサブ状態にできるのは、便利すぎるというか、誤操作で、サブ状態にしちゃって、戻すコマンドを見つけるのに、ちょっと手間取った。

むしろ、状態の順番を並び変えるのを、ドラッグアンドドロップでやってもらえたほうがうれしい。
あと、S1 , S2 などのラベリングも、自動のリナンバリングとか、別名機能で表示できたりすると、うれしいかな。

という感じで、道具に慣れるのに、1,2時間かかった後は、ほんと、びっくりするくらい、状態遷移とイベントのモデリングが簡単にできちゃった。

初期のモデリングで、思いつくままに、状態も、イベントもたくさん作っちゃって、ひどい状態。

その状態の整理は、手書きでは、たぶんできなかったと思う。

ステートマシン図、状態遷移図、イベントの関連図、そして、プロジェクトブラウザ の4つのビューをいったりきたりしながら、モデルが洗練されていく様子は、われながら、ちょっと感動的だった。

それぞれが別のビューではなく、根底の一元管理された「モデル」への操作なので、たとえば、イベントの名前変更とか、削除や追加が、他のビューにも、素直に反映される。

ステートマシン図で、いい感じになってきたら、状態遷移図で、対応関係を論理的に検証してみる。

イベントの関連図で、それぞれのイベントを、

・採用担当者と求職者の間で発生するメッセージ交換イベント
・採用担当者のアクションとして発生するイベント
・期限切れとか、時間によって発生する「タイマーイベント」

として整理することで、業務の流れの中で発生するイベントの抜け漏れや重複を発見しやすくなる。

モデルの要素の一覧も簡単に作れるし、プロジェクトブラウザで、階層構造として把握できる。

どのダイヤグラムからも参照されていない、ゴミになっているモデル要素も、簡単にリストアップできる機能も付いている。

候補の洗い出しから、一連の整理のプロセスは、ツールなしには、まともな仕事ができなかったと思う。

ツールの威力に脱帽です。

イベントソーシングスタイルを実装する

採用業務の状態管理の仕組みをモデリングしている。

状態管理を、イベントソーシングスタイルで、やるための、大まかなクラス構成を絵にしてみた。
それぞれのクラスの役割をできるだけ、単純明快にすることを、重視した。

関心ごとの分離( SoC : Separation of Concerns )原則、 単一責任原則 ( SRP : Single Responsibility Principa ) をこころがけたつもり。

イベントソーシングの実現モデル

メッセージング / Web アプリケーション


上半分は、メッセージングのフレームワーク Mule ESB での実装をモデル化したもの。
下半分は、(今までやってきた) Web アプリケーションの MVC モデル、サービス層/ドメイン層/インフラ層のレイヤ構造を整理したもの。

Mule ESB のサービス部品と、Web アプリで使う Service クラスとは、完全に一致していない。
どちらも、薄いファサードで、実際の責務は、下のドメイン層のクラスに委譲するのは、同じパターン。

たぶん、コアのサービスクラスを作って、それを、 Mule ESB 用にラッピングしたクラスと、Web アプリケーションのサービス層用にラッピングしたクラスを、それぞれ用意することになると思う。

ドメイン層のイベント処理モデル


Event と Document


Event クラスは、シグナルに近い。 単純に「変化があった」ことだけを表現する。
Document クラスは、その event に付随する「その時の状態」を表現したもの。

この二つは、発生時点の状態を、feeze して記録する。つまり、不変(immutable)オブジェクト。

State


State オブジェクトは、業務上の関心のあるオブジェクト。
「現在の状態」とか「履歴」とか「次にやるべきこと」、「予定日時」とか、業務上、参照したい情報を置いておく場所。
図には描いていないけど、State オブジェクト ( リファレンスオブジェクト、または Entity )は、参照用の識別キー(ID とか管理番号)が必須の属性。

こちらは、業務で変化が起きるたびに、状態を変更していく 可変 ( mutable ) オブジェクト。

Procedure


Procedure クラスは、ドメイン層内部のレイヤ構造で、上位レイヤ(Policy層)に位置するオブジェクト。
このクラスに、
・ある event が発生したら、何をすべきか
・State オブジェクトの状態と、その変更の妥当性 (有効な状態遷移)
などの「業務手順の知識」を記述する。

実装技術


この絵で、白い背景の要素は、フレームワーク側で用意している仕組みや部品で実現しようと思っている。

Mule ESB だと、 inbound/ountbound 、メッセージ routing 、例外処理、などは、いろいろ部品がそろっているので、ビジネスロジックコンポーネント( Service クラス )と、委譲先のドメインクラスを設計・実装して、組み立てるだけ。
(というか、ドメイン駆動設計でやっているので、ドメイン層は、サービス層を実装する時には、できあがっている)

Web アプリケーションも、 コントローラーは、 Spring 3 MVC と、 Spring Web Flow が用意されているので、それを活用する。

いままでのシステムでは、 Validation は、if 文とか使って、validation 用のメソッドを、ごりごり書いていた。
今回の案件では、 JSR-303 Bean Validation を全面的に採用することにチャレンジ中。
アノテーションで、 @NotEmpty とか @Length とか、宣言するだけで、検証は、フレームワークがやってくれる。
if 文が、激減する。

O-R Mapping フレームワークとか、Java の Collection フレームワークを活用するようになって、もともと、for 文は、ほとんど、コードに登場しなくなった。

今回、アノテーション方式の Validation フレームワークを導入したので、if 文も、ほとんど見かけなくなる予定。

たぶん、サービス層やドメイン層で、if 文や for 文を発見したら、「いやな臭い」として、ドメインモデルの設計改善ネタにしてまちがいなさそう。

if 文や、for 文が激減していくのは、まさに、IoC ( Inversion of Control ) ですね。
「プログラムの制御文(control)」は、どんどんフレームワーク側に移動して、アプリケーション開発は、どんどん、宣言スタイルに進化(?)していく。

モデリングして、それを、アノテーションや XML で宣言、以上終了、という感じ。
テスト記述も、どんどん、アノテーションと、XML になってきちゃっている。

開発という仕事は、制御構造(if分岐、forループ)にどっぷりつかった「プログラミング」から、ドメインを表現する「ライティング」に大きくシフトしてきた感じ。


event とメッセージング 【きっと、良いパターン】

前の記事で、 state ソーシングスタイルと、event ソーシングスタイルについて書いた。

単純にいえば、メモリ上でオブジェクトを操作する順番、そして、データベース操作の順番の問題。

state ソーシング


state ( 現在の状態 ) オブジェクトの更新が最初。
必要が、あれば、audit ログ(監査記録)とか、history ( 履歴 ) オブジェクトを作成する。

テーブルであれば、state テーブルを update すると、トリガー で、監査テーブルにレコードを insert したり、history テーブルに insert する、というやり方。

顧客の連絡先、例えば、住所を変更したら、住所変更ログを書いたり、住所変更履歴を作成する、というパターン。

event ソーシング


ビジネスの事象オブジェクトを作成する。 そのオブジェクトが、しかるべき、state オブジェクトを変化させる。

入庫があったら、入庫イベントオブジェクトを作って、そのイベントオブジェクトを処理すると、「在庫」オブジェクトの現在高を更新。

入庫レコードを作成すると、トリガーで、在庫テーブルの「在庫数」を 自動更新。

書類選考の合格イベントを記録したら、「選考状況」オブジェクトのステータスを「書類選考合格」に更新する。

というような、パターン。

システム間の連係


今までの例は、ローカルなアプリケーションで、メモリ上のオブジェクトやデータベーステーブルでの操作の順序の話。

システム間の連係になると、event (変化が起きたこと)をメッセージング(通知)するのが基本パターン。

仕事探しのサイトで応募があったら、採用管理システムに通知。
採用管理システム側で、選考結果を変えたら、仕事探しサイトに通知して、さらに、メールで、応募者に通知。
...

人とシステムの連係であれば、何か、関心事に変化があったら、電子メールで通知する。
システム間であれば、変化があったら、メッセージを非同期で送る。(例えば、XML over HTTP で)

関心事に変化があったら、それを、イベントオブジェクトとして表現し、非同期メッセージングでしかるべきところに送る、というのが業務アプリの基本パターン。

event ソーシングパターンは、メッセージング(通知)という仕組みを使って、エンタープライズアプリケーション間を連係を実現する有力な手段。

event ソーシングスタイルは、

* メモリ上のオブジェクトの操作
* ローカルデータベースを使った永続化
* リモートシステムとの連係

に一貫して使える、基本パターン、ということ。

業務の基本、

* 起票 (イベントの表現 & 永続化)
* 記帳 (現在の状態の表現 )
* 連絡 (通知)

を、素直に、メモリ/DB/通信 で実装するには、 event ソーシングスタイルが、よさそう。

コマンド、イベント、ドキュメント


メッセージは、基本的に3種類ある。

コマンド・メッセージ


メッセージの主たる内容が、「指示」や「依頼」であるパターン。
リモート手続き呼び出しを、非同期にしたもの。

メソッド名と、そのパラメータセットを、そのままメッセージにする。

システム間の結合度はかなり強い。
非同期だけど、相手からの回答があることを、前提としている。
(少なくとも、こちらが指示した内容を、相手が実行することを期待している)

イベント・メッセージ


変化があったことだけを伝える方式。

どんな変化があったか、詳しく送る場合もあれば、「変化したよ」ということだけを通知する方法もある。

「変化したよ」だけの場合は、イベントメッセージを受け取った側が、必要だと判断すれば、詳細情報を、取りに行く。

イベント・メッセージの設計・実装で興味深いのは、

・イベントメッセージの送り先
・詳細情報の手に入れ方

を、送る側が意識しない、という設計ができる点。

イベントメッセージを、関係がありそうなところに、ブロードキャストすると、関心がある受信者だけが、それを処理し、また、必要な受信者だけが、必要な詳細情報を、自分で取りに行く、というパターン。

例えば、会社で、「お中元でビールをもらいました」というメッセージを社内のブロードキャストすると、ビール飲みたいやつが、しかるべき場所(冷蔵庫?)に、勝手に取りに行く、というやり方。

これは、システム間の結合を、劇的に「疎」にできるパターン。

というか、人が、ビジネスや社会活動をする時の基本パターンがこれ。

event ソーシングで、event メッセージング、というアーキテクチャスタイルが、これからのエンタープライズアプリケーション設計の基本パターンなんだと思う。

ドキュメント・メッセージ


メッセージの中身が「ドキュメント」、つまり、データだけのメッセージングのパターン。

これも、実際の業務では多いパターンですね。「書類送付」。
あるいは、システムでも、CSV ファイルを送る連係方式は、このドキュメントメッセージングのバリエーションですね。

ドキュメントメッセージは、「コマンド」つまり「指示」とか「依頼」は明示しない。
メソッド名なしに、パラメータセットだけ送る、という、ある意味、とても乱暴なやり方。

実際の業務では、多いパターン。

応募、注文のように、しかるべき「送り先」にドキュメントを送れば、しかるべき処理をしてもらえる、という了解の上になりたっている。

「送り先」がポイント。
あるいは、受け取った側が、ドキュメントの内容を判断して、処理をやり分ける、という仕組みも現実には多い。

アプリケーション間の結合度としては、「コマンド」と「イベント」の中間。

アプリケーション間である程度のデータ形式の合意が必要。
受け取った側が、自分の都合だけで、データ項目の取捨選択や解釈することが可能なので、コマンドメッセージングよりは、結合度が低い。

メッセージングの設計


「コマンド」「イベント」「ドキュメント」の選択。

コマンド・メッセージングの設計


これは、メソッドの設計そのもの。

メソッド名(コマンド名)、パラメータ形式、戻り値、例外、をそれぞれ設計する。

これを、アプリケーション間で合意するわけだから、結合度はかなり密になる。
変更が大変になるパターン。

イベント・メッセージングの設計


何を通知するか ( event タイプの列挙 )
誰に伝えるか ( 宛先、場合によっては、ブローカーの設計や、ブロードキャストの設計 )
どこまで伝えるか ( 詳細情報をメッセージに含めるか)

いろいろバリエーションがあって、なかなか興味深い、設計テーマ。

もちろん、答えは、「ドメイン」の言葉に耳を傾けること。
テクニカルな検討ではなく、「業務」でどうやっているかが、その答えになる。

ドキュメント・メッセージングの設計


乱暴にいえば、紙、画面のフォーム、csv ファイルなど既存の情報の表現を、XML 形式で表現すれば、設計完了。
通信方法は、HTTP という便利な仕組みがるので、XML 形式のデータ表現さえ設計すれば、 XML over HTTP で実装完了、というわけだ。

もちろん、XMLの組み立てとか、解釈とかの処理は必要だけど、最近は、O-X マッピングのフレームワークとかも、なかなか良い感じになってきたので、実装の負担はかなり減ってきている。

XML ドキュメントの 設計だけが課題、という感じ。

イベント+ドキュメントが基本


実際のアプリケーション設計は、

  • イベントメッセージングのための event タイプの設計
  • 詳細情報を伝えるためのドキュメントメッセージングの XML 形式の設計

の2つが、二大設計課題ということ。

ここがちゃんと設計できちゃえば、アプリケーションの骨格は、かなり固まるはず。

(ここまでは、仮説)
この仮説を、今回の、仕事探し+採用管理のシステムで、実践しながら、設計・実装ノウハウを獲得したいと思っている。

state ソーシング、 event ソーシング 【スタイルの選択肢】

業務の情報の扱い方の基本スタイルとして、

* state ソーシング
* event ソーシング

がある。

state が先か、event が先か、という正反対のスタイル。

state ソーシング


現在の「状態」を中心にしたスタイル。

state オンリー


一番、単純なパターン。
いわゆる「上書き」モード。

メモリ上のオブジェクトを、 setter とか update メソッドで、最新の状態を保持する。
更新前の状態は、どこにも残っていない。

テーブルであれば、update 文で、最新の状態に上書きしていくパターン。

もっとも単純だし、これで要件が満たせるなら、これで必要十分。

情報源は、「上書き」された最新の state だけ。 これが、state ソーシング のもっとも、単純な state オンリー パターン。

state - audit log パターン


state を変更した時に、記録を残すパターン。
audit log ( 監査ログ ) 。

業務アプリでは、金銭がからんだり、責任の所在を明確にするために、この要求は多い。

実装方法としては、 state オブジェクトを更新した時に、いっしょに、audit log を書くパターン。
データベースだと、state テーブルを update するたびに、トリガーで、audit log を自動的に記録する。

情報源は、 state で、そこから、 audit log を派生させるパターン。

state - history パターン


状態・履歴パターン。

audit log と基本は、いっしょ。
異なるのは、audit log は、アプリケーションの通常の機能では、アクセスしない。あくまでも、監査目的の情報。

それに対して、 history ( 履歴 ) は、アプリケーションで、その情報を利用することを目的としている。

大きな違いは、「history (履歴)」の、識別キー を使った参照が必要になること。

例えば、バージョン番号とか、人が、業務上、意識する、なんらかの識別キーが表にでてくるのが、 state - history パターン。

実装の仕組みとしては、 state - audit log パターンといっしょ。
state を更新して、 history ( 履歴 ) を派生させる。

ここまでは、情報の起点が、更新可能な state オブジェクトまたは、state テーブル。

state ソーシングのバリエーション。

event ソーシング


状態の変化を、イベント(事象)として表現するパターン。
state ソーシングでは、すべての情報源は、最新の状態(state ) に更新するところから派生させる。

event ソーシングでは、event が、起点になって、現在の状態 ( state ) を派生させる。

テーブルで考えるとわかりやすい。

event レコードテーブルの、 insert トリガーで、 state テーブルを更新する、というパターン。
例えば、入庫イベントを記録したら、現在の在庫数を更新する。

紙ベースの業務では、event ソーシングのほうが、自然なパターン。
まず、入庫という経済イベントが起きたら、伝票を作成(起票)する。それから、元帳に 記帳 して、残高を変更する。

これを、すなおに、実装すれば、 event ソーシングスタイルになる。

紙ベースだと、 event ソーシングがあたりまえなのに、電子化(データベース化)すると、state ソーシング が、けっこう幅を利かせている。

これ、電子化だから、ではなく、IT技術者が、業務をよく理解していないから、そうなっているように思う。

紙だろうが、電子だろうが、 業務は、個別の事象を、まず、 起票 して記録し、合算や残高の変更は、伝票から派生させるのが、基本。

理論的には、イベントの記録だけあれば、現在高は、導出可能。
もちろん、それでは、残高参照に時間がかかってしょうがないので、「現在高」も、ついでに更新しておく。

情報源は、イベント記録で、現在の状態 (state)は、導出された値。

state オブジェクト/テーブルは、キャッシュや、インデックスみたいな、高速化の技法で、あって、本質的なオブジェクトではない、ということ。

event ソーシングで行ってみよう


始まったばかりの採用支援プロジェクトでは、この event ソーシングスタイルに、こだわってみようと思っている。

応募イベントを起点にして、採用可否の決定までの業務のサポートを、

「採用プロセスで発生するイベント」を情報源(ソース)として、「選考状況 ( state ) 」を導出しておく、というパターン。

選考状況の変更を、関係者に通知する、という業務ニーズがいろいろあるんだけど、これも、「イベント」を通知(メッセージング)するスタイルで、モデリングし、設計・実装しようと思っている。

業務のモデルとして、それが自然だと思っている。
また、Mule ESB というメッセージングのフレームワークが、なかなか、いい感じで使えそうとう、実装技術面からのサポートもある。

自分も今までは、event ソーシングぽいことを、なんとなくやってきたけど、初期のモデリング段階から、event ソーシングを明確に意識して取り組むのは今回が初めて。

さて、どんなことになりますか。

<参考>
マーチン・ファウラーの PoEAA の続編 wiki の

Event Sourcing パターン

リレーションシップ駆動要件分析(RDRA)の実践

採用支援の新サイトの構築プロジェクトが始まった。

* 仕事を探して応募するためのジョブサイト
* 求人情報を登録するアプリ
* 応募者と採用側の連絡アプリ
* 採用側の応募者管理アプリ
* サイト運営のための機能

こんな感じで、5つのコンテキストが、関連しあったシステム。

もしかしたら、採用企業側の採用関連システムとの連係も必要になるかもしれない。

コンテキストモデル


RDRA の基本ステップ。最初は、「システム価値」を明確にすること。

その中でも、第一歩は、コンテキスト図を描いて、「関連する人」「関連する外部システム」を洗い出して、関係者で共通理解にすること。

募集と採用は、密接に関係しているし、小規模な企業の採用であれば、募集情報をサイトに掲載する人と、それに対する応募に対応して、選考をする人は、同じ人(部門)。

ただ、この二つの業務は本質的に、別の業務。ここらへんの登場人物分けが、最初の検討テーマ。

あと「サイト運営」を、初期のコンテキストモデルでは、ひと固まりに「サイト運営者」にしちゃったけど、ここはかなり怪しい。

まあ、業務モデルくらいまで、落としながら、コンテキストモデルの見直し、特に登場人物の見直しを繰り返そう。

「リレーションシップ駆動」なので、コンテキスト図で把握した「登場人物」は、「要求モデル」のアクタ、「業務モデル」(アクティビティ図)のレーン、ユースケースモデルのアクタに、それぞれ、直接対応させるので、後続のモデリングをしながら、なんども、登場人物のとらえ方を改定することになる。

実践では、業務モデルのレーンと、コンテキストモデルのアクタが、ずれを発見。
どうやって整合させるか、今、検討中。

5つのサブの問題領域を、一つのコンテキストモデルでとりあえずは進めてみる。

要求モデル


コンテキストモデルと、アクタとシステム、外部システムとシステムとの間に引いた関連線をさらにブレークダウンしてみる。

線を引く、つまり、関連がある、という認識合わせは、コンテキストモデルのほうでやる。
それぞれの関連の意味(価値)を、具体的に考えてみるのが、要求モデル図。

ここの議論、整理の仕方は、たぶん、RDRAというか、上流工程のキモ。
教科書的な方法論を語っても、実践では、なかなかうまくいかなかった。
私流だけど、「大まかなユースケース」「重要なユースケース」という視点で、「中核機能の列挙」というような視点で、とりあえず進めている。

あと、でてきたニーズや要望は、とりあえずメモしておくべき。
ただし、これを、要求モデルに入れると、収拾がつかなくなるので、

* 中核な関心事(価値)の入れ物 (UMLの要求モデル図)
* それ以外の関心ごとの入れ物 (要望の箇条書きメモをノート形式で)

に使い分けて、その間を行ったりきたりしながら、整理をしている。

概念モデル


神崎さんの本来のやり方だと、概念モデルは、「システム価値を明らかにする」ための最初のステップではなく、次の「システムの外部環境を把握する」ステップでの作業。

私の「ドメイン駆動設計」こだわりで、「概念モデル」は、最初の「システム価値を明らかにする」モデルとして位置付けている。

というか、ドメインモデルの基本設計をやりながら、コンテキストモデル、要求モデルを発展させていく、「ドメイン駆動」でやっている感じ。

順番はともかく、「モデル間の関係、整合性のチェック」という神崎さんのRDRAの基本は、ちゃんと押さえてやっているつもり。ドメイン駆動だけど、リレーションシップの整合性には、とてもこだわている、ということ。

業務モデル


コンテキストで、登場人物を洗い出し、要求モデルで、システムに期待される、主要な関心事を明らかにし、それを、概念モデル(初期のドメインモデル)という形で、まず、だいたいのイメージをつかむ。

今日は、このイメージをもとに、次の「システムの外部環境を把握」するためのステップとして、「業務モデル」、いわゆる、業務フロー図を、描き初めてみた。

見事に、概念モデル、要求モデル、コンテキストモデルに立ち戻って、いろいろ改定することになった。
モデル間の関連性や整合性をいつも気にかける、これが、RDRA流なんだと思う。

アークテクチャ


並行して、アーキテクチャの設計も進めている。
要件を定義してから、アーキテクチャ、といのは、ちょっと遅すぎる感じ。
概念モデルといっても、最初から、ソフトウェアにするための作業なのだから、その概念を、どうやって実装するかの議論も並行して進めちゃうのが私流。

今のところ、主な技術ポイントは、こんな感じ。

Bean Validation の全面採用


Spring Framework 3.0 で、 JSR-303 のアノテーションベースの Bean Validation がサポートされた。
ドメインモデルの実装のための便利な実装技術。さっそく飛びついた。

今のところいい感じ。 ( Spring Web Flow で、ちょっと一工夫必要だけど、ここは、Spring Framework エキスパートの大野さんの、さくっと、かたをつけてもらえそう)

プロジェクトの分割とプロジェクト参照


システム全体のレイヤ構造、アプリケーション間の依存関係、ドメインモデル内部のドメインオブジェクト間の依存関係、...

概念的には、依存関係、参照関係を、すっきり整理し、可能な限り、単一方向で、必要最小限の依存関係にする。

設計レベルでは、パッケージ図でそれなりにきれい描ける。
でも、実装に入ると、結構、あちこちで、 好き勝手に参照を始める。
Public クラスと、Public メソッドであれば、結局、実装としては、どんな参照でも記述できてしまう。

なんのことはない、グローバル変数の悪夢、スパゲティコードアンチパターンへまっしぐら。

今回は、これを、概念レベルの設計や、お互いの設計モラル(?)に依存するのではなく、物理的に、制限をかける試みにチャレンジ。

まあ、大げさな話ではなく、 Eclipse のプロジェクトの分割と、プロジェクト参照の設定の決めごとの話。

レイヤ構造で、ちゃんと実装するために、レイヤごとに別プロジェクトにする。そして、下のレイヤのプロジェクトを、上のレイヤのプロジェクトが「プロジェクトで参照」する。

jar にして、ライブラリの参照にするのではなく、プロジェクトの参照にする。

こうすると、双方向の参照が実装しにくくなる。(やればできちゃう方法はある)

ドメインモデルを、依存関係を元に、プロジェクトを複数に分割することにした。
ドメイン駆動設計(DDD) の、ドメインのレイヤリングを参考にしてモデリング。

その結果を、プロジェクト分割として、実装する。

一つのドメインモデルプロジェクトにしてしまうと、意味的な依存関係を無視して、あるドメインオブジェクトは、ドメインモデル内の他の public な オブジェクト/メソッドを自由にアクセスできてしまう。

ドメインを意味のあるパッケージ単位にまとめ、パッケージの参照を、単一方向かつ最小限に設計する。

そのパッケージ単位に、Eclipse のプロジェクトにして、開発を進める。
プロジェクト参照にしておくことで、下のレイヤ(プロジェクト)のドメインオブジェクトは、上のレイヤ(プロジェクト)のドメインオブジェクトを参照できなくなる。

こうやって、依存関係をかなり厳しく制約することで、安定したドメインモデルの設計・実装ができると思っている。

この開発案件では、この方式にこだわってみようと思う。

実際には、パッケージレベルでは、双方向に参照したくなる、ケースもでてきそう。
その場合、その原因になっているドメインオブジェクトの再モデリング、設計の改善ネタを発見したということ。

まあ、双方向の参照を許したほうが、目先の設計・実装は簡単になることはわかっている。

でも、そこをがんばって、設計改善することが、グローバル変数の悪夢、スパゲティコードのアンチパターンから抜け出す、足がかりだと思う。

まあ、ここらへんも、やりながら、いろいろ設計・実装ノウハウをためていこうと思う。

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