業務ロジックの整理 〜三層+ドメインモデルの構築〜

クラスとはデータとロジックを一つのプログラミング単位としてまとめるための仕組みであり、データをインスタンス変数として持ち、それに対するロジックをメソッドに書くのがオブジェクト指向におけるクラスの本来の使い方である。

データとロジックを別のクラスに分けるとわかりにくさが発生する

三層アーキテクチャを採用しても、データクラスと機能クラスを分ける手続き型の設計のままでは以下の状況が起こりやすくなる。

  • 変更の対象箇所を特定するために、プログラムの広い箇所を調べる
  • 一つの変更要求に対してあちこちの修正が必要
  • 変更の副作用が起こっていないことを確認する大量のテストが必要

この要因としては、手続き型の設計では業務ロジックが入り組んでくると次の問題が顕著になるからである。

  • プレゼンテーション層、アプリケーション層、データソース層がそれぞれデータクラスにアクセスできるため、
  • 同じ業務ロジックがあちこちに書かれる
  • どこに業務ロジックがか書いてあるか見通しが悪くなる
  • 業務ロジックをアプリケーション層に集約したとしても
    • 機能クラスが画面と密結合になる
      • 画面と機能クラスを一対一で関連付けると、複数の機能クラスでロジックが重複する可能性が高い
    • 機能クラスがテーブルのCRUD操作単位での設計になる
      • たとえば注文テーブルのCRUD操作と出荷テーブルのCRUD操作をそれぞれ別の機能クラスとして実装した場合、合計金額導出ロジックをどこに置くべきか明確でなくなる
  • 共通機能ライブラリを作ったとしても
    • 通化できそうなロジックでも、ユースケースによってニーズが微妙に異なる
      • それらのニーズに対応するため、メソッドにオプションやフラグを渡すことになり、使い方が煩雑になる
    • そうなると、用途ごとに細分化されたメソッドが大量に定義され、結果的にコードが重複する

データとロジックを一体化する

  • メソッドをロジックの置き場所にする
    • クラスにインスタンス変数を返すだけのゲッターメソッドだけがある状態ではデータクラスと何も変わらない
    • 何かしらのロジックをもたせる(データをgetする側のクラスではそれを使って何かをしたいはず)
    • その「何か」のロジックが重複することを防げる
  • メソッドは必ずインスタンス変数を使う
    • もし使わない場合、そのメソッドの置き場所は不適切
    • データを持つクラスに移動させる
  • クラスが肥大化したら小さく分ける
    • 関連性の強いデータとロジックを新しいクラスに分ける
    • 凝集性が高まる
    • 関連性の強いデータとロジックをもったオブジェクトをドメインオブジェクトという
    • 小さなドメインオブジェクトを組み合わせて大きな業務の関心事を表現するクラスを設計する

三層のそれぞれの関心事と業務ロジックの分離を徹底する

データとロジックをドメインオブジェクトとして小さな単位に分けて整理すると、クラスの数が膨大になるため、整理する必要がある。

  • 様々なドメインオブジェクトを関心事の単位にグルーピングしてパッケージに分けることで整理
  • パッケージの参照関係も含めて整理する
ドメインモデル方式

業務アプリケーションの対象領域(ドメイン)をオブジェクトのモデルとして整理したもの(ドメインオブジェクトの集合)をドメインモデルという。

  • ドメインモデル方式では、ドメインモデルに集めた業務ロジックを三層が利用する形になる。
  • ドメインモデル方式では画面やデータベースの都合から独立して、純粋に業務の観点から業務ロジックを整理できる。

三層+ドメインモデルの各レイヤーの役割は以下のようになる。

  • プレゼンテーション層:UIなど外部との入出力を受け持つ
  • アプリケーション層:業務機能のマクロな手順の記述
  • データソース層:データベースとの入出力を受け持つ
  • ドメインモデル:業務データと関連する業務ロジックを表現したドメインオブジェクトの集合