Open5

設計とかDDDとかデザインパターンとか。覚えたことをメモしていく

集約外の整合性を担保する方法について

例えば、「タスク集約」と「タスクの活動履歴集約」がある。(設計上、別集約にしたとする。)
「①,タスク集約を永続化するrepository」と「②,活動履歴集約を永続化するrepository」はそれぞれ用意されている。

パターンA:ユースケース(アプリケーションサービス内)で①と②の処理を書く。

このパターンのデメリットは別の人が他のユースケースを実装したときに①のみ実装して集約間の整合性を壊してしまう可能性がある。

パターンB:①と②の処理まとめたtaskCreaterという名前のドメインサービス作成してタスクを登録する際はこのドメインサービスを使うとプロダクト内でルール決めする。

ただ、ルールを逸脱するとパターンA同様に整合性は壊れる可能性はある。

パターンC:ドメインイベントを実装する。

①の処理を検知して、②の処理を動かすようにドメインイベントを実装する。整合性を破壊することはないが、実装コストが高い。
ドメインイベントについて:https://codezine.jp/article/detail/10392

DDDの目的

①,機能性を高めること

  • 役に立つものを作る
  • 「作ったけど使えない」を避ける

②,保守性を高めること

  • 長期間開発しても機能拡張が容易でありつづける
  • 「技術的負債で開発生産性が低下する」ことを防ぐ

目的を達成するために

  • 機能性を高めるために
    • モデリングを行う
  • 保守性を高めるために
    • モデルをそのまま表現する
    • エンティティ、リポジトリなどの実装パターン

設計を上手くするには?

いろいろな設計パターンがあるので覚えるの大変。
1つ覚えるとしたらで高凝集、低結合であること

凝集度

  • モジュール内の要素同士がどれだけ関連しているか?
  • クラスの責務、クラスのメソッドとデータの関連の強さ
  • 高い方が良き
    プロパティが5つあるのにあるメソッドでは2個しか使われていないのは凝集度が低い。

結合度

  • モジュール間の依存度の高さを示す指標
  • 依存度が高い→依存先の修正の影響を受けやすくなる
  • 低い方が良い(低結合、疎結合)

凝集度が低い(Bad)

  • クラスの責務が不明確:このクラスは何をしているクラスなのかを問いかける
  • データと全く関係ないメソッドがある
class OperationUtil( // 責務が曖昧なクラス名
    private var count: Int
) {

    fun increment() {  // なんらかの数値をインクリメント
        count++
    }

    fun greet() { // 保持している数値に関係ない挨拶を出力
        println("Hello!")
    }
}

凝集度が高い

  • クラスの責務が明確、単一
  • 責務、データとメソッドが関連している
class Counter( // 責務が明確なクラス名
    private var count: Int = 0 // クラスの責務と関連が明確なデータ
) {
    fun increment() { // クラスの責務、データと関連が明確なメソッド
        count++
    }

    fun getCurrentCount(): Int {   // クラスの責務、データと関連が明確なメソッド
        return count
    }
}

結合度が高い(Bad)

Printer.print() // 0が出力される

Counter.increment() // 何かしらをインクリメント

Printer.print() // 何が出力される?
// ↑ 1が出力された!!
//  この振る舞いは外側から推測が難しい

// 依存している
object Printer {
    fun print() {
        println(Counter.count) // 処理結果がCounterの内部の値に依存している
    }
}

object Counter {
    var count: Int = 0

    fun increment() {
        count++
    }
}

ドメイン駆動設計との繋がり

  • 責務・凝集度の話は設計を考える上で常に重要

  • アーキテクチャのレイヤー化時に考えることは

    レイヤーによる責務の切り分け」

  • エンティティ、リポジトリなどの設計を考えることは

    • クラスによる責務の切り分け」
  • とにかく責務を考え、凝集度を上げる

  • この原則でかなりの領域をカバーできる

依存関係は循環させてはいけない

プログラムを読みやすく、変更しやすくする方法

  • 名前は略語ではなく、普通の名前で行う
  • 数行のコードを意味のある単位として「段落」に分ける
  • 「目的別の変数」を使う
  • 意味のあるコードのmとまりを「メソッド」として独立させる
  • 業務の関心事に対応したクラス(ドメインオブジェクト)を作る
ログインするとコメントできます