プレゼンテーションドメインデータレイヤリング
2015年8月26日
情報量の多いプログラムをモジュール化するための最も一般的な方法の1つは、プレゼンテーション(UI)、ドメインロジック(ビジネスロジックとも呼ばれる)、データアクセスという3つの広範なレイヤーに分割することです。そのため、Webアプリケーションは、HTTPリクエストの処理とHTMLのレンダリングを処理するWebレイヤー、検証と計算を含むビジネスロジックレイヤー、データベースまたはリモートサービスで永続的なデータを管理する方法を解決するデータアクセスレイヤーに分割されることがよくあります。

全体として、これは多くのアプリケーションにとって効果的なモジュール化の方法であり、私自身も定期的に使用し、推奨しています。最大の利点(私にとって)は、3つのトピックについて比較的独立して考えることができるため、注意の範囲を狭めることができることです。ドメインロジックコードに取り組んでいるときは、UIをほとんど無視し、データソースとのやり取りを、必要なデータを提供し、必要に応じて更新する抽象的な関数セットとして扱うことができます。データアクセスレイヤーに取り組んでいるときは、インターフェースに必要な形式にデータを整理することに集中します。プレゼンテーションに取り組んでいるときは、UIの動作に集中し、表示または更新するデータは関数呼び出しによって魔法のように表示されると扱います。これらの要素を分離することで、各部分の思考範囲を狭め、必要な作業を容易に把握できます。
このスコープの縮小は、それらのプログラミングにシーケンスが暗示されるわけではありません。通常、レイヤー間を反復する必要があります。UXの最初の理解からデータとドメインレイヤーを構築することがありますが、UXを洗練する際にはドメインを変更する必要があり、データレイヤーの変更が必要になります。しかし、そのようなレイヤー間の反復があっても、変更を加える際に一度に1つのレイヤーに集中する方が簡単だと感じています。リファクタリングの2つの帽子で得られる思考モードの切り替えに似ています。
モジュール化を行うもう1つの理由は、モジュールの異なる実装を置換できるようにすることです。この分離により、同じドメインロジックの上に複数のプレゼンテーションを構築できます。複数のプレゼンテーションは、Webアプリ内の個別のページ、Webアプリとモバイルネイティブアプリ、スクリプト作成のためのAPI、さらには旧式のコマンドラインインターフェースなどにすることができます。データソースをモジュール化することで、データベーステクノロジーの変更にうまく対処したり、わずかな通知で変更される可能性のある永続性のためのサービスをサポートしたりできます。ただし、データソースレイヤーを分離するための推進力としてデータアクセスの置換についてよく耳にしますが、実際に行っている人をめったに聞いたことがないことを付け加えておく必要があります。
モジュール化はテスト可能性もサポートしており、自己テストコードの大ファンである私にとって自然に魅力的です。モジュール境界は、テストに適したシームを公開します。UIコードはテストが難しいことが多いため、UIを介してプログラムにアクセスするための体操を行うことなく簡単にテストできるドメインレイヤーにできるだけ多くのロジックを含めることが重要です[1]。データアクセスは遅くて面倒なことが多いため、データレイヤーの周りにテストダブルを使用すると、ドメインロジックのテストがはるかに簡単かつ迅速になります。
置換可能性とテスト可能性は確かにこのレイヤリングの利点ですが、これらの理由がなくても、このようにレイヤーに分割する必要があることを強調しなければなりません。注意の範囲を狭めるという理由はそれ自体で十分です。
これについて話す際には、1つのパターン(プレゼンテーション-ドメイン-データ)と見なすか、2つのパターン(プレゼンテーション-ドメイン、ドメイン-データ)に分割するか、どちらかの見方ができます。どちらの見方も役立ちます。プレゼンテーション-ドメイン-データをプレゼンテーション-ドメインとドメイン-データの複合体と考えています。
これらのレイヤーは、ソフトウェアを比較的独立したピースにどのようにまとめるかを示す一般的な用語であるモジュールの一種と考えています。これがコードにどのように対応するかは、使用しているプログラミング環境によって異なります。通常、最低レベルはサブルーチンまたは関数の何らかの形式です。オブジェクト指向言語には、関数とデータ構造を収集するクラスの概念があります。ほとんどの言語には、パッケージや名前空間と呼ばれるより高レベルのものがいくつかあり、多くの場合、階層を形成できます。モジュールは、ライブラリやサービスなど、別々に展開可能なユニットに対応する場合がありますが、必ずしもそうである必要はありません。
レイヤリングはこれらのレベルのいずれかで発生する可能性があります。小さなプログラムでは、レイヤーの個別の関数を異なるファイルに配置するだけです。大規模なシステムでは、各レイヤーに多くのクラスを持つ名前空間に対応するレイヤーがある場合があります。
ここでは3つのレイヤーについて説明しましたが、3つ以上のレイヤーを持つアーキテクチャを見かけることもよくあります。一般的なバリエーションとしては、ドメインとプレゼンテーションの間にサービスレイヤーを配置したり、プレゼンテーションモデルのようなものでプレゼンテーションレイヤーを個別のレイヤーに分割したりすることがあります。コアの分離は依然として残っているため、レイヤーが増えても基本的なパターンが壊れるとは考えていません。

依存関係は通常、レイヤースタックの上から下へと実行されます。プレゼンテーションはドメインに依存し、ドメインはデータソースに依存します。一般的なバリエーションとしては、ドメインとデータソースレイヤーの間にマッパーを導入することで、ドメインがデータソースに依存しないように配置することです。このアプローチは、ヘキサゴナルアーキテクチャと呼ばれることがよくあります。
これらのレイヤーは論理レイヤーであり、物理的な階層ではありません。3つのレイヤーすべてをラップトップで実行できます。プレゼンテーションとドメインモデルをデスクトップで実行し、サーバーにデータベースを配置できます。ブラウザでリッチクライアントを使用してプレゼンテーションを分割し、サーバーにバックエンド・フォー・フロントエンド(BFF)を配置できます。その場合、BFFは特定のプレゼンテーションオプションをサポートすることに重点を置いているため、プレゼンテーションレイヤーとして扱います。
プレゼンテーション-ドメイン-データの分離は一般的なアプローチですが、比較的細かい粒度で適用する必要があります。アプリケーションが大きくなると、各レイヤーはそれ自体で十分に複雑になるため、さらにモジュール化が必要になります。このような場合、通常、上位レベルのモジュールとしてプレゼンテーション-ドメイン-データを使用することは最適ではありません。フレームワークでは、上位レベルの名前空間としてビュー-モデル-データのようなものを使用することが推奨されることがよくありますが、これは小規模なシステムでは問題ありませんが、これらのレイヤーのいずれかが大きくなりすぎると、内部的にレイヤー化されたドメイン指向モジュールに最上位レベルを分割する必要があります。

開発者はフルスタックである必要はありませんが、チームはそうであるべきです。
このレイヤリングが組織を誤った方向に導く一般的な方法の1つは、これらのレイヤーによって開発チームを分離するというアンチパターンです。フロントエンドとバックエンドの開発には異なるフレームワーク(または言語)が必要なため、開発者が一方に特化するのが容易になるため、これは魅力的に見えます。共通のスキルを持つ人々をまとめることで、スキルの共有をサポートし、組織がチームを単一の明確に定義されたタイプの作業のプロバイダーとして扱うことができます。同様に、すべてのデータベーススペシャリストをまとめることは、データベースとスキーマの一般的な集中化に合致しています。しかし、これらのレイヤー間の豊富な相互作用は、それら間での頻繁な切り替えを必要とします。これは、気軽に協力できる同じチームにスペシャリストがいる場合はそれほど難しくありませんが、チームの境界はかなりの摩擦を追加するだけでなく、個人がシステムの重要なレイヤー間の理解を開発するためのモチベーションを低下させます。さらに悪いことに、レイヤーをチームに分離すると、開発者とユーザー間の距離が広がります。開発者がフルスタックである必要はありません(ただし、それは称賛に値します)が、チームはそうであるべきです。
参考資料
この分離については、他の角度からも書いています。このレイヤリングはP of EAAの構造を推進しており、その本の第1章ではこのレイヤリングについてさらに詳しく説明しています。その本ではこのレイヤリングをパターンとして作成しませんでしたが、分離されたプレゼンテーションおよびプレゼンテーションドメイン分離でその領域を検討しました。
より大規模なシステムでは、プレゼンテーション-ドメイン-データが最上位レベルのモジュールでない理由の詳細については、サイモン・ブラウンの著作と講演を参照してください。ソフトウェアアーキテクチャはコードに埋め込まれるべきだという彼の意見にも同意します。
ヘキサゴナルアーキテクチャの本質について、同僚のBadri Janakiramanと興味深い議論をしました。コンテキストは主にRuby on Railsを使用するアプリケーションに関するものでしたが、このアプローチを検討している場合、多くの考え方が他のケースにも当てはまります。
謝辞
ジェームズ・ルイス、ジェロエン・ソーターズ、マルコス・ブリゼノ、ルーアン・ウィルセナッハ、ショーン・ニューハムがこの投稿のドラフトについて議論しました。注記
1: ページオブジェクトも、UI周辺のテストに役立つ重要なツールです。