そのドメインにおいて重要な概念をコードで暗黙的に表現してしまうと、
概念を表現するためのロジックが散らばって保守性が低下したり、
概念を表現するのを忘れてバグに繋がったり、
といったケースを現場でよく見かけます。
この記事では以下についてまとめました。
- 重要な概念をコードで暗黙的に表現すると何が悪いのか??
- ドメインエキスパートとの会話で重要な概念に気づくには??
- 重要な概念をコードで明示的に表現する例
重要な概念をコードで暗黙的に表現すると何が悪いのか??
僕の経験上これらに陥りやすくなります。
- 概念をコードで表現するのを忘れたり間違える
- 至る所に同じような概念を表現して保守性が低下する
例えばとあるショッピングサイトにおいて、
商品を購入する際の購入数について考えてみます。
そのショッピングサイトでは
購入数はマイナスやゼロを指定することは許容せず、
発送時の梱包の都合上1回の注文あたり1商品で指定できる購入数は5個までとします。
この場合購入数という概念は重要な意味を持っています。
この購入数を暗黙的にコードで取り扱うということは、
例えばint型で取り扱い、
注文ユースケースの中でバリデーションチェックをして。
int型ではマイナスの値もゼロも5よりも大きな値も許容されるので、
購入数を取り扱う注文ユースケースでは常にショッピングサイトで許容する購入数の範囲内かどうかを
心配しなければなりません。
例えば価格をコードで表現できるか?と考えるとInt型でも良いと判断できる。
価格がこのドメインでどのように機能するか?を理解できているとマイナス値はありえないから
Int型ではダメだと判断できる。
では、
注文ユースケースが今まで店頭注文だけだったものが、
オンライン注文、予約注文などユースケースが増えていくとどうでしょう??
これらに購入数の概念を忘れずに同一の表現ができるでしょうか??
自分は表現を忘れていたり、表現をしているものの微妙にずれてしまって、
注文の経路によって挙動が異なるというようなケースにも現場で何度か遭遇したことがあります。
また、購入数をint型で取り扱っているため、
注文ユースケースの中でも、
厳密に購入数を取り扱わなければならない箇所では、
事前にバリデーションチェックされているにも関わらず
念の為もう一度バリデーションチェックをしたくなります。
特に開発チームが分かれている場合に、
1つのユースケースを通しで見ると同じバリデーションを何度も行っているケースに現場で遭遇したことがあります。
この状況で購入数のルールが変更になると至る所に表現されたルールを漏れなく変更できるでしょうか??
ドメインエキスパートとの会話で重要な概念に気づくには??
先ほどまでは、
ドメインエキスパートとの会話で開発者が重要な概念と認識できていたけど、
コードで明確に表現できていなかった例について見てきました。
一方で、開発者が重要な概念としてそもそも認識できないまま
重要な概念を暗黙的に取り扱ってしまったり、
開発者が勝手に概念を作ってコードで表現しているケースも現場ではよく見かけます。
ここからは、
自分が普段現場で実践していることを紹介します。
まず、設計が歪になっていたり実装が複雑すぎる場合、
僕はドメインエキスパート(と可能なら当時の開発担当者に機能)に
機能が必要な背景や目的を確認するようにしています。
なぜこの機能が必要で、目的は何でどういう価値を届けているのかを聞くと、
そこまで複雑な仕様や実装にする必要はなかったり、
シンプルな代替案で十分というケースは
自分の経験ではよくありました。
また、
ドメインエキスパートとの会話の際に登場する用語や概念には、
歪になっている設計を改善するヒントが隠されています。
聞き逃さないように注意しましょう。
例えば、
会話で登場していない概念や用語をコードで表現したり、
会話で登場する概念を全然コードで表現できていなければ、
ドメインエキスパートが思い描いているドメインモデルとコードが乖離してしまい、
設計が歪になり、
ソフトウェアが本来の価値を発揮したり目的を達成できない。
ソフトウェアが動いたけど変更が難しい。
といったことに陥る可能性があります。
ドメインエキスパートとの会話やコードを確認する際、
僕はこの辺りを意識するようにしています。
「ドメインエキスパートとの会話で頻繁に登場する概念や用語は何か?」
「ドメインエキスパートが端的に概念を表現している用語は何か?」
「開発側が利用する用語はドメインエキスパートに伝わっているか?」
「重要な概念をコードで明示的に表現できているか?」
「変更のたびに複雑さが増している箇所はないか?」
「コードで複雑に手続き的に表現しているがドメインエキスパートに正確にそれを伝えられるか?」
重要な概念をコードで明示的に表現する例
ここまで
重要な概念や用語を明示的にコードで表現する必要性
どうやって重要な概念や用語を発見するか
について説明してきましたが、
最後に、重要な概念をコードで明示的に表現する方法についてみていきましょう。
例えば、とある取引業務で取り扱える金額には制限がある場合、
以下のような値オブジェクトを用意したりします。
data class TransactionAmount(
val amount: Int,
) {
init {
if(amount < 0 || amount > 1_000_000) {
throw IllegalArgumentException("取引金額が不正です")
}
}
}
これによって、
TransactionAmountを取り扱うクライアント側のコードは、
TransactionAmountのインスタンス化に成功して引き渡された時点で
取引業務での制約を満たす金額であることを疑う必要はなくなります。
また、IDEなどでTransactionAmountを利用する箇所を検索可能となり、
どういう機能で取引金額を利用しているのか影響調査もしやすくなります。
もし、Intなどのプリミティブ型で表現していたら、
クライアントはマイナスや1億などの数値の可能性を常に疑う必要が出てきて、
TransactionAmountのinitに記述しているような
バリデーションチェックが至る所に散らばる危険があります。
(いくつかもうちょっといい例を作ってみます・・・)
まとめ
コードで手続き的に暗黙的に表現している概念が、
実はそのドメインの中で重要な概念だったりする可能性もあります。
それを見落とさずに明示的にコードで表現することで、
ソフトウェアの価値を高め、変更に強いソフトウェアに
一歩ずつ近づくのだと思います。
今回のテーマについては以上です。
DDD実践のためのきほんシリーズのまとめ記事を作りました。
是非こちらもご覧ください。
![](https://poppingcarp.com/wp-content/uploads/2022/02/ddd-summary_rewrite_1-160x160.png)
第9章 暗黙的な概念を明示的にする
エリック・エヴァンスのドメイン駆動設計