Vertical Slice Architectureについて
はじめに
この記事ではVertical Slice Architectureと呼ばれるアーキテクチャパターンについて解説します。Vertical Slice Architectureはこの2,3年の間にいくつかのブログポスト[1][2][3][4]で言及されているアーキテクチャです。Clean Architectureに対する反省から生まれたアーキテクチャであり、機能(feature)に沿ってモジュール分割を行う点が特徴です。
まず、Clean Architectureについて説明してからVertical Slice Architectureについて説明します。最後に私のコメントとして、Vertical Slice Architectureに対する評価、Clean Architectureに対する評価、それから日本でVertical Slice Architectureが受容され得るかどうかについて述べます。
Clean Architecture
Clean ArchitectureはUncle Bobが提唱したアーキテクチャ[5]で、Ports and AdaptersパターンとOnion Architectureをベースとしたアーキテクチャです。Ports and Adaptersパターンは核となるビジネスロジックをデータやイベントから分離します。データやイベントへのアクセスを提供する部分はプラガブルなものとして取り替えが可能にします。Onion Architectureはドメインモデルを中心として、UIやデータベースを外側に置いたレイヤードアーキテクチャです。レイヤー数はアプリケーションによって異なりますが、必ずドメインモデルが中心にあり、各レイヤーは自身より内側のレイヤーのことだけを知っていることができます。
Clean Architectureは中心から順に以下の4つのレイヤーを持ちます。ただし、必ずしもこれらのレイヤーに限られるわけではありません。
- エンティティ(enterprise wideなビジネスロジックをカプセル化する)
- ユースケース(アプリケーション固有のビジネスロジックをカプセル化する)
- インターフェースアダプタ(データをユースケースやエンティティが利用する形式からUIやDBが利用する形式に変換する)
- フレームワークとドライバー(ウェブアプリケーションフレームワークやDBドライバーとのグルーコード)
Onion Architectureと同様に各レイヤーは自身より内側のレイヤーのことしか知ることができません。また、ユースケース・レイヤーにPort and Adaptersパターンを適用して、入出力を担うインターフェースアダプタ・レイヤーをプラガブルにします。
上記の構成を取ることでレイヤーごとのテストを容易にしたり、フレームワークやデータベースの取り替えを容易にしたりすることを目指します。
Clean Architectureが実践されるときにはレイヤーごとにパッケージやディレクトリが作成されます。例えば、以下のようなディレクトリ構成になっていることが頻繁に見受けられます。
app
├── entities
├── repositories
├── presenters
├── controllers
└── usecases
また、レイヤーの取り替えを可能にするために抽象クラスを宣言することが行われます。
冒頭で触れたブログポストではClean Architectureに対して以下の問題点が指摘されています。
- モノリシックである。
- レイヤーごとのテストのためにモックが重くなる傾向がある。
- 過剰な抽象化を行ってしまう。
- ある機能について作業するためにいくつものディレクトリを移動しなければならない。
- 機能の追加や修正が困難である。
- データベースを取り替えることはめったにない。
特に、ある機能を実現するコードがディレクトリツリーのなかでバラバラの場所にあるのは、コンテクストスイッチのために記憶力と気力を消費することになり開発者体験が悪化します。この問題を解消するために提案されたのがVertical Slice Architectureです。
Vertical Slice Architecture
Vertical Slice Architecture[1:1]は、スライス間の結合を最小化し、スライス内の結合を最大化することを目標として機能ごとにディレクトリを組成するアーキテクチャです。
ここでいう機能とは、end-to-endな形で表現されたユーザーストーリーのことであって、レイヤードアーキテクチャのそれぞれのレイヤーのことではありません。
例えば、ブログアプリケーションを作っていてユーザーに関する機能、ブログポストに関する機能、コメントに関する機能があったとすると、以下のようなディレクトリ構成になるでしょう。
app
├── users
├── posts
└── comments
それぞれの機能を実装する際に利用するパターンに対する言及はありません。重要なのは、機能ごとにソースコードをまとめ、同時に変更されるものはなるべく近くにあるようにすることです。
Vertical Slice Architectureによってもたらされる利点として以下の点が挙げられています[2:1][4:1]。
- 特定の機能を実装するコードを素早く探すことができる。
- 個別の機能がもつ複雑性が隔離される。
- ビジネスとプロダクトについて考えることを開発者に強制する。
- マイクロサービスへと発展させることが容易である。
- インクリメンタルなリファクタリングが容易になる。
以上の利点はあるものの、Vertical Slice Architectureは全ての問題を解決するものではなく、落とし穴があることをSampicaは指摘しています[4:2]。Vertical Slice Architectureを実践するためにはドメイン設計とストーリー分割のスキルが必要になります。フレームワークの思想に反する場合は実現しづらいです。また、自動テストはインテグレーションテストやE2Eテストが必要になります。
いくつかのコメント
Vertical Slice Architectureに対する私の評価
私はVertical Slice Architectureというパターンに対してとても好意的でうまくいきそうだと思っていますが、私自身が実践したことがないため正確な評価は下せません。ですが、Clean Architectureがもたらす苦痛を取り除いてくれるというのは確かだと思います。また、ユーザーストーリーをvertical sliceに分割するのだから実装もvertical sliceに分割されるというのは理にかなっていると思います。
参考にしたブログポストで挙げられていたVertical Slice Architectureの利点以外にも、機能ごとにディレクトリを分けることでGitHubのコードオーナーの設定がやりやすくなるでしょう。
Vertical Slice Architectureを採用したとしても、それぞれの機能で適度に分割したプログラムを書くべきであるというのは変わらないと思います。ただし、必要な時に必要なだけの責務の分割を行うべきであって、最初からテンプレートに当てはめればいいものではありません。
また、機能間に依存関係が生じた場合の設計については言及していないので、その都度適切なパターンを採用する必要があると思います。Vertical Slice Architectureはモジュール構造に関するパターンであって、実行時に現れるコンポーネントやそれらをサーバーやコンテナに割り当てる対応関係には言及していないことに注意しておく必要があります。
ドメイン駆動設計はVertical Slice Architectureと親和的
機能ごとにディレクトリあるいはモジュールをまとめるという発想はドメイン駆動設計との親和性が高いと思います。『エリック・エヴァンスのドメイン駆動設計』第7章にある記述を確認しておきましょう。
図7.7が示しているのは、本書を熱心に読んだ架空の読者によって、きれいに分割されたモデルである。この図は、第5章で提起した、インフラストラクチャ駆動のパッケージングが持つ問題を示すバリエーションの1つであるといえる。ここでオブジェクトは、それぞれが従っているパターンによってグループ化されている。結果として、概念的にはほとんど関係ない(低凝集)オブジェクトが一緒に詰め込まれ、すべてのモジュール間に関連が無秩序に走っている(高結合)。このパッケージは、あるストーリーを伝えてはいるが、それは輸送に関するものではなく、開発者がその時に読み取ったストーリーなのである[6]。
上記の引用ではドメイン概念とは関係のないストーリーに沿ってモジュールを分割することが諌められています。続く記述でエヴァンスはこう述べています。
我々がすべきことは、凝集度の高い概念を探し、プロジェクトにおいて他の人々に伝えたいことに集中することなのだ[7]。
ドメイン駆動設計で求められているのは、ドメイン概念を伝えることのできるモジュール構成だと読み取ることができます。そして、Vertical Slice Architectureはそれに適合しているように見えます。
自動テストのプラクティスへの影響
Vertical Slice ArchitectureはインテグレーションテストやE2Eテストのような大きなレベルでのテストを必要とします。どのレベルのテストコードを重点的に書くかという問題に対して、ユニットテストを重視するテストピラミッド[8]というプラクティスがあります。このプラクティスがどれほど広まっているかわかりませんが、テストを書く際のより良いプラクティスもvertical sliceによって変化していくのではないかと思います。
Clean Architectureに対する私の評価
Clean Architectureのデメリットは参考にしたブログポストで挙げられた点以外にもあると私は考えています。まず、適切な抽象化を行うことはかなり難しい仕事です。ライブラリを作る根気と労力があればやってもいいと思いますがそんな余裕があることは滅多にないでしょう。そもそもdesign by contractを理解し実践できるソフトウェアエンジニアがいなければ、まともな抽象化ができずにソフトウェアが破綻するでしょう。
小規模なプログラムでClean Architectureを採用した場合にはボイラープレートのようなコードを書く必要があり、必要以上にコードの量が増えます。この点もデメリットだと思います。
メリットを挙げるとすれば、リファクタリングのスキルがない人にプログラムを書いてもらう場合に、一定のテンプレートに当てはめてしまうことで一応のコードの質を保つことが可能になるかもしれません。
私が最も問題だと思っているのは、Clean Architectureという名前です。この名前はcleanという主観的な評価が入っており、Clean ArchitectureがOnion Architectureに対するPorts and Adaptersパターンの適用したものであるという内容を表現していません。Clean Architectureの採用でソフトウェアがcleanになるとは言い難く、誇大広告と捉えられても致し方ないものだと思います。(Cleanという名前はUncle Bobのトレードマークのようなものなので真剣に捉えない方がいいかもしれないのですが…)
日本における受容の問題
日本においてチーム開発の場でVertical Slice Architectureを実践することは困難だと思います。多くの日本のソフトウェアエンジニアはアジャイルな開発に慣れていないようです。ユーザーストーリーの分割どころかユーザーストーリーを書くことすらままならないかもしれません。
Clean Architectureが人口に膾炙しているようであり、他のパターンを知らないソフトウェアエンジニアがClean Architectureに固執するかもしれません。この点もClean Architecture以外のアーキテクチャパターンを採用する障壁となりそうです。
さいごに
Vertical Slice Architectureは銀の弾丸ではありませんが、ユーザーストーリーに沿った形でコードを組織化することでプロダクト駆動な開発を可能にできるのではないかと思います。この点はプロダクト開発を中心とした開発を行う場合は大きなメリットになるでしょう。
Clean ArchitectureとVertical Slice Architectureのどちらを採用する場合でもエンジニアに一定のスキルが要求されることは変わりありません。ステークホルダーの要求を収集し表現するスキルから堅牢なプログラムを書くスキルまで幅広いスキルとソフトウェアを実装する際に使われるパターンやコンセプトに関する幅広い知識が求められると思います。結局のところ、アーキテクティングは高いレベルのソフトウェアエンジニアでなければできない仕事であって、これさえ知っていれば誰でもできるというものはないということは読者の皆様に覚えておいていただきたいです。
-
Bogard, Jimmy. "Vertical Slice Architecture." 19 Apr, 2018. (blog post) ↩︎ ↩︎
-
Hickey, James. "The life-changing (and time-saving!) magic of Feature Focused code organisation." 2019. (blog post) ↩︎ ↩︎
-
Hickey, James. "Clean Architecture: The Bad Parts." 27 May, 2020. (blog post) ↩︎
-
Sampica, Benjamin. "Vertical Slice Architecture." 25 Oct, 2021. (blog post) ↩︎ ↩︎ ↩︎
-
Martin, Robert C. "The Clean Architecture." 13 Aug, 2012. (blog post) ↩︎
-
Evans, Eric. 監訳 今関剛. エリック・エヴァンスのドメイン駆動設計 翔泳社. 2013. p.179. ↩︎
-
ibid. p.181. ↩︎
-
Rasmusson, Jonathan. 翻訳 玉川紘子. 初めての自動テスト――Webシステムのための自動テスト基礎 オライリー. 2017. ↩︎
Discussion