Closed11

『エンタープライズアプリケーションアーキテクチャパターン』要点・考えたことメモ

ピン留めされたアイテム
susansusan

Djangoに引きつけて考えたことメモ

Djangoの設計思想にあるように、DjangoのModelはアクティブレコードとのこと。
設計思想に「Include all relevant domain logic」「all the information needed to understand a given model should be stored in the model.」などと書かれているし、
Modelにドメインロジックのメソッドを実装していくのがDjango公式の推奨? なのかも?

ModelのManagerはテーブルモジュール的なクラスだし、QuerySetはQuery Object的(第13章 13.2で解説されているが、本記事では割愛)なクラスのように思える。
カスタムManagerやカスタムQuerySetにビジネスロジックを実装するのは気が引けるが、共通的に使うクエリを実装するパターンはよく見る。

susansusan

マーチン・ファウラー著『現場で役立つシステム設計の原則 ~変更を楽で安全にするオブジェクト指向の実践技法』(ISBN-10: 4798105538) の主要部分を読んだ。

アーキテクチャ設計について、そもそもの用語定義や具体例を深堀りしたく最古典(原著は2002年、邦訳は2005年発行)のこれを読んでみた。
誤訳が多いとのことで一部原書と対応させつつ読んだ。

自分に役立ちそうな要点をまとめたり、考えたことをメモする。
私はDjango使いなのでDjangoに引きつけて考えたこともメモする。

susansusan

「第1章 レイヤ化」要点まとめ

3つのレイヤ

1. プレゼンテーションレイヤ: サービスの提供、情報の表示、HTTPリクエスト、コマンドライン呼び出し、バッチAPI
2. ドメインレイヤ: システムそのものであるロジック
3. データソースレイヤ: データベース、メッセージングシステム、トランザクションモニタ、その他のパッケージとの通信

ドメインロジックと他のロジックの見極め方

  • ドメインロジックがプレゼンテーションにはみ出ている: Webアプリにコマンドラインインタフェースを追加するように、全く異なるレイヤを追加することを想像する。このときに機能を複製する必要があれば、はみ出ている
  • ドメインロジックがデータソースにはみ出ている: 同様に、RDBをXMLファイルで置き換えるためにロジックを複製する必要があるかを想像する
  • 具体例: 製品一覧を考える。前月よりも10%販売増となった製品を赤字で表示する。 当月と前月の比較をプレゼンテーションレイヤに配置した場合、ドメインロジックがプレゼンテーションに入り込んでいる。ドメインレイヤ側で比較結果の論理値を計算するべきだ
susansusan

第1章 考えたこと

具体例: 製品一覧を考える。前月よりも10%販売増となった製品を赤字で表示する。 当月と前月の比較をプレゼンテーションレイヤに配置した場合、ドメインロジックがプレゼンテーションに入り込んでいる。ドメインレイヤ側で比較結果の論理値を計算するべきだ

経験的には、製品一覧が大量である場合、ドメインレイヤ側で製品をループで回して1つ1つ比較結果の論理値を設定するよりも、SQLクエリ側で論理値を計算したほうが高速そうだ。
(出版時の時代背景に根ざした記述かもしれないが。)
なので、むしろデータソースレイヤにこのロジックを記述するほうが良さそうに思える。

『現場で役立つシステム設計の原則』でも「すべての業務ロジックをドメインモデルに任せる」旨があったが、アーキテクチャの都合に合わせて性能が悪化するのを許容するのは避けたほうが良さそうに思える。

susansusan

「第2章 ドメインロジックの構築」要点まとめ

ドメインロジックの3パターン簡易解説(詳細は後述)

  1. トランザクションスクリプト: 手続きを1つずつ構築する。いくつかのサブルーチンに分割されそれらを共有できる
  2. ドメインモデル: ドメイン内の名詞について体系化したモデルを構築する。妥当性確認や計算のロジックはドメインモデルに配置する
  3. テーブルモジュール: テーブル毎に1つのクラス(またはモジュール)を用意し、その中にビジネスロジックをまとめる

これら3パターンは相互排他的な選択肢ではない。併用することは珍しくない。

3パターンの関係

サービスレイヤについて

ドメインレイヤを上下2分割することを考える。
この場合サービスレイヤを、ドメインモデルまたはテーブルモジュールの上に配置する。
サービスレイヤは明確なAPIを提供し、トランザクション制御等を行う。

サービスレイヤにどの程度振る舞いを置くか

  • 最小限にする場合: 実際の振る舞いはすべて下位のドメインオブジェクトに移譲する。サービスレイヤはユースケース中心となる
  • 最大限にする場合: サービスレイヤ内をトランザクションスクリプトとし、ビジネスロジックをそこに置く。下位のドメインオブジェクトはシンプルであり、アクティブレコードパターンなどのシンプルなデータソースレイヤを使うことができる

