👌

【オブジェクト指向】アプリケーション機能を組み立てる

2022/09/21に公開

現場で役立つシステム設計の五章を読んだのでメモします

ドメインオブジェクトを使って機能を実現する

アプリケーション層のクラスの役割

  • プレゼンテーション層からの依頼を受ける
  • 適切なドメインオブジェクトに判断/加工/計算を依頼する
    - プレゼンテーション層に結果(ドメインオブジェクト)を返す
    - データソース層に記録や通知の入出力を指示する

三層+ドメインモデルのアプリケーション層のクラスは、プレゼンテーション層に対して、業務サービスを提供する。業務サービスを提供するという意味で、アプリケーション層のクラスをアプリケーションサービスクラス、または単にサービスクラスとよぶ。

アプリケーション層の実装が膨らみ、見通しが悪くなったり思わぬ副作用が起きないように次の3つの方針を徹底する。

  • 業務ロジックは、サービスクラスに書かずにドメインオブジェクトに任せる(サービスクラスで判断/加工/計算しない)
  • 画面の複雑さをそのままサービスクラスに持ち込まない
  • データベースの入出力の都合からサービスクラスを独立させる

サービスクラスを作りながらドメインモデルを改善する

オブジェクト指向の変更容易性は段階的な開発を可能にする。
段階的に開発するときに大切なことは、コードを追加したり修正するたびに、クラスの設計や、クラスとクラスの関係を見直しながら、設計の改善を積み重ねること。

業務アプリケーションを段階的に作っていく時に、サービスクラスのメソッドに業務ロジックを直接書いてしまうことが最も手っ取り早い場合があるが、そうすると、手続き型のプログラミングで起こりがちなコードの重複が始まる。
見通しが悪くなり、変更が厄介になる。

データベースとの入出力が入り組んできて、処理の流れがデータベース操作の手続になり始めたら、リポジトリの設計やドメインオブジェクトの設計を見直す。
テーブル設計を変えることで、データベースをもっとシンプルにできるかもしれない。

初期のドメインモデルは力不足

初期はドメイン知識が浅いため、業務ロジックが貧弱になりがち。開発していく過程で業務知識を新たに獲得した際、業務ロジックを追加する方法は以下二つ。

  • ドメインオブジェクトを追加したり修正してドメインモデルを充実させる。
  • 不足している業務ロジックをサービスクラスに直接書いてしまう

動かすだけでは後者の方が簡単だが、異なるサービスクラスに同じ業務ロジックが重複する問題を引き起こす。

ドメインモデルに追加、変更

サービスクラスに書いているときに、業務ロジックの不足に気が付いたら、ドメインモデルに追加する。適切なドメインオブジェクトがなければ、適切な名前が思い浮かばなくても、とにかくドメインモデルにクラスを追加する。
業務ロジックの置き場所が明確になり、他のサービスクラスとの同じロジックの重複を防げる。
逆に、ドメインオブジェクトの変更が、業務的な繋がりとは異なるサービスクラスに影響が出た場合は、ドメインオブジェクトの設計に問題がある。業務の関心ごとと整合するように、ドメインオブジェクトを分けたり、同じドメインオブジェクトに別のメソッドを追加するなどの改良を試みる。

画面の多様な要求を小さく分けて整理する

プレゼンテーション層に影響される複雑さ

サービスクラスは、プレゼンテーション層からの依頼を受ける窓口。
ドメインモデルが充実していれば、サービスクラスのメソッドはシンプルに保てビスの依頼元のプレゼンテーションが原因で複雑になりがち。

例えば、商品情報や顧客情報を編集する画面は、全ての情報項目を編集でkる「なんでも編集画面」になりがち。
サービスクラスは入力された内容や利用者の利用履歴や個人設定などをもとに場合ごとの対応をする必要がある。
画面の多様な要求をサービスクラスの一つのメソッドに押し込めると、メソッドはif文だらけになり、判断と分岐の流れを追うだけでも大変になる。
サービスクラスをシンプルに保ち、変更を楽で安全にするためにはどうすれば良いか。

小さく分ける

オブジェクト指向設計の基本は小さく分けて独立させた部品を用意すること。対象が複雑な時は小さな単位に分けて、その後でそれらを組み合わせて目的を実現する。

サービスクラスの設計も、まずサービスの独立性の高い部品に分けることを考える。
サービスの全体をいきなり実現しようとせず、部品を作りながら、全体を組み立て、組み立てながら部品を調整する。
サービスクラスを小さく分ける基本は、まず登録系のサービス参照系のサービスを分けてしまうこと

系統 説明
登録系 プレゼンテーション層から渡された情報を検証し、加工や計算をおこなたt上で、記録したり通知したりする
参照系 プレゼンテーション層の依頼に基づき情報を生成し、プレゼンテーション層に戻す機能

登録系のサービス

  • 状態を変更する副作用を伴う。
  • 適切な状態を管理するために事前の確認や、事後の確認が必要になる。
  • 状態の不整合などを検知した場合の例外的な処理を記述する必要もある。

参照系のサービス

  • 副作用なし。

上記のように参照系のサービスと登録系のサービスをクラス単位で分けることによって、複雑さが切り分けられ、業務ロジックの整理がしやすくなる。
画面からの要求は表面的には参照と登録が一体になっていることがよくある。
具体例)

  • 引き出したい金額を入力する
  • 残高が不足していなければ残高を更新する
  • 更新後の残高を画面に表示する

Discussion