はじめに
どうも、なんか中途半端シリーズが多い(OWASP ASVSとかそのうちやります)さばかんです。
今回は、エリック・エヴァンスのドメイン駆動設計についての本を読んでいるのでアウトプットがてら色々まとめていこうかなと思います。
以下に今回、読んでいく本のAmazonリンクを提示しておきます。
ぜひ一度読んでみてください(僕も頑張ります)
※あくま私個人というフィルターを一度通したものになっています。解釈違いなど正確に読み取れていない部分も含むかもしれないので、悪しからずご了承ください。
序章
- モデルとは?
→ 問題を解決する上で関連する側面を抽象化し、それ以外は無視する。現実に対する1つの解釈である
- ドメインとは?
→ まず全てのソフトウェアプログラムは、使用するユーザーのなんらかの活動や関心と関係ある。
ユーザーがプログラムを適用するこの対象領域が、ソフトウェアのドメインである。
ドメインは物理的な世界も含む物もある。
例:航空機に搭乗する予約するシステムだったとする。
- プログラムのドメイン(領域)は実際に飛行機に乗る人も含まれる。
含まない場合
例:会計プログラム
- ドメイン(領域)は金銭と財務
例外としてソフトウェア開発そのものがドメインのもの
例:ソースコード管理システム
- ドメイン(領域)はソフトウェア開発
このようにユーザーに利用してもらうソフトウェアを開発するためには様々な体系化された知識を身につけなくてはならないしこの膨大な情報量に圧倒されるかもしれない。
これらと戦うためにモデルというツールを利用する。
結局としてモデルは選び抜かれてシンプルにされ意図的に組み立てられた表現形式である。
ドメインモデルとは??
特定の図を指すわけではなく、図が伝えようとしている考え方。
ドメインエキスパート(対象の領域の専門家)の頭の中にある知識が厳密に構成され、選び抜かれて抽象化されたもの
である。
簡単に近しい例として、映画制作や動画制作がある。
体験したことの側面をいくつか選び出し、独特な手法で動画の内容やストーリーを強調する。
別に未編集なものを世に提供しているわけではない。
この彼らと同じようにドメインモデラも、実用のために特定のモデルを選択する。
DDDにおけるモデル有用性
DDDの3つの基本思想
1.モデルと設計の核心が相互に形成し合う
- モデルと実装が結びつけられることによって、モデルとドメインは深く関連したものになる
- 保守性にも有用である、モデルの理解に基づいてコードを解釈できるから
2.モデルは、チームメンバー全員が使用する言語の基盤である。
- モデルと実装が紐づいているので開発者とドメインエキスパートは通訳要らずに話すことができる
3.モデルとは、蒸留された知識である。
- モデルとはドメインの知識を構成して最も関連のある要素と区別するためにチームで取り決めた方法(蒸留)である
ソフトウェアの核心
ソフトウェアの核心とは
→ ドメインに関連したユーザーのために解決する能力である
問題点として、あまりソフトウェアの核心について考えて設計している人は少ない。
第1章:知識を噛み砕く
全く知らないドメインに関してどうアプローチするのか
1.モデルと実装を結びつける
筆者は具体的には早い段階で荒削りなプロトタイプを作成して本質的なモデルと実装の結び付けを行い、イテレーション通してずっと維持された。
2.モデルに基づいての言語を洗礼させる
モデルが洗礼されていくと、通訳の必要がなくなり、メンバー全員がモデルから用語を取り出し、会話できるようなった。
3.知識豊富なモデルを開発する
モデルは単なるスキーマではなく、振る舞いや守るべきルールを包括しているので複雑な問題への解決のアプローチとして欠かせないものだった。
4.モデルを蒸留する
不要な概念をが必要な概念と結びついている時には、本質的な概念を切り分け、不要なものを削除できるようなモデルを探した。
5.ブレストと実験を行う
言語をスケッチやブレストとの組み合わせにより、実験室となった。
バリエーションを出し、実験し使えるかの判断素材を多く得た。
このようにして、知識を噛み砕くことで、チームの持っている知識が価値のあるモデルへと変わっていく。
知識の噛み砕きについて諸々
開発者がドメインに対する興味などがなかったらドメインに対する背景などが読めずに実装が簡素なものになったり、強力な新規機能が現れることは決してない
また、ドメインエキスパートとの共同作業がない場合にも、その概念は素朴なものにしかならない。
すなわち、ドメインエキスパートとの考え方と深く結びつくことはないということ
チームメンバーとはメンバ全員がモデルを一緒に噛み砕くことで、変化する。
噛み砕いていくうちに、ビジネスにおける重要な原理を理解していけるようになる。
継続的学習
まず、大前提として 『ソフトウェアを書き始める時、我々は対象を十分に理解しているわけではない』
自分がどれだけ無知かを理解していないことによって、誤った想定をしてしまう。
一方で、知識は流出していっている。何かを会得したが違うところへ移動となれば知識が断片化して、口頭などの伝承の場合は途中で途切れたら、知識が失われてしまう。
だが、高度な生産的なチームは、自ら知識を意識的に育てる継続的学習を実施する。
技術の勉強やドメインモデリングに対しての勉強も含まれる。
こうして、自ら学んだメンバーは最も重要な領域を含む開発作業におけるコアメンバーとなる。
つまり、自ら学んで継続的に学習している人はチームでもコアメンバーになり、そのような人が多いチームは生産性もより高度で高くなっていくよねって話。
簡単な例で
例えば、会社に来場する客を予約するシステムだったとする。
ここで欲しい機能は予約となるが、キャンセルも考慮したい。
そこで以下のようなメソッドが考えられる。
class ReservationService:
def book(self, customer, company, time):
return Reservation(customer, company, time)
来場者が会社に対して予約を行う、というシンプルな構造です。
要件の追加
基本機能は「予約」ですが、次のような要件が追加されるとします。
• キャンセルが発生することを想定し、定員の1.2倍まで予約可能とする
このようなルールをそのまま book() メソッド内に直接書いてしまうと、以下の問題が発生します:
• ビジネスルールの意図が読みにくい
• ドメインエキスパート(業務担当者)に説明しづらい
• 責務の分離が不十分になる
例えばbook()メソッドに追加した場合このようになる。
ドメインクラス(悪い例)
class ReservationService:
def book(self, customer, company, time, current_reservations, capacity):
if len(current_reservations) >= capacity * 1.2:
raise Exception("定員を超えています")
return Reservation(customer, company, time)
解決策:ポリシーに切り出す
DDDでは、複雑なビジネスルールを「ポリシーオブジェクト」として切り出すことで、責務が明確になります。
ポリシークラス
class ReservationPolicy:
def can_accept(self, current_reservations, capacity):
return len(current_reservations) < capacity * 1.2
ドメインサービスメソッド(抜粋)
def book(self, customer, company, time, current_reservations, capacity):
if not self.policy.can_accept(current_reservations, capacity):
raise Exception("定員を超えています")
return Reservation(customer, company, time)
1章よんでの感想
我々ソフトウェアの専門家として、そのドメインが「何の問題を解決するのか?」を意識しながら設計していくことが大切だと改めて感じました。
また、ソフトウェアの専門家ではあっても、ドメインに対して自分がどれだけ無知であるかを理解し、「何の問題を解決するのか」という本質から外れた誤った設計をしないようにすることも重要だと学びました。
さらに、ドメインについて継続的に学び続けることで背景や事情をより深く理解できるようになり、結果としてそのビジネスに対してより本質的な価値を提供できたり、ユーザーにとって本当に使いやすいシステムを開発できる可能性が高まると思います。
そして、そうした継続的に技術やドメインを学び続ける姿勢が、自ずと開発チームの中でコアメンバーとしての立ち位置を築くことにつながります。そういうメンバーが多いチームほど、生産性が高く、レベルの高い開発ができるチームになるのだと思いました。
DDDの考え方の中で最も大切だと感じたのは、ソフトウェアエキスパートとドメインエキスパートがどれだけしっかりコミュニケーションを取り合い、お互いの領域を尊重しつつ理解し合いながら、モデルを洗練させていけるかという点です。
そのような姿勢が、最終的には強いチームと良いプロダクトを生み出していくのだと実感しました。