著者(ファウラー)が気に入っている方法

サービスレイヤをできる限り薄いレイヤにする。
本来ならサービスレイヤは1つもいらないという前提で、アプリケーションに必要と思われる場合だけ追加する。

susansusan

第2章 考えたこと

最も驚いたことは、
ファウラー自身はドメインモデルが最推しであるかのような印象を受けるが、
3パターンを比較したグラフの「見えている範囲」においては、
テーブルモジュールが「機能追加の労力」が最も小さい領域の線分が一番長いこと。

たしかに「ドメインロジックの複雑性」 → ∞ の時、ドメインモデルが最も発散速度が遅い。
そのことを強調したいのならもっと横に長いグラフにするべきだったと思うのだが。

第8章で「上記3つの中でも、適合するツールがある場合は、テーブルモジュールが群を抜いている。」と書いているし、実はテーブルモジュールが一番扱いやすいということなのかも。

susansusan

「第9章 9.1 トランザクションスクリプト」要点まとめ

トランザクションスクリプトとは、
「ビジネスロジックを一連の手続きで構築して、プレゼンテーションからの要求を処理する」。

どう配置するか

ファウラーはトランザクションスクリプトを使う場合、できる限り分離させることを好む。
プレゼンテーションやデータソースの処理とは異なるクラスにまとめる。
トランザクションスクリプトからプレゼンテーションロジックを呼び出さないようにする。

使用するタイミング

トランザクションスクリプトのメリット

  • シンプルさ
  • ロジック量が少ないアプリケーションに適する
  • パフォーマンス面、開発者の理解の面でオーバーヘッドがほとんどない

トランザクションスクリプトのデメリット

  • ロジックが複雑になるにつれて、コードの重複が起きやすい

ドメインモデルとの選択

複雑なビジネスドメインでは、トランザクションスクリプトではなく、ドメインモデルの構築が必要となる。そのカットオーバーレベルを見定めるのは難しい。
トランザクションスクリプトからドメインモデルにリファクタリングするのは難しい。初期段階で対応するのがよい。
しかし頑固なオブジェクト主義者でも、トランザクションスクリプトをすべて除外するべきではない。世の中にシンプルな問題は数多くあり、シンプルな解決策の方が素早く対処できるからだ。

コード例: 収益認識の問題

本書のトランザクションスクリプトのJavaコード例では以下のような問題が取り上げられている。

ワープロ、データベース、表計算という3つの製品を販売している会社を考える。
3製品はそれぞれ収益を計上するタイミング(ロジック)が異なる。

トランザクションスクリプトでは、
RecognitionService.calculateRevenueRecognitions() にて、
製品のタイプをif ~ else if 文で判定し、
各タイプ毎に異なるロジックで収益認識テーブルにレコードを追加する。

なおデータベースとの相互作用は、
preparedStatementを使用してSQLを発行する処理がゲートウェイクラスのメソッドでラップされる実装となっている。
susansusan

「第9章 9.2 ドメインモデル」要点まとめ

ドメインモデルとは、「振る舞いとデータを一体化させたドメインのオブジェクトモデル」。

データベースモデルとの違い

ドメインモデルではデータとプロセスが一体化され、さらに継承が使われる。

ドメインモデルの2形式

  1. シンプルなドメインモデル: データベーステーブルごとに1つのドメインオブジェクトを持つ。アクティブレコードが適する
  2. 豊富なドメインモデル: 継承、ストラテジー、GoFのデザインパターンや、相互関連する小さなオブジェクトが複雑に絡み合う構造を持つ。複雑なロジックを扱う。データベースにマッピングする際は、データマッパーが必要となる

ドメインオブジェクトの肥大化

表示用途など、特定用途向けの振る舞いをドメインオブジェクトに入れ込むとクラスが肥大化する。
しかし、振る舞いを分離すると重複の問題が発生しうる。
ファウラーは、特定用途向けの振る舞いもドメインオブジェクトに含め、肥大化したら修正することを推奨している。つまり、肥大化は一定許容し、重複が発生しないことを重視している。

使用するタイミング

ドメインモデルをいつ使用すべきかは、開発チームが、ドメインオブジェクトを扱うスキルがあるか否かも重要な要素となる。ドメインモデルに慣れるまでには相当の訓練と学習を必要とする。

コード例: 収益認識の問題

本書のJavaコード例では、トランザクションスクリプトのコード例と同様の収益認識の問題が登場する。
以下の様になっている。

ワープロ、データベース、表計算という3つの製品を販売している会社を考える。
3製品はそれぞれ収益を計上するタイミング(ロジック)が異なる。

