ドメインモデルを成長させていくアプローチ
概要
この記事は、現場で役立つシステム設計の原則〜変更を楽で安全にするオブジェクト指向の実践技法を読み学習した内容を Ruby on Rails のコードに例を変換してまとめ直したものです。
また、書籍では Java のコードを例にしており、Ruby on Rails の慣習とは一部異なる部分があるので、その部分はオミットした内容となっています。
この記事では主に設計したドメインモデルを段階的に改善していくアプローチについて記述しています。オブジェクト指向におけるドメインモデルが何かについては別記事を参照してください。
ドメインオブジェクトの設計を段階的に改善していく
組み合わせて確認しながら改良する
開発を進めていくと、基本パターンを単純に真似ただけのドメインオブジェクトでは、部品として使い勝手が良くないことに気づくことがある。
ドメインオブジェクトは一度作成して完成ではなく、実際にアプリケーションで使用してみて部品としての使い勝手を確認しながら改善を続けていくことが重要。以下の三点が改善ポイントとなる。
- クラス名やメソッド名の変更
- ロジックの移動
- 取りまとめ役クラスの導入
クラス名やメソッド名の変更
他のオブジェクトから使用してみると、使用者目線では、クラス名やメソッド名が適切ではないことに気づくことがある。(同じような名前、抽象度にばらつきがあるなど)
使用する側のコードがわかりやすくなるように、意図の違いがより明確になるクラス名やメソッド名へ改善する。
ロジックの移動
ドメインオブジェクトを使用する側のコードがごちゃごちゃしてきたら、ドメインオブジェクト側にロジックを移動すべき兆候と言える。
本来部品であるドメインオブジェクトが担うべきロジックを部品を使用する側のコードに置いておくと、その部品を使うその他の部分にも同じコードが重複しやすくなるので、部品側にロジックを移動してより多くの仕事をさせるべき。
一旦動かすために部品を使用する側にロジックを追加していくことは問題ないが、動作が確認できたら随時部品側にロジックを移動してドメインオブジェクトを改良していくのが望ましい。
取りまとめ役クラスの導入
ドメインオブジェクトの最小単位は一つの数値・日付・文字列をラッピングした値オブジェクトとなる。
また、コレクションオブジェクトや区分オブジェクトも基本となるドメインオブジェクトとなる。
しかし、それらの基本オブジェクトは、業務の関心事の粒度としては小さすぎるので、粒度として適切な大きさとなる取りまとめ役クラスを導入することで業務の関心事を適切に表現できるようになる。
例えば、複数の値オブジェクトをまとめたAddress
クラスは以下のようになる。
class Address
# コンストラクタ引数は全て値オブジェクト
def initialize(postal_code, city, street, block)
@postal_code = postal_code
@city = city
@street = street
@block = block
end
def as_text
"#{@postal_code.value} #{@city.value} #{@street.value} #{@block.value}"
end
end
最初は、より大きな関心事のクラスから出発して、開発を進めながら段階的に部品を追加していくパターンでも良い。
# 初期状態の顧客クラス
class Customer
def initialize(customer_number, name)
@customer_number = customer_number
@name = name
end
end
# 顧客情報を増やすために住所クラスと連絡先クラスを部品として組み込む
class Customer
def initialize(customer_number, name, address, contact_method)
@customer_number = customer_number
@name = name
@address = address
@contact_method = contact_method
end
end
業務の言葉とコードを一致させると変更が楽になる
コードに登場する名前やプログラムの構造が業務の関心事に直接的に対応しているほど、ソフトウェアの変更は楽で安全になる。
具体的には、ドメインモデルを構成するドメインオブジェクトを以下のような形で設計する。
- クラス名が問題領域の関心事の用語と一致している
- メソッド名が利用者が知りたいこと・やってほしいことと一致している
この設計により、以下のような理由で変更が楽で安全になる
- どこに何が書いてあるのか特定しやすい
- 変更の対象のクラスが、変更の要求の範囲と一致している
- 変更の影響するソフトウェアの範囲が、変更が関連する業務の範囲と一致する
また、業務の関心事をプログラミング言語で記述することで、プログラムの側から、問題領域を深く理解する手掛かりが見つかることがある。
- 同じことを複数の業務用語で表現しているあいまい性
- 一つの業務用語が使う文脈ごとに異なる意図を持つあいまい性
- 業務ルール間の矛盾の発見
- 込み入った微妙な関心事の整理の軸
ドメインモデルは業務を学びながら成長させていく
ドメインオブジェクトを作成するには業務を理解する必要があり、そのためには要件を理解するための「分析」が必要となる。
分析して得た知識・理解はプログラミング言語で表現することが可能。例えば、分析で得た業務用語や言い回しはそのままパッケージ名・クラス名・変数名となる。
そのようにソースコードで業務の要件仕様を表現することをプログラムの自己文書化と呼ぶ。
業務を学びながら、業務知識を増やし、より深く理解していく。そして、その学んだことを自己文書化して、ドメインオブジェクトの設計に反映させていくのがドメインモデルの設計のサイクルとなる。
業務の理解がドメインモデルを洗練させる
業務の背景にある構造を反映した洗練されたドメインモデルを作成するためには、業務知識の広さと深さが必要となる。
しかし、ありとあらゆる業務知識が必要なわけではない。開発者がアプリケーションの対象とする業務を効果的に学び、役に立つドメインモデルを設計するための基本は次の二点となる。
- 重要な言葉とそうでない言葉を見つける
- 言葉と言葉の関係性を見つける
これらを実践する具体的な方法は以下の通り。
「言葉」と「会話」で業務経験者から業務知識の「暗黙知」を引き出す
業務知識は、その業務を実際に経験している人の頭の中にある。
そして、業務の経験者の言葉はクラス名やメソッド名の候補となる。
業務に習熟した業務の専門家と会話し、そういった業務用語を習得することが、ドメインモデルを設計する基本の活動となる。
業務経験者にとっては「自然と体が動く」ような自然なことだが、まだ言語化されていないような「暗黙知」と言える業務知識を「言葉」と「会話」から引き出すことが、開発者が業務知識を獲得し、業務を理解する重要な手掛かりとなる。
「聞きなれない」言葉をキャッチする
業務の専門家と会話するときに、「聞きなれない」言葉や「違和感」のある言葉、あるいは知っているがどうも自分の理解とは違う意味で使われているらしい言葉が色々と出てくる。
業務を深く理解するにはこういった「聞きなれない」言葉を聞き逃さない、また、相手の意図とは違う誤った解釈をしないことが重要になる。
これらの言葉をキャッチするコツは、聞いた後に以下のような方法でアウトプットしてみて専門家に言葉の使い方が適切かどうか確認してもらうこと。
- ホワイトボード(Miro など)
- チャット・メールなどの Q&A(Slack, Discord など)
- ディスカッションボード(Notion など)
- オンラインの ToDo 管理ツール(Jira, Slack など)
重要な言葉を見極めながらドメインモデルに反映していく
開発者が業務の用語を適切に発言するようになると、相手の反応が良くなる。
そして、正しい業務用語を使用しているのに相手の反応が良くない場合は、その言葉はおそらく業務における重要な関心事ではないと判断できる。
また、重要な言葉をキャッチしても正しく理解できていないと、専門家との会話はぎこちないものになる。
業務の経験者にとって自然な言い回しができ、かつ、その内容が業務の重要な関心事であれば、相手の反応が積極的になってくる。
重要な言葉を正しく理解し、業務の文脈で意味が通じるように言葉を組み合わせて語れる状態になれば、その言葉をそのままクラスにし、クラス間の関係を言葉と言葉の関係に対応させれば、ドメインモデルの中核が形となってくる。
形式的な資料は作成せず、重要な言葉と関係性を整理する
形式的に議事録やドキュメントを整えることは、特に大量に作成する場合に「思考停止」が発生し、何が重要で何が重要でないかを判断しなくなる。また、表面的に形式が整っていると、理解ができていると勘違いしがちである。
形式的に詳細なドキュメントを大量に作成するよりも、重要な言葉が何で、骨格となる関係は何かを判断することに時間とエネルギーを使うべきである。
全体を俯瞰しながら要点と重要な関係を理解するためには例えば、以下のような図法が有効となる。
図法名 | 目的 |
---|---|
コンテキスト図 | システムの目的を表す言葉を探す(重要なクラスの発見の手掛かり) |
業務フロー図 | コトの発生を時系列に整理する |
パッケージ図 | 業務の関心事を俯瞰する(用語の全体的な整理) |
主要クラス図 | 重要な関心事とその関係を明確にする |
重要なのは、これらの図はあくまで「考える道具」であること。
業務の知識が広がり、理解が深まるたびに、これらの図の内容は逐次変化していく。そして、公式のドキュメントとして維持する必要はない。
業務知識を増やすアプローチ
ドメインモデル設計のやり方として、対象業務の基本知識を身につけることがスタート地点となる。
業務知識を身につけるために具体的には以下のようなアプローチを順番に行う。
- その業務のマニュアルや利用者ガイドを読んでみる
- その業務の一般的な知識を書物などで勉強する
- その業務で使っているデータに何があるか画面やファイルを調べる
- その業務の経験者と会話する
改善を続けながらドメインモデルを成長させる
ドメインモデルの設計に模範回答や最終回答はない。しかし、「より良い」解答はある。
ドメインモデルの設計とはこの「より良い解答」を探し続けることとなる。
「より良い」解答を探す一つの方法は、関係者で設計レビューを行うこと。
ドメインモデルとして設計したパッケージ名、クラス名、メソッド名が業務の概念や、実際の業務のやり方と整合しているかのチェックを行う。
チェックするポイントは、基本的に「言葉」の使い方である。
具体的には、ドメインモデルに登場する変数名・メソッド名・クラス名・パッケージ名を使って業務の処理の流れを、関係者に意図が伝わるようによどみなく説明できるかどうかをチェックする。
もし、説明が詰まったり、業務の専門家に意図が伝わらなかった場合は、そのドメインモデルの改良を試みる。
業務を深く正しく理解した開発チームが設計したドメインモデルは、業務知識の体系となる。それはつまりプログラミング言語を用いた「業務マニュアル」そのものと言える。
そのような体系的に整理されたドメインモデルを中核としたアプリケーションは、業務ロジックの置き場所が特定しやすく、業務ルールの変更が必要になった時に変更の対処箇所を限定し、変更の影響範囲を狭い範囲に閉じ込めやすくなる。
これがオブジェクト指向で業務アプリケーションを開発する最終的な狙いとなる。
参考文献
この記事は以下の情報を参考にして執筆しました。