ADOP (Application Domain Others Pattern)

ADOP (Application Domain Others Pattern)
目次

TL;DR

ADOP はヘキサゴナルアーキテクチャの実装パターンとして考えられます。
パターンという名前はそれに由来します。
あえて名付けた理由はこぼれ話をご確認いただけると幸いです。

ADOP の概要

ADOP (Application Domain Others Pattern) は中長期的に運用可能なコードへ誘導するアプリケーションアーキテクチャパターンです。

ADOP は次の特徴があります。
 

  • 最小限のルールである
  • 指針が明確である
  • 特定の技術スタックに縛られない
  • テスタビリティが確保される

これらの特徴は、コードを自然と中長期的に運用可能なコードへ導きます。
まず、簡単にそれぞれがどういった意味を成すのかを確認してきましょう。

最小限のルールである

どれほど完璧な作戦であっても、その実行が不可能であれば何の意味もありません。
プログラミングにおいてもそれは同じことで、制約を守るために多大なる労力を求められるようであれば、いつしか制約が守られなくなってしまいます。

ADOP は無理なく作戦を実行するために、ルールは最小限になっています。
ADOP で課されるルールはたったの2つです。

  1. オブジェクトが3つのレイヤーのうち、どれにあたるかを考え、配置すること
  2. 上位レイヤーのオブジェクトが下位レイヤーのオブジェクトを取り扱うときには汎化すること
    1.  
      ルール1は難しく思えるかもしれませんが、その基準はとても単純で明快なものです。
      たった2つの質問に答えるだけで、どのレイヤーにあたるかは導かれます。

      ルール2に関しては抽象型(インターフェースや純粋仮想関数で構成された仮想クラス)の概念さえ分かれば取り扱えるものです。
      抽象型を扱ったコードは OOP の基礎的なテクニックであるので、数度コードを記述して実行し、処理の流れを追えば体得できるものです。

      指針が明確である

      アーキテクチャはそのコンセプトを主張するものであることが多く、ある程度の指針を明示しつつも、具体的なディレクトリ構成やコード内容に関しては受け取り手次第であることが多いです。
      ADOP はディレクトリ構造とコーディングに関する指針が明示的です。

      ADOP は3つのレイヤーにしたがってディレクトリを分割することを推奨します。
      ADOP は3つのレイヤーの依存関係に言及し、汎化を利用すべき箇所を明示します。

      これらの指針が明確であるために、開発者はディレクトリ構造や依存関係の整理方法などの本質的でない問題について悩む必要がなくなります。
      また、開発者に強い自制心や深い理解を求める必要もありません。
      開発者に唯一求められることは ADOP の打ち立てる2つの指針の理解と実践のみです。

      特定の技術スタックに縛られない

      伝統的なソフトウェア開発において、上位レベルのオブジェクトは下位レベルのオブジェクトに依存するように開発されていました。
      言い換えるなら、ビジネスロジックがデータベースの操作に四苦八苦していたのです。
      そのため、データベースの入れ替えなどを起因に下位レベルのオブジェクトが変更されることになると、上位レベルのオブジェクトにまで修正が及んでいました。

      ソフトウェアの関心ごとはいつだって上位レベルのオブジェクトにあります。
      したがって、下位レベルのオブジェクトが変更に関する方針を左右するような主導権を有している状況はおかしいといわざるを得ません。

      ADOP の指針に従うと、この問題は解決されます。
      上位レベルのオブジェクトも下位レベルのオブジェクトも、いずれも抽象に依存するようになるため、依存関係逆転の原則が達成されます。
      ビジネスロジックは特定の技術スタックと疎になるため、様々な(たとえば政治的な)理由から生じる技術スタックの変更に怯えることがなくなります。

      テスタビリティが確保される

      テスト駆動開発の台頭により、いまやユニットテストは欠かせないものです。
      特に中長期的な運用を目指したコードであればあるほど、その必要性は高まります。

      その一方で、ユニットテスト可能なオブジェクトを開発するには一定のコーディング技術が必要です。
      チームが成熟していれば問題ありませんが、たとえばビギナーがチームに参画した際にそれをいきなり求めるのは難しいでしょう。

      ADOP はこの問題を解決します。
      ADOP が求める指針はテスタビリティの確保を強力に支援します。

      概要まとめ

      ADOP はヘキサゴナルアーキテクチャと同じ発想にあります。
      ADOP が解決することはヘキサゴナルやクリーンといった他のアーキテクチャと同じです。
      ADOP は何か新しいブレイクスルーを提供するものではありません。

      その上で ADOP を定義した理由は、実装方針を明確化しない限り、最初の一歩を踏み出せない組織が多いことです。
      ADOP はディレクトリ構造にまで言及し、現場で起こりがちな「これはどうすればいいのだろう」という問題を排除するようにしています。
      この特徴は、ソフトウェアアーキテクチャといったものを採用する最初の一歩として利用しやすいものでしょう。

      ADOP の指針

      ADOP は次の図で説明されます。

      この図を見て、レイヤードアーキテクチャを想起したのであれば、それは正しい感覚です。
      ADOP はレイヤードアーキテクチャをベースに一歩推し進めたものです。

      図を前提に解説していきましょう。
      ADOP は三つの層から構成されます。

      • アプリケーションレイヤー(Application Layer )
      • ドメインレイヤー(Domain Layer)
      • アザーズレイヤー(Others Layer)

      図の右側に存在する矢印は UML の依存(黒矢印)と汎化(白抜き矢印)を示しています。
      つまり、アプリケーションレイヤーやドメインレイヤーのオブジェクトはそれ以外から利用されます。
      反対にアプリケーションレイヤーやドメインレイヤーに存在しないオブジェクトを、アプリケーションレイヤーやドメインレイヤーで利用したい場合は汎化して利用します。

      レイヤー

      レイヤーの概要を確認します。
      詳しいコードはこの後に続きますので、理解できなかった場合には、互いに次からの説明と具体的なコードを行き来するとよいでしょう。

      ドメインレイヤー(Domain Layer)

      ドメインとは関心ごとの意味で、つまりソフトウェアを適用しようとする対象領域のことをいいます。
      したがって、このレイヤーに配置されるのはビジネスルールをカプセル化したオブジェクトです(ドメイン駆動設計の文脈でドメインオブジェクトと呼ばれるものです。)。

      なお、ドメインオブジェクトを技術的な詳細から守り、ドメインに集中させるためのファクトリやリポジトリのインターフェースなどのオブジェクトも、便宜上このレイヤーに配置します。
      ただし、これはそれらをアプリケーションレイヤーに配置する可能性を奪うものではありません。

      アプリケーションレイヤー(Application Layer )

      ドメインレイヤーのオブジェクトはドメインの知識をコードで体現するものに過ぎないため、それらをまとめ上げて、ソフトウェアで成し遂げたいことを達成するオブジェクトが必要です。
      アプリケーションレイヤーのオブジェクトはドメインレイヤーのオブジェクトを利活用し、ソフトウェアが解決したいことを達成するよう導きます。
      これらはアプリケーションサービスと銘打たれ、この層に配置されます。

      オブジェクトかメソッドかの違いはあるでしょうが、ユースケースと言い換えても差し支えないでしょう。

      アザーズレイヤー(Others Layer)

      ADOP において重要なのは、アプリケーションレイヤーとドメインレイヤーに、それ以外のコードが紛れ込まないようにすることです。
      したがって、アプリケーションレイヤーやドメインレイヤー以外のすべてをその他として、アザーズレイヤーのオブジェクトとします。

      アザーズレイヤーはたとえば MVC フレームワークといったユーザーインターフェースを完全に内包します。
      またデータベースを操作するコードや O/R Mapper を使ったコードもアザーズレイヤーに含まれます。
      これらの技術スタックをアザーズレイヤーに適切に封じ込めることで、技術スタックの変更に柔軟に対応できるようになります。

      アザーズレイヤーはすべてをひとところで管理するものではなく、技術スタックによって分割管理します。
      図の Others に背景色がなく、User Interface や Infrastructure に背景色があるのはそのためです。

      ディレクトリ構成

      ADOP ではレイヤーごとにディレクトリを分けることは強く推奨します。
      なぜなら、ディレクトリを分け、そこに配置するオブジェクトを理解することで、自然と ADOP の達成したいことにたどり着けるからです。
      ADOP ではディレクトリをアプリケーションレイヤー、ドメインレイヤー、そして特定の技術領域ごと分けることを推奨します。
      なお、あくまでも分けることを推奨するのであり、ディレクトリ構造自体は一定のルールを守っている限り柔軟です。

      次に典型的なディレクトリ構造をいくつか例示します。
      これらの例は絶対的なものではありません。
      重要なことは例に従うことではなく、アプリケーションレイヤーとドメインレイヤーとその他を分割し、アプリケーションレイヤーやドメインレイヤーを次の技術スタックに載せ替えられるようにすることです。

      ディレクトリ構成例・その1: flat

      アプリケーションレイヤーとドメインレイヤー、そしてその他技術領域に従って分けた形です。
      トップレベルのディレクトリごとにパッケージを分けても問題ありません。

      この構造は非常に単純です。
      しかし、すべてのアプリケーションレイヤーやドメインレイヤーがひとつのディレクトリに集められるという単純さゆえに、全体がぼやけて見える可能性があります。

      ディレクトリ構成例・その2: Split Application

      このディレクトリ構成例は flat における問題を解決すべく、アプリケーションの関心ごとをより詳しく分割したものです。

      ひとつのソフトウェアを完成させるのに、アプリケーションレイヤーがひとつとは限りません。
      ときとして、もしくはほとんどの場合、関心ごとによってアプリケーションを分割しておく方が管理しやすいことが多いです。
      どのように分割するかについては、コアドメインやサブドメインといった考え方がありますが、主題ではないので割愛します(このことは『エリック・エヴァンスのドメイン駆動設計』(翔泳社)を参考にするとよいでしょう)。

      インフラストラクチャのディレクトリについては図のようにアプリケーションごとに分けて管理する場合もあれば、まったく別の管理をすることもあります。
      チーム編成が色濃く出やすい部分でありますので、あくまで例のひとつとして受け取ってください。

      ディレクトリ構成例・その3: Application Included

      なお UserInterface がフレームワークであるため、次のようにアプリケーションレイヤーとドメインレイヤーが UserInterface に内包されるよう要求されることもあります。

      コンセプト図における上位レイヤーは下位レイヤーに依存しても構いませんので、このディレクトリ構成は肯定されます。
      反対に、アプリケーションレイヤーやドメインレイヤーが UserInterface や Infrastructure を内包するのは許可されません。
      アプリケーションレイヤーやドメインレイヤーからユーザーインターフェースや特定のインフラストラクチャへの直接の依存は許されないからです。

      コード

      それぞれのディレクトリごとのコードを例示します。
      MVC フレームワークをインターフェースとした WEB アプリケーションを題材とします。
      ADOP を発表したのは PHP Conference 2020 における講演でしたので、ここで紹介するサンプルのプログラミング言語は PHP で、フレームワークは Laravel とします。
      (必要そうであり余裕があれば、他のプログラミング言語でもサンプルを作ります)

      サンプルアプリケーション

      解説に利用しているコードは次の github リポジトリのコードです。
      https://github.com/nrslib/scrum-app-sample-php
      先述したディレクトリ構成例では、その3の Application Included にあたります。
      packages ディレクトリ以下にアプリケーションレイヤーなどが存在しています。

      なお、次の2つはまったく別のアーキテクチャの名前を冠していますが、ADOP に則っている C# コードです。
      https://github.com/nrslib/itddd/tree/master/Layered
      https://github.com/nrslib/itddd/tree/master/CleanLike

      UserInterface

      ここからは処理の流れにしたがってコードを確認していきます。

      まずは UserInterface のコードです。
      MVC フレームワークは UserInterface に内包されるものですので、ここで紹介しているコードはコントローラです。

      https://github.com/nrslib/scrum-app-sample-php/blob/main/src/app/Http/Controllers/BackLogController.php

      5行目の postAddUserStory アクションは第二引数に BackLogApplicationService を受け取っています。
      BackLogApplicationService はアプリケーションレイヤーのコードです。
      このコードは入力の検査を行い、アプリケーションレイヤーのオブジェクトを使用し、結果を返却しています。

      Application

      コントローラが使用していたアプリケーションレイヤーのオブジェクトのコードです。

      https://github.com/nrslib/scrum-app-sample-php/blob/main/src/packages/scrum/Application/Service/BackLog/BackLogApplicationService.php

      ADOP ではアプリケーションレイヤーやドメインレイヤーに存在しないその他のコードは汎化して使うルールがあります。
      それを実際に行っているコードがここに存在します。
      27行目の $this->transaction->scope メソッドや、33行目の $this->userContext->getId、そして36行目の $this->repository->save です。

      それぞれ、トランザクションの範囲指定を行い、セッション情報からログインユーザの ID を取得し、任意のデータストアへの保存を行っています。
      フィールドの定義に目を移すと(3行目、5行目、7行目)、インターフェースであるので汎化されていることが分かります。

      これらのフィールドに束縛されるオブジェクトはコンストラクタの引数で受け取っています。
      引き渡される具象クラスは一般的に IoC Container にて設定されます。
      IoC Container の活用については後述します。

      Domain

      ドメインレイヤーのコードです。
      ドメインレイヤーにはビジネスルールをカプセル化したオブジェクトが配置されます。
      https://github.com/nrslib/scrum-app-sample-php/blob/main/src/packages/scrum/Domain/Models/UserStories/UserStory.php

      ここに例示するオブジェクトはビジネスルールを含んだロジックに乏しく、例としては少し適切ではない可能性があります(よい例が見つかったら改めて記述し直します)。
      詳しい解説は『エリック・エヴァンスのドメイン駆動設計』におけるドメインオブジェクト(値オブジェクト・エンティティ・ドメインサービス)に解説を譲ります。

      もうひとつ、ドメインオブジェクトではありませんが、このディレクトリに配置しているものがあります。
      それはリポジトリのインターフェースです。

      https://github.com/nrslib/scrum-app-sample-php/blob/main/src/packages/scrum/Domain/Models/UserStories/UserStoryRepositoryInterface.php

      サフィックスに Interface がついているのは PHP の命名規則のひとつです。

      リポジトリはドメインオブジェクトの保存と再構築を担うオブジェクトです。
      リポジトリ自体はドメインのモデルを表現するドメインオブジェクトではありませんが、ドメインオブジェクトを鮮明にするのに役立つため、ドメイン設計の一部であり、ドメインレイヤーのオブジェクトとしています。
      ファクトリやリポジトリが同一ディレクトリにないと、ドメインオブジェクトの生成や再構築のオブジェクトが存在することに気づかなかったり、ドメインレイヤーを別アプリケーションに転用することが叶わなくなる問題があるので、このような形にしています。

      Others

      アプリケーションレイヤーで汎化していたオブジェクトの具象クラスを確認していきます。

      Infrastructure
      リポジトリ

      次のコードは O/R Mapper を使ってデータを保存するコードです。
      https://github.com/nrslib/scrum-app-sample-php/blob/main/src/packages/scrum/EloquentInfrastructure/Persistence/UserStories/EloquentUserStoryRepository.php

      またインフラストラクチャはデバッグ用のオブジェクトも存在しています。

      https://github.com/nrslib/scrum-app-sample-php/blob/main/src/packages/scrum/DebugInfrastructure/Persistence/UserStories/FileUserStoryRepository.php

      これはデータベースではなくファイルにインスタンスを保存するオブジェクトです。
      たとえば WEB アプリケーションをデータベースに接続せず、疑似的に動作させてテストするのに役に立ちます。

      トランザクション

      整合性を維持するための機構はインフラストラクチャに結びついているため、インフラストラクチャごとにトランザクションの制御は異なります。
      そのため、トランザクションを実行するオブジェクトはインフラストラクチャに適したものを用意する必要があります。

      https://github.com/nrslib/scrum-app-sample-php/blob/main/src/app/lib/Transaction/LaravelDbTransaction.php

      これは Laravel の DB ファサードを利用してトランザクションを実現するモジュールです。

      なお、先のファイルを使ったデバッグ用リポジトリの場合はトランザクションの制御機構がありません。
      その場合は何も行わないオブジェクトを使用します。

      https://github.com/nrslib/scrum-app-sample-php/blob/main/src/packages/basic/Transaction/Transaction.php

      またトランザクションについてはアノテーションを使ったアスペクト指向プログラミングで実装されるパターンもあります。
      ほかにユニークなものでは C# に TransactionScope といった機能もあります。
      https://docs.microsoft.com/ja-jp/dotnet/api/system.transactions.transactionscope?view=net-5.0
      いずれにせよ、データベースなどインフラストラクチャに紐づくトランザクションをそのまま扱わないようにするための手法です。

      UserInterface

      WEB アプリケーションではセッション情報を取り扱いたいことがあります。
      しかし、セッション情報はアプリケーションレイヤーでもなく、ドメインレイヤーでもありません。
      そのため、セッション情報を取り扱うためには、汎化して実装したオブジェクトを利用します。

      https://github.com/nrslib/scrum-app-sample-php/blob/main/src/app/lib/Context/AuthUserContext.php

      Basic

      関心ごと毎にアプリケーションを分けた場合には、アプリケーションレイヤーやドメインレイヤーのオブジェクトを支援するコードを共通ライブラリとして抽出することになります。
      たとえば、次のようなドメインオブジェクトを実装するのを支援するようなオブジェクトです。

      https://github.com/nrslib/scrum-app-sample-php/blob/main/src/packages/basic/DomainSupport/ValueObjects/StringValueObject.php

      これはどのレイヤーのコード?

      たった3つであっても、コードがどれに所属するかを考えて、それを適切に配置するのは難しく感じるものです。
      そこで、今記述しているコードがどのレイヤーに配置されるべきかを判定する、簡単なフローチャートを作成しました。

      わずか2つの質問に答えるだけで、どのレイヤーに配置されるべきかが分かります。

      Q1. ドメインの事物を直接的に表現するコード、もしくは表現を支援するコードか

      ドメインは冒頭でも解説しようとしたとおり、ソフトウェアを適用する対象領域のことです。
      たとえば物流システムであれば、ドメインの事物には運送手段(トラックなど)や拠点、配送など様々なモノやコトがあります。
      それらを表現するコードであれば、質問への回答は Yes になり、ドメインレイヤーに所属させます。
      また、それらのオブジェクトを構築するためのファクトリ、永続化の指針を示すリポジトリのインターフェースも、表現を支援するコードであるため、この質問に関しては Yes になります。

      Q2. ドメインの事物を表現するコードを取り扱い、ユースケースを達成するコードか

      ドメインの事物を表現するコードとはドメインレイヤーのオブジェクトのことを指し、つまり、運送手段(トラックなど)や拠点、配送など様々なモノやコトを表現したコードやファクトリ、リポジトリといった表現の支援を行うオブジェクトのことです。
      それらを取り扱い、ソフトウェアのユースケースを達成するコードであれば、この質問に対する回答は Yes になります。

      すべて No

      ここまでの質問に No で返答したのであれば、それは Others に含まれます。
      技術領域に従って、ディレクトリを分割するようにしましょう。

      なお、コアドメインやサブドメインといったように分割している際のインフラストラクチャのコードは、それに従って分割されることもあります(2.2.3 ディレクトリ構成例・その3: Application Included 参照)。

      IoC Container の活用

      コンストラクタがインターフェースのオブジェクトを要求している際に、どの実装クラスを渡すかについての設定は IoC Container を利用すると便利です。

      次のスクリプトは IoC Container を使って、インターフェースに対して引き渡す実装クラスを設定しています。

      https://github.com/nrslib/scrum-app-sample-php/blob/main/src/app/Providers/ServiceProviders/ProductionServiceProvider.php

      10行目で BackLogApplicationService が登録されています。
      これは、IoC Container に対して BackLogApplicationService が要求されたらインスタンスをそのまま生成する設定です。

      次に23行目では UserStoryRepositoryInterface に対して EloquentUserStoryRepository が登録されています。
      これは、IoC Container に対して UserStoryRepositoryInterface が要求されたら、EloquentUserStoryRepository のインスタンスを生成するという設定です。

      これらの設定の上で、IoC Container に対して BackLogApplicationService を要求すると、BackLogApplicationService のコンストラクタが要求する UserStoryRepositoryInterface には EloquentUserStoryRepository が引き渡された BackLogApplicationService を生成します。

      IoC Container を使えば、オブジェクトのインスタンス化が IoC Container に内包され、どの実装クラスを利用するかといったことを一箇所で管理できます。
      たとえばこの設定スクリプトを次のスクリプトに切り替えることで疑似的に WEB アプリケーションを動かしたりできます。

      https://github.com/nrslib/scrum-app-sample-php/blob/main/src/app/Providers/ServiceProviders/LocalServiceProvider.php

      特筆すべき違反的なコード

      サンプルコードではドメインレイヤーの UserStory を Eloquent (O/R Mapper) で保存ないし再構築する際に、UserStoryDataModel を利用しています。
      これはドメインレイヤーのオブジェクトである UserStory がインフラストラクチャのコードに依存しないようにするためです。

      具体例を紹介しましょう。
      次のコードは UserStoryDataModel を利用しなかった場合の UserStory です。

      ADOP はアプリケーションレイヤーとドメインレイヤーを長期的に利用することを目的としています。
      インフラストラクチャの特定技術に依存してしまうとそれが叶わなくなる可能性を残します。
      したがって、UserStoryDataModel といったオブジェクトに移し替えを行い、ドメインレイヤーが特定のインフラストラクチャのコードに侵食されないようにすることを推奨します。

      ADOP に関係のある動画解説

      ADOP は PHP Conference 2020 にて講演を行った『PHP WEBアプリケーション設計入門――10年先を見据えて作る』で発表したパターンです。
      ADOP が必要となる経緯や理由についてはアーカイブを確認すると、より現実感を得られるでしょう。
      アーカイブではより詳しいコードの流れの解説もあります。

      スライド

      講演の資料は次のスライドです。
      スライドはトークを前提としたものですので、可能であれば動画の視聴をお勧めします。

      他アーキテクチャとの関係

      まずはじめに断っておきたいことは、ADOP はどのアーキテクチャとも直交するアーキテクチャパターンではないということです。
      むしろ、これより紹介するいずれのアーキテクチャも、ほとんど ADOP の求めることは達成しています。
      ここで紹介するアーキテクチャは次の4つです。

      • レイヤードアーキテクチャ
      • ヘキサゴナルアーキテクチャ
      • 独立したコアレイヤーパターン
      • クリーンアーキテクチャ

      レイヤードアーキテクチャ

      レイヤードアーキテクチャは主に次の図で紹介されます。


      引用元: エリック・エヴァンスのドメイン駆動設計(翔泳社)

      ADOP で示すコンセプト図ととても似通った図です。
      それもそのはずで、ADOP はレイヤードアーキテクチャを前身としています。
      唯一異なるのはアプリケーションレイヤーやドメインレイヤーからインフラストラクチャレイヤーに対して直接的な依存の矢印が延ばされていることです。
      書籍内部で UnitOfWork といったパターンが示されているとおり、インフラストラクチャに依存するコードを示唆しています。
      これは当時の時代背景もあったと考えますが ADOP ではそれを非推奨としており、その一点でのみ異なります。

      ADOP はレイヤードアーキテクチャを現代に合わせて更新したものと言っても差し支えないものです。

      余談ですが、『エリック・エヴァンスのドメイン駆動設計』で紹介されていることもあり、ほとんどドメイン駆動設計といえばレイヤードアーキテクチャといったように語られますが、それは異なります。
      ドメイン駆動設計においてアーキテクチャはドメインレイヤーを隔離する手段にすぎないので、他のアーキテクチャと組み合わせることが可能です。
      むしろドメイン駆動設計はドメインと相対し、深い洞察を得て、それをソフトウェアに活かすことが主題です。

      ヘキサゴナルアーキテクチャ


      引用元: https://alistair.cockburn.us/hexagonal-architecture/

      ヘキサゴナルアーキテクチャは ADOP が達成したいことを完全に説明しています。
      したがって、ADOP はヘキサゴナルアーキテクチャを厳密な実装としてパターン化したものです。

      独立したコアレイヤーパターン


      引用元: https://blog.shin1x1.com/entry/independent-core-layer-pattern

      独立したコアレイヤーパターンはヘキサゴナルアーキテクチャと同じく、ADOP の課題や目的を説明しています。
      独立したコアレイヤーパターンはヘキサゴナルアーキテクチャをより抽象化し、そのコンセプトを理解しやすくしたものであると私は認識しています。
      ADOP はその反対に、ヘキサゴナルアーキテクチャをより具体化し、実践しやすくしたものです。

      クリーンアーキテクチャ

      クリーンアーキテクチャは書籍とコンセプト図によってその印象が異なりますが、ここではコンセプト図を取り扱います。

      引用元: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

      クリーンアーキテクチャの実装例はコンセプト図の右下に存在しますが、その詳しい実装例も存在します。

      引用元: Clean Architecture 達人に学ぶソフトウェアの構造と設計(アスキードワンゴ)

      クリーンアーキテクチャに従えば ADOP が求める中長期的な運用を見据えたコードを得られます。
      その一方でクリーンアーキテクチャの実装例は相当のコード量を要求します。
      それはそのまま、開発者にアーキテクチャへの理解と労力、遵法精神を求めることになります。
      そのため、アーキテクチャを守るための努力が必要になるのです。

      ADOP にはクリーンアーキテクチャほど厳密ではないため、多大なる負担を開発者に求めません。

      総評

      各種アーキテクチャと ADOP は解決しようとしている課題が同じです。
      したがって、コンセプトは同じになります。
      では ADOP が不要かというと、そうでないことに気づきました。

      ADOP にはほかのアーキテクチャと異なるところが2つあります。

      1つ、ディレクトリ構造やコーディングに関して明確な指針があるので、受取り手の解釈によるブレがないこと。
      1つ、指針の数が少なく、そこに多大な労力を犠牲にする必要がないこと。

      この2つの相違点が、ADOP の価値です。
      ADOP は軽量であるがゆえに導入しやすく実践しやすいものです。

      おわりに

      ADOP のルールは単純です。

      アプリケーションレイヤー、ドメインレイヤー、アザーズレイヤーの3つに分け、それぞれのディレクトリで管理すること。
      そして、アプリケーションレイヤーやドメインレイヤーからアザーズレイヤーの処理を呼び出したいときは汎化して使うこと。

      このルールは中長期化するサービス開発において、保守開発のしやすいコードを目指すために必要最小限の取り決めです。

      ADOP の目的は、ソフトウェア開発において、初めて中長期的な視座に立ったときのサポートです。
      既存のアーキテクチャは受け取り手に任せる部分があり、とりあえず始めることが難しいのです。
      ADOP であれば、深い理解を得るより先に、体験から始められます。

      まずは ADOP を始めてみて、必要であれば他のアーキテクチャを学ぶとより深い理解が得られるに違いありません。

      こぼれ話

      根本的に私はすでに存在しているアーキテクチャと同じコンセプトに沿ったものをパターンとして名づけることに強い拒否感を覚えていました。
      なぜなら、粗製乱造とほとんど似た感覚でいたからです。
      それにもかかわらず、今回 ADOP を記述するに至った理由は、既存のアーキテクチャが設計に関心を寄せたばかりの入門者にとって、敷居の高いものであることに気づいたからです。

      ADOP はヘキサゴナルアーキテクチャとまったく同じコンセプトをもつものです。
      また、オニオンアーキテクチャとも同様です。
      クリーンアーキテクチャとも同様です。
      独立したコアレイヤーパターンとも同様です。
      アーキテクチャが成し遂げたいことは根本的には同じことなのです。

      多くのアーキテクチャが提唱されていますが、入門者にとってそれらを実際に実践するのは難しいと言わざるを得ません。
      入門者がアーキテクチャの本質に気づくにはどのような手順を踏むべきでしょうか。

      仏教の言葉には「心は形を求め、形は心をすすめる」という言葉があります。
      心を整えたくても心そのものは形をもちません。
      そのため、所作や行動といった、目に見えるものの形を整えることから、心を整えていくといった考えです。

      他には「形直影端」という禅語があります。
      これは、身体の姿勢が美しければ、影も美しくなるという意味です。
      形から入ることの大切さを説いています。

      つまり、何かの心を知るには、形から入る必要があるのです。
      アーキテクチャの心を知るにはまず形が必要なのです。
      ADOP は形を明確に示すものです。
      その形を踏襲することで、アーキテクチャの本質――心を理解できるのではないかと考え、ここに記すことにしました。

Architectureカテゴリの最新記事