ドメインモデルでは、ストラテジーパターンが示される。
多態性を利用して、呼び出し時の実際のインスタンスのクラスに応じて条件分岐がなされ、
各タイプ毎に異なるロジックで収益認識インスタンスを作成する。

ドメインオブジェクトたちは協調して働く。
Contract(契約)がProduct(製品)をインスタンス変数として持ち、
ProductはRecognitionStrategy(収益認識ストラテジー)をインスタンス変数として持つ。
product.calculateRevenueRecognitions()内で多態性を利用して、
recognitionStrategy.calculateRevenueRecognitions()に処理を移譲するような形となっている。

なおデータベースとの相互作用は実装からオミットされている。
susansusan

「第9章 9.3 テーブルモジュール」要点まとめ

テーブルモジュールとは、「データベーステーブルのすべての行に関するビジネスロジックを扱うシングルインスタンス」。
この説明だとよくわからないが、テーブル毎に1つのクラス(またはモジュール)を用意し、その中にビジネスロジックがまとまっているパターン。

ドメインモデルとの比較

ドメインモデルパターンでは、RDBを大抵無視している。その結果、DBとデータをやりとりし、二つの異なる表現の間で変換するために、かなりのプログラム的な工夫が必要になってしまう。
テーブルモジュールとドメインモデルの違いは、ドメインモデルは1つのエンティティに1つのオブジェクトが使われるが、テーブルモジュールは1つのオブジェクトで全てのエンティティを扱う点。

動作方法

テーブルモジュールはSQL呼び出しの結果であるテーブル形式のデータ(レコードセット)を扱う。
テーブルモジュールは、データに対してメソッドベースのインタフェースを利用できる。
テーブルモジュールはインスタンスの場合もあれば、静的メソッドが集まったものの場合もある。

使用するタイミング

テーブル形式のデータ(レコードセット)とともに使うのが理にかなっている。
ただしテーブルモジュールでは、ドメインモデルのように、オブジェクト間での直接的な関係を築くことや、ポリモーフィズムを機能させることができない。
複雑なロジックを扱えるドメインモデルを取るか、テーブルデータと簡単に統合できるテーブルモジュールの統合性を取るか、という問題になる。
ドメインオブジェクトとデータベーステーブルが類似している場合、アクティブレコードを使うドメインモデルのほうが適しているだろう。

susansusan

「第8章 まとめ」要点まとめ

この章ではエンタープライズアプリケーションを設計する際にどのパターンを使うべきかを検討している。

ドメインレイヤ

トランザクションスクリプト、テーブルモジュール、ドメインモデルのどれで行くか。
最も強い影響を与えるのは、ドメインロジックの複雑性。
また、データベースとの接続の難しさも決定に影響を及ぼす。

最もシンプルなのはトランザクションスクリプト。
理解しやすいが、重複コードが起こりやすい問題がある。

対極がドメインモデルで、複雑なドメインロジックを扱える。
しかし、適切に設計するのにスキルが必要だ。
またRDBとの接続が難しい問題がある。

テーブルモジュールは上記2つの中間に位置する。
ドメインロジックはトランザクションスクリプトよりも扱いやすいし、RDBとうまく適合する。

理論的には逆であるべきだが、
アーキテクチャの方をツールに合わせなくてはならないことのほうが多い。
上記3つの中でも、適合するツールがある場合は、テーブルモジュールが群を抜いている。

データソースレイヤ

ドメインモデル用のデータソース

ドメインモデルの最大の弱点はデータベースとの接続が複雑なこと。
DBに隣接する20~30のクラスで構成されるようなシンプルなドメインモデルの場合、アクティブレコードが適切。
もう少し複雑な場合は、データマッパーが必要。この手法は、ドメインモデルを他のレイヤに依存しないものにする。一方で、データマッパーは最も実装が複雑なものの1つである。

susansusan

「第10章 10.3 アクティブレコード」要点まとめ

アクティブレコードとは、「テーブルの行をラップし、データベースアクセスをカプセル化してデータにドメインロジックを追加するオブジェクト」

動作方法

アクティブレコードの本質はドメインモデルである。
アクティブレコードはDBへの保存や読み込みを行い、
またデータに適用されるドメインロジックの役割も果たす。

アクティブレコードのデータ構造は、DBのデータ構造と完全一致している必要がある。つまりクラス内のフィールドはテーブルのカラムと一致する。

使用するタイミング

ドメインモデルの設計で最初に判断するべきは、アクティブレコードかデータマッパーのいずれを使用するかだ。
アクティブレコードのメリットはシンプルな構造。
問題は、アクティブレコードが有効なのは、アクティブレコードオブジェクトがテーブルと同一構造スキームの場合だけという点。
ビジネスロジックが複雑な場合には、コレクションや継承を使用したいと考えるようになり、データマッパーの使用を考えるようになる。

このスクラップは2ヶ月前にクローズされました