TadaoYamaokaの開発日記

個人開発しているスマホアプリや将棋AIの開発ネタを中心に書いていきます。

【読書ノート】Clean Architecture 達人に学ぶソフトウェアの構造と設計

書籍「Clean Architecture 達人に学ぶソフトウェアの構造と設計」を読んだので、内容をまとめた。
以下の内容は、ほとんどClaude3 Opusを使用して作成している。

まえがき・第I部 イントロダクション

まえがき

ソフトウェアシステムの構造を決定するルールは、システムの種類に関係なく普遍的である。ソフトウェアアーキテクチャの目的は、システム構築に必要な人材を最小限に抑えることであり、設計の品質は開発・保守に必要な労力で測ることができる。アーキテクチャは仮説であり、実装と計測によって証明すべきものである。本書は、時代を超越した不変のルールを解説する。

印象的なフレーズ
  • 恋のおそろしい化け物とは、意欲は無限だが実行は有限、欲する心ははてしないがおこなうには限度がある。
  • 優れたアーキテクチャのコストが高いと思うなら、劣ったアーキテクチャにすればいい。
  • 速く進む唯一の方法は、うまく進むことである。
重要なポイント
  • ソフトウェアアーキテクチャのルールは、システムの種類に関係なく普遍的で不変である
  • ソフトウェアアーキテクチャの目的は、システム構築に必要な人材を最小限に抑えること
  • アーキテクチャは仮説であり、実装と計測によって証明すべきもの
理解度確認のための質問文
  • ソフトウェアシステムの構造を決定するルールは、システムの種類によってどのように異なりますか?
  • ソフトウェアアーキテクチャの品質は何によって測ることができますか?
  • アーキテクチャとはどのようなものだと著者は主張していますか?

第1章 設計とアーキテクチャ

設計とアーキテクチャに明確な区別はなく、システムを形作る重要な意思決定を表したものである。優れたアーキテクチャの目的は、求められるシステムを構築・保守するために必要な人材を最小限に抑えることである。崩壊したコードを書くことは短期的にも長期的にもクリーンなコードを書くよりも遅い。速く進む唯一の方法は、うまく進むことである。

印象的なフレーズ
  • 設計とアーキテクチャについては、何年も混乱が生じている。設計とは何か?アーキテクチャとは何か?両者の違いは何か?
  • 速く進む唯一の方法は、うまく進むことである。
重要なポイント
  • 設計とアーキテクチャに明確な区別はない
  • 優れたアーキテクチャは、開発・保守に必要な人材を最小限に抑える
  • 崩壊したコードを書くことは短期的にも長期的にもクリーンなコードを書くよりも遅い
理解度確認のための質問文
  • 著者は設計とアーキテクチャの違いをどのように述べていますか?
  • 優れたアーキテクチャの目的は何だと著者は述べていますか?
  • 崩壊したコードを書くことの問題点は何だと著者は述べていますか?

第2章 2つの価値のお話

ソフトウェアは、振る舞いとアーキテクチャという2つの価値を持つ。振る舞いは緊急だが重要とは限らず、アーキテクチャは重要だが緊急とは限らない。開発者はアーキテクチャの重要性を強く主張する責任があり、ステークホルダーと対等に、ひるむことなく口論しなければならない。アーキテクチャを後回しにすると、開発コストが高くなり、変更不能になる。

印象的なフレーズ
  • 私には緊急と重要の2種類の問題がある。緊急と重要は違う。重要なことが緊急になるわけではない。
  • ソフトウェア開発者もステークホルダーであることは忘れてはいけない。保護すべきソフトウェアに対する責任がある。それが、あなたの役割であり、義務である。それが、あなたが雇われている大きな理由だ。
重要なポイント
理解度確認のための質問文

第I部の重要な概念

  • アーキテクチャ:ソフトウェアシステムの構造を決定する重要な設計上の意思決定のこと。システムの構築・保守に必要な人材を最小限に抑えることを目的としている。
  • 振る舞い:ソフトウェアがユーザーの要求を満たすために提供する機能のこと。一般的にステークホルダーにとって緊急な課題とみなされる。
  • 設計:ソフトウェアの構造や振る舞いを決定するための意思決定のこと。著者は設計とアーキテクチャを同義とみなしている。
  • 崩壊したコード:複雑で理解しづらく、変更が難しいコードのこと。短期的には早く書けるが、長期的には開発速度を低下させる。
  • アイゼンハワーマトリックス:緊急度と重要度の2軸で課題を分類するフレームワーク。緊急かつ重要なものから優先的に取り組むべきだとしている。

第I部の要点

本書の第I部では、ソフトウェアアーキテクチャの重要性と、開発者がアーキテクチャに注力すべき理由が説明されている。

著者は、ソフトウェアシステムの構造を決定するルールは普遍的で不変であると主張している。そして、優れたアーキテクチャの目的は、システムの構築・保守に必要な人材を最小限に抑えることであると述べている。

ソフトウェアには、ユーザーの要求を満たす「振る舞い」と、変更に柔軟な「アーキテクチャ」という2つの価値がある。振る舞いは緊急だが必ずしも重要ではなく、アーキテクチャは重要だが緊急ではないことが多い。開発者は、アーキテクチャの重要性をステークホルダーに強く主張する必要がある。

設計とアーキテクチャに明確な区別はなく、どちらもシステムの構造を決定する意思決定を指す。崩壊したコードを書くことは、短期的には速く書けるように見えて、長期的には開発速度を低下させてしまう。

本書では、アーキテクチャを重視することで、ソフトウェア開発の生産性を高く保ち、変更に強い柔軟なシステムを構築できると主張している。

第I部の考察

「Clean Architecture」の第I部では、ソフトウェアシステムの設計とアーキテクチャに関する著者の考えが述べられている。著者は、アーキテクチャを重視し、あらゆるステークホルダーに対してその重要性を訴え続けることが、開発者の責務であると主張している。

確かに、機能を重視するあまりアーキテクチャがおろそかになるという問題は、多くのソフトウェアプロジェクトで見られる。そのような「技術的負債」は、短期的には開発速度を上げられるものの、長期的にはシステムの複雑性を増大させ、生産性を低下させる原因となる。

一方で、アーキテクチャを重視しすぎるあまり、ビジネス要求の実現が後手に回るというリスクもある。アジャイルソフトウェア開発のように、機能の提供とアーキテクチャの改善を小さなサイクルで繰り返す手法は、両者のバランスを取る上で有効であると考えられる。

著者も指摘しているように、アーキテクチャは仮説であり、実装と計測によって検証していく必要がある。設計とアーキテクチャの区別を明確にしない点には疑問が残るが、アーキテクチャを意識し、ステークホルダーを巻き込んで議論していくという姿勢は、開発者にとって重要な示唆になるであろう。

本書の主張を実践に移すためには、アーキテクチャに関する知識だけでなく、コミュニケーションやマネジメントのスキルも必要になる。開発者一人ひとりがアーキテクチャに対する責任感を持ち、チームやステークホルダーとの対話を重ねていくことで、プロジェクトの成功確率を高められるはずである。

システムの長期的な発展を考えれば、アーキテクチャの重要性は論を俟たない。本書は、そのような問題意識を持つ開発者にとって、良き指針となるであろう。

第II部 構成要素から始めよ:プログラミングパラダイム

第3章 パラダイムの概要

構造化プログラミング、オブジェクト指向プログラミング、関数型プログラミングの3つのプログラミングパラダイムを紹介。各パラダイムプログラマから特定の能力を奪うことで規律を課している。これら以外の新しいパラダイムは1958年から1968年の間に発見されていない。

印象的なフレーズ
重要なポイント
  • 3つのプログラミングパラダイムは、それぞれ特定の能力を奪うことで規律を課している
  • 1968年以降、新しいプログラミングパラダイムは発見されていない
理解度確認のための質問文

第4章 構造化プログラミング

Edsger DijkstraはGOTO文の濫用がプログラムの構造を破壊することを発見し、構造化プログラミングを提唱した。構造化プログラミングでは、順次、選択、反復の3つの基本構造のみを使用し、GOTO文を排除する。これにより、プログラムを階層的に分割し、論理的に証明することが可能になった。ただし、数学的な証明は実用的ではなく、テストによってプログラムの正当性を示すことが一般的である。

印象的なフレーズ
  • 構造化プログラミングは、直接的な制御の移行に規律を課すものである
  • プログラムが正しくないことは証明できるが、正しいことは証明できない
重要なポイント
  • 構造化プログラミングは、GOTO文を排除し、順次、選択、反復の3つの基本構造のみを使用する
  • プログラムの正当性は数学的な証明ではなく、テストによって示される
理解度確認のための質問文
  • 構造化プログラミングが排除したものは何か?
  • 構造化プログラミングで使用される3つの基本構造は何か?
  • プログラムの正当性を示すために使われる方法は何か?

第5章 オブジェクト指向プログラミング

オブジェクト指向プログラミング(OOP)の本質は、ポリモーフィズムを使ってソースコードの依存関係を制御する能力である。OOPによってソースコードの依存関係を制御の流れとは逆転させることができ、これを依存関係逆転の原則という。これにより、上位レベルのポリシーを含むモジュールを、下位レベルの詳細を含むモジュールから分離し、独立してデプロイ・開発できるようになる。

印象的なフレーズ
重要なポイント
理解度確認のための質問文

第6章 関数型プログラミング

関数型プログラミングでは、変数は一度初期化されると変更されない。これにより、並行処理における競合状態やデッドロックなどの問題を防ぐことができる。ただし、現実のアプリケーションでは、状態を持つ部分と持たない部分に分離し、状態を持つ部分に適切な保護メカニズムを適用する必要がある。将来的には、十分な記憶容量と処理能力によって、アプリケーションを完全に不変にすることが可能になるかもしれない。

印象的なフレーズ
  • 関数型プログラミングは、代入に規律を課すものである
  • 十分な記憶容量と十分な処理能力があれば、アプリケーションを完全に不変にできる
重要なポイント
  • 関数型プログラミングでは、変数は一度初期化されると変更されない
  • 現実のアプリケーションでは、状態を持つ部分と持たない部分に分離し、適切な保護メカニズムを適用する必要がある
理解度確認のための質問文

第II部の重要な概念

  • プログラミングパラダイム:プログラミングの方法や考え方を表す概念。構造化プログラミング、オブジェクト指向プログラミング、関数型プログラミングなどがある。
  • 構造化プログラミング:GOTO文を排除し、順次、選択、反復の3つの基本構造のみを使用するプログラミングパラダイム。プログラムの論理的な構造を明確にし、理解や保守を容易にする。
  • オブジェクト指向プログラミング:データと関連する処理をオブジェクトとしてまとめ、相互作用させるプログラミングパラダイムカプセル化、継承、ポリモーフィズムの概念を持つ。
  • ポリモーフィズム:同じインターフェースを持つオブジェクトが、それぞれ独自の方法で振る舞うことができる性質。オブジェクト指向プログラミングの重要な概念の1つ。
  • 依存関係逆転の原則:上位レベルのモジュールが下位レベルのモジュールに依存するのではなく、両方が抽象化に依存するようにするという原則。オブジェクト指向設計の重要な原則の1つ。
  • 関数型プログラミング:副作用を避け、状態変化を最小限に抑えるプログラミングパラダイム。データを変更するのではなく、関数を使ってデータを変換する。

第II部の要点

「Clean Architecture」の第II部では、プログラミングパラダイムとそれらがソフトウェアアーキテクチャに与える影響について解説している。著者は、構造化プログラミング、オブジェクト指向プログラミング、関数型プログラミングの3つのパラダイムに焦点を当て、それぞれのパラダイムプログラマに課す規律と、その結果もたらされる利点について説明している。

構造化プログラミングはGOTO文を排除し、プログラムの論理的な構造を明確にした。オブジェクト指向プログラミングは、ポリモーフィズムを使ってソースコードの依存関係を制御する能力をプログラマに与えた。関数型プログラミングは、副作用を避け、状態変化を最小限に抑えることで、並行処理における問題を防ぐことができる。

著者は、これらのパラダイムプログラマから特定の能力を奪うことで、プログラムに一定の規律を課していると指摘する。そして、これらのパラダイムを適切に使うことで、ソフトウェアアーキテクチャをより柔軟で保守性の高いものにできると主張している。

第II部の考察

「Clean Architecture」の第II部で著者が示した洞察は、ソフトウェア開発の歴史を振り返り、プログラミングパラダイムの役割を再考するものである。著者は、3つの主要なプログラミングパラダイムがそれぞれプログラマに規律を課し、特定の問題を解決してきたと指摘する。これは、プログラミングパラダイムの意義を明確に示すものであり、ソフトウェア開発者にとって重要な示唆を与えてくれる。

特に、オブジェクト指向プログラミングと関数型プログラミングの重要性が強調されている。オブジェクト指向プログラミングは、ポリモーフィズムを通じてソースコードの依存関係を制御する能力を与え、システムの柔軟性と保守性を高める。一方、関数型プログラミングは、副作用を避け、状態変化を最小限に抑えることで、並行処理における問題を防ぐことができる。これらのパラダイムを適切に使うことで、ソフトウェアの品質と信頼性を向上させることができるだろう。

ただし、著者の主張にはいくつかの限界もある。まず、著者は1968年以降、新しいプログラミングパラダイムが発見されていないと述べているが、これは厳密には正しくない。例えば、アスペクト指向プログラミングやコンポーネント指向プログラミングなど、新しいパラダイムが提案されている。また、著者は関数型プログラミングの利点を強調しているが、現実のアプリケーションでは完全に状態を排除することは難しく、オブジェクト指向プログラミングとの適切な組み合わせが必要になる。

とはいえ、著者の主張は全体としてソフトウェア開発者に重要な示唆を与えるものである。プログラミングパラダイムの役割を理解し、それらを適切に使うことで、より柔軟で保守性の高いソフトウェアアーキテクチャを設計できるだろう。また、著者が指摘するように、十分な記憶容量と処理能力が利用可能になれば、関数型プログラミングの利点がさらに発揮され、ソフトウェアの信頼性と品質が向上することが期待できる。

ソフトウェア開発者は、これらのプログラミングパラダイムの利点と限界を理解し、適材適所で使うことが求められる。そのためには、各パラダイムの基礎となる原理を深く理解し、それらを実践に活かす努力が必要不可欠である。「Clean Architecture」の第II部は、そのための優れたガイドとなるだろう。

第III部 設計の原則

第7章 SRP:単一責任の原則

モジュールはたったひとつのアクターに対して責務を負うべきである。アクターとは、変更を求めるグループのことを指す。異なるアクターのコードを1つのモジュールにまとめると、想定外の重複や、マージの際のリスクが生じる。これを避けるために、アクターごとにコードを分割する必要がある。

印象的なフレーズ
  • モジュールはたったひとつのアクターに対して責務を負うべきである
  • 想定外の重複は避けられる
  • アクターの異なるコードは分割するべき
重要なポイント
  • モジュールを変更する理由は1つであるべき
  • 異なるアクターのコードを1つのモジュールにまとめるとリスクが生じる
  • アクターごとにコードを分割することが重要
理解度確認のための質問文
  • 単一責任の原則において、「アクター」とは何を指すか?
  • 異なるアクターのコードを1つのモジュールにまとめるとどのようなリスクが生じるか?
  • 単一責任の原則に従うためにはどのようにコードを分割すべきか?

第8章 OCP:オープン・クローズドの原則

ソフトウェアの構成要素は拡張に対して開いていて、修正に対して閉じていなければならない。変更の影響を受けずにシステムを拡張しやすくするために、システムをコンポーネントに分割し、コンポーネントの依存関係を階層構造にする。上位レベルのコンポーネントが下位レベルの変更の影響を受けないようにする。

印象的なフレーズ
  • ソフトウェアの構成要素は拡張に対して開いていて、修正に対して閉じていなければならない
  • 上位レベルのコンポーネントが下位レベルの変更の影響を受けないようにする
  • 変更の影響を受けずにシステムを拡張しやすくする
重要なポイント
  • ソフトウェアは拡張に開いていて、修正に閉じているべき
  • システムをコンポーネントに分割し、依存関係を階層構造にする
  • 上位レベルが下位レベルの変更の影響を受けないようにする
理解度確認のための質問文
  • オープン・クローズドの原則とはどのような原則か?
  • オープン・クローズドの原則に従うためにシステムはどのように設計されるべきか?
  • なぜ上位レベルのコンポーネントが下位レベルの変更の影響を受けないようにする必要があるのか?

第9章 LSP:リスコフの置換原則

S型のオブジェクトo1の各々に対応するT型のオブジェクトo2が存在し、Tを使って定義されたプログラムの振る舞いがo1に置き換えても変わらない場合、SはTの派生型であると言える。置換可能性に違反すると、システムのアーキテクチャが複雑になる。

印象的なフレーズ
重要なポイント
  • 派生型の置換可能性が重要
  • 置換可能性の違反はアーキテクチャを複雑にする
理解度確認のための質問文
  • リスコフの置換原則における「派生型」とはどのようなものか?
  • 置換可能性に違反するとどのような問題が生じるか?
  • リスコフの置換原則はアーキテクチャにどのような影響を与えるか?

第10章 ISPインターフェイス分離の原則

必要としないモジュールに依存することは有害である。使っていないメソッドの変更によって再コンパイルや再デプロイを強制されたり、使っていない部分の障害の影響を受けたりするリスクがある。インターフェイスを分離することで、このような問題を回避できる。

印象的なフレーズ
  • 必要としないモジュールに依存することは有害である
  • インターフェイスを分離することで問題を回避できる
重要なポイント
  • 不要なモジュールへの依存は有害
  • インターフェイスの分離によって依存関係の問題を回避できる
理解度確認のための質問文
  • インターフェイス分離の原則とはどのような原則か?
  • 不要なモジュールへの依存はどのような問題を引き起こすか?
  • インターフェイスの分離によってどのように依存関係の問題を解決できるか?

第11章 DIP:依存関係逆転の原則

ソースコードの依存関係は具象ではなく抽象を参照すべきである。変化しやすい具象クラスではなく、安定した抽象インターフェイスに依存することで、柔軟なシステムを作ることができる。依存関係逆転の原則を満たさない具象コンポーネントは分離する。

印象的なフレーズ
重要なポイント
理解度確認のための質問文
  • 依存関係逆転の原則が推奨するソースコードの依存関係とはどのようなものか?
  • なぜ変化しやすい具象クラスではなく、安定した抽象インターフェイスに依存すべきなのか?
  • 依存関係逆転の原則を満たさない具象コンポーネントをどのように扱うべきか?

第III部の重要な概念

  • モジュール:関連する機能や責任をまとめた、ソフトウェアの構成単位。
  • コンポーネント:独立してデプロイ可能な、ソフトウェアの構成要素。モジュールよりも大きな単位。
  • インターフェイス:モジュールやコンポーネントの機能を定義し、他の部分との契約を表す。
  • 抽象:具体的な実装の詳細を隠蔽し、本質的な機能や振る舞いを表現したもの。
  • 具象:抽象の具体的な実装。詳細な内部動作を含む。
  • 依存関係:あるモジュールやコンポーネントが他のモジュールやコンポーネントを利用する関係。
  • 責任:モジュールやコンポーネントが担当する機能や役割。
  • 変更:要件の変化や不具合の修正などによって、ソフトウェアに加えられる修正。
  • 拡張:既存の機能はそのままに、新しい機能を追加すること。
  • アーキテクチャ:ソフトウェアシステムの全体的な構造や設計方針。

第III部の要点

「Clean Architecture」の第III部では、SOLID原則と呼ばれる5つの重要な設計原則について解説されている。これらの原則は、変更に強く、理解しやすく、再利用性の高いソフトウェア構造を作るための指針となる。

単一責任の原則(SRP)は、モジュールが1つの責任のみを持つべきだと述べている。オープン・クローズドの原則(OCP)は、ソフトウェアが拡張に開いていて、修正に閉じているべきだと説明する。リスコフの置換原則(LSP)は、派生型がベースとなる型と置換可能であるべきだと主張する。インターフェイス分離の原則(ISP)は、不要なモジュールへの依存を避けるべきだと述べている。依存関係逆転の原則(DIP)は、具象ではなく抽象に依存すべきだと説明する。

これらの原則に従うことで、ソフトウェアシステムを構成するモジュールやコンポーネントの役割と責任が明確になり、変更の影響範囲を限定できる。また、抽象インターフェイスを介して疎結合な設計を実現することで、システムの柔軟性と拡張性を高めることができる。

SOLID原則は、適切なソフトウェアアーキテクチャを設計するための基礎となる考え方を提供している。これらの原則を理解し、実践することは、複雑なソフトウェアシステムを効果的に構築し、維持していくために不可欠である。

第III部の考察

「Clean Architecture」の第III部で紹介されているSOLID原則は、ソフトウェア設計における重要な指針を提供している。これらの原則に従うことで、変更に強く、理解しやすく、再利用性の高いソフトウェア構造を実現できる。特に、単一責任の原則と依存関係逆転の原則は、モジュールやコンポーネントの役割と責任を明確にし、疎結合な設計を促進する上で大きな役割を果たしている。

一方で、これらの原則を適用する際には、現実的な制約や trade-off についても考慮する必要がある。例えば、完全に独立したモジュールを作ることは理想的だが、時にはある程度の依存関係を許容しなければならない場合もある。また、インターフェイスの分離は重要だが、過度な分離はかえって複雑性を増大させる可能性がある。

SOLID原則は、ソフトウェア設計の基本的な考え方を示してくれるが、これらを絶対的なルールとしてではなく、状況に応じて柔軟に適用していくことが重要だと考える。開発チームは、これらの原則の本質的な目的を理解した上で、プロジェクトの特性や制約に合わせて適切に応用していく必要がある。

また、SOLID原則はオブジェクト指向設計の文脈で語られることが多いが、その本質的な考え方は、他のパラダイムアーキテクチャスタイルにも応用可能だと思われる。例えば、関数型プログラミングにおける純粋関数の考え方は、単一責任の原則と通じるものがある。

SOLID原則は、ソフトウェア設計における普遍的な価値を提供してくれる。これらの原則を深く理解し、現実的な制約の中で適切に応用していくことが、高品質なソフトウェアシステムを構築するための鍵となるだろう。同時に、これらの原則を絶対視するのではなく、状況に応じて柔軟に解釈し、適用していくことも重要である。

第IV部 コンポーネントの原則

第12章 コンポーネント

コンポーネントとは、デプロイ可能な最小単位のこと。かつてはプログラムの配置場所をプログラマが管理していたが、コンパイラの進化によってリロケータブル化が実現し、動的リンクによるコンポーネント化が可能になった。

印象的なフレーズ
  • 「プログラムは、コンパイルとリンクに使える時間を使い切るまで肥大化する」
重要なポイント
  • コンポーネントはデプロイ可能な最小単位である
  • リロケータビリティとは、プログラムを再配置可能にすること
  • 動的リンクによって、実行時にコンポーネントを入れ替えることが可能になった
理解度確認のための質問文

第13章 コンポーネントの凝集性

コンポーネントの凝集性には、再利用・リリース等価の原則(REP)、閉鎖性共通の原則(CCP)、全再利用の原則(CRP)がある。これらの原則は時にトレードオフの関係にあり、バランスを取ることが重要。

印象的なフレーズ
  • 「変更の種類が似ているクラスをひとつのコンポーネントにまとめる」
  • 「不要なものには依存しないこと」
重要なポイント
  • 再利用性と開発の利便性はトレードオフの関係にある
  • 再利用・リリース等価の原則(REP)は、再利用の単位とリリースの単位を一致させるべきとする原則
  • 閉鎖性共通の原則(CCP)は、同じタイミングで変更されるクラスは同じコンポーネントにまとめるべきとする原則
  • 全再利用の原則(CRP)は、再利用時に不要な依存を避けるべきとする原則
理解度確認のための質問文
  • 再利用・リリース等価の原則(REP)とは何か?
  • 閉鎖性共通の原則(CCP)とは何か?
  • 全再利用の原則(CRP)とは何か?

第14章 コンポーネントの結合

コンポーネントの結合には、非循環依存関係の原則(ADP)、安定依存の原則(SDP)、安定度・抽象度等価の原則(SAP)がある。コンポーネントの依存関係は時とともに変化するので、これらの原則を使って適切に管理する必要がある。

印象的なフレーズ
  • コンポーネントの依存構造は、システム設計の際に検討するだけのものではなく、その後もどんどん変わっていく」
  • 「無駄でもないし、大きな苦痛を伴うこともない」
重要なポイント
理解度確認のための質問文
  • 非循環依存関係の原則(ADP)とは何か?
  • 安定依存の原則(SDP)とは何か?
  • 安定度・抽象度等価の原則(SAP)とは何か?

第IV部の重要な概念

  • コンポーネント:独立してデプロイできる、ソフトウェアの構成単位。クラスやモジュールを含む。
  • 凝集性:コンポーネント内の要素がどれだけ密接に関連しているかを表す指標。高いほうがよい。
  • 結合度:コンポーネント間の依存関係の度合いを表す指標。低いほうがよい。
  • 循環依存:複数のコンポーネントが互いに依存し合っている状態。避けるべき。
  • 主系列:コンポーネントの抽象度と安定度のバランスが取れている状態。

第IV部の要点

第IV部では、ソフトウェアシステムをコンポーネントに分割する際の原則について説明されている。コンポーネントは独立してデプロイできる単位であり、クラスやモジュールをまとめたものである。コンポーネント分割の際には、凝集性と結合度を適切に管理することが重要である。

凝集性に関する原則としては、REP、CCP、CRPがある。再利用性を高めつつ、変更の影響範囲を限定するために、これらの原則を適用する。一方、結合度に関する原則としては、ADP、SDP、SAPがある。コンポーネント間の依存関係を適切に管理し、循環依存を避け、安定度と抽象度のバランスを取ることが重要である。

これらの原則を適用することで、保守性と拡張性の高いソフトウェアアーキテクチャを設計できる。ただし、原則同士がトレードオフの関係になることもあるため、状況に応じて適切なバランスを取る必要がある。また、コンポーネント構造は固定ではなく、システムの成長に合わせて変化していくものであることを理解しておくことも重要である。

第IV部の考察

「Clean Architecture」の第IV部で説明されているコンポーネントの原則は、ソフトウェアアーキテクチャを設計する上で非常に重要な概念だと言える。システムを適切なコンポーネントに分割することで、保守性や拡張性を高めることができる。特に、凝集性を高め、結合度を低く保つことは、変更の影響範囲を限定し、システムの進化を容易にする上で欠かせない。

著者が提示している個々の原則は、いずれも納得感のある内容であり、実際のソフトウェア開発で活用できる指針となっている。REPやCCPのように、保守性と再利用性のバランスを取ることを重視する原則もあれば、ADPやSAPのように、アーキテクチャの安定性を確保することを重視する原則もある。これらの原則をバランス良く適用することが、優れたアーキテクチャ設計につながるのだろう。

ただし、著者も指摘しているように、これらの原則はトレードオフの関係にあることが多い。そのため、画一的に適用するのではなく、システムの特性や要件に合わせて適切に取捨選択することが重要である。また、コンポーネント構造は固定ではなく、システムの成長に合わせて変化させていく必要がある。アーキテクトには、原則を理解した上で、柔軟に適用していく力量が求められると言えるだろう。

本書で示されている原則は、ソフトウェア開発者にとって非常に示唆に富む内容だと感じた。一方で、実際のソフトウェア開発では、これらの原則を完璧に適用することは難しいかもしれない。特に、レガシーシステムの改修や、短期的な開発プロジェクトにおいては、理想的なアーキテクチャ設計に時間を割くことが難しい場合もあるだろう。

とはいえ、長期的な視点に立てば、適切なアーキテクチャ設計は非常に重要である。本書で示されている原則を、開発現場で少しずつでも実践に移していくことが、ソフトウェアの品質を高め、開発の効率を上げることにつながるのではないだろうか。

第V部アーキテクチャ

第15章 アーキテクチャとは?

アーキテクチャの目的は、システムの開発・デプロイ・運用・保守を容易にすることである。優れたアーキテクトは、プログラミングを継続し、チームの生産性を最大化し、ソフトウェアを長期間にわたり使いやすくするための設計を行う。アーキテクチャの主な関心事は、システムのユースケース、運用、開発、デプロイをサポートすることであり、詳細な技術的決定をできる限り遅らせることが重要である。

印象的なフレーズ
  • 「優れたソフトウェアアーキテクトは最高のプログラマである」
  • アーキテクチャの主な目的は、システムのライフサイクルをサポートすること」
  • 「優れたアーキテクチャがあれば、システムを容易に理解・開発・保守・デプロイできる」
重要なポイント
  • アーキテクチャはシステムの「形状」を決定し、開発・デプロイ・運用・保守を容易にする
  • アーキテクチャはシステムの振る舞いを決定するものではない
  • アーキテクトは技術的な決定をできる限り遅らせ、選択肢を残すべき
理解度確認のための質問文
  • ソフトウェアアーキテクトの主な役割は何か?
  • アーキテクチャが直接的に影響を与えるのはシステムのどの側面か?
  • 優れたアーキテクチャを実現するための戦略は何か?

第16章 独立性

優れたアーキテクチャは、ユースケース、運用、開発、デプロイの4つの独立性をサポートしなければならない。これを実現するには、ビジネスルール、フレームワークユーザーインターフェイス、データベースなどを切り離す必要がある。アーキテクトは、モノリシック、コンポーネント、サービスなどの切り離し方式を状況に応じて選択し、コンポーネント間の依存関係を適切に管理する。

印象的なフレーズ
  • アーキテクチャの目的は、求められるシステムを構築・維持するために必要な人材を最小限に抑えること」
  • 「優れたアーキテクチャは、ソースコードを変更から保護してくれる」
  • 「優れたアーキテクチャがあれば、システムはモノリシックとして生まれ、サービスやマイクロサービスまでたどり着くことが可能」
重要なポイント
  • アーキテクチャは、ユースケース、運用、開発、デプロイの4つの独立性をサポートすべき
  • ビジネスルール、フレームワーク、UI、データベースなどを切り離すことが重要
  • モノリシック、コンポーネント、サービスなどの切り離し方式を状況に応じて選択する
  • 偶然の重複を排除するために、過剰な抽象化に注意する
理解度確認のための質問文
  • 優れたアーキテクチャがサポートすべき4つの独立性とは何か?
  • ビジネスルールとデータベースを切り離すことの利点は何か?
  • モノリシック、コンポーネント、サービスの切り離し方式の違いは何か?

第17章 バウンダリー: 境界線を引く

アーキテクチャの境界線は、「重要なもの」と「重要ではないもの」の間に引く。ビジネスルールとUIの間、ビジネスルールとデータベースの間などに境界線を引き、それぞれを独立して変更できるようにする。この境界線によって、フレームワークやデータベースなどの詳細な決定を遅らせることができる。境界線は、単一責任の原則(SRP)と閉鎖性共通の原則(CCP)を適用して決定する。

印象的なフレーズ
  • 「アーキテクトの目的は、求められるシステムを構築・維持するために必要な人材を最小限に抑えること」
  • 「境界線は、変更する理由の違いでシステムの要素を切り離すところに引く」
  • フレームワークは使用するツールであり、アーキテクチャが従うものではない」
重要なポイント
  • 境界線は「重要なもの」と「重要ではないもの」の間に引く
  • ビジネスルール、UI、データベースなどの間に境界線を引く
  • 境界線によって、詳細な決定を遅らせ、変更の影響を局所化できる
  • SRPとCCPを適用して境界線を決定する
  • フレームワークに依存しないアーキテクチャを設計する
理解度確認のための質問文

第18章 境界の解剖学

アーキテクチャの境界には、モノリシック、バイナリコンポーネント、ローカルプロセス、サービスの4つの形態がある。これらの境界は、関数呼び出し、動的リンク、プロセス間通信、ネットワーク通信などの方法で越えられる。境界を越えるときは、ソースコードの依存関係を適切に管理し、下位レベルから上位レベルに向かうようにする。複雑なシステムでは、これらの境界が混在することが多い。

印象的なフレーズ
重要なポイント
  • アーキテクチャの境界には4つの形態がある
  • 境界を越えるときは、ソースコードの依存関係を適切に管理する
  • 境界を越える通信には、シンプルなデータ構造を使用する
  • 複雑なシステムでは、複数の境界形態が混在する
  • サービスとアーキテクチャの境界の関係は一様ではない
理解度確認のための質問文
  • アーキテクチャの境界にはどのような形態があるか?
  • 境界を越える通信ではどのような点に注意すべきか?
  • サービスとアーキテクチャの境界の関係にはどのようなパターンがあるか?

第19章 方針とレベル

ソフトウェアシステムは、さまざまなレベルの方針を持つコンポーネントに分割される。レベルは、入力と出力からの距離で決まる。上位レベルの方針は下位レベルの詳細について知らず、下位レベルが上位レベルに依存する。コンポーネント間の依存関係は、上位レベルから下位レベルに向かう。方針は、変更頻度と重要性に基づいてコンポーネントにまとめられる。

印象的なフレーズ
  • 「ソフトウェアシステムは方針を示したものである」
  • 「レベルの厳密な定義は入力と出力からの距離である」
  • 「異なる理由で変更されるものとは何か? 明らかなものがいくつかある」
重要なポイント
  • システムはさまざまなレベルの方針を持つコンポーネントに分割される
  • レベルは入力と出力からの距離で決まる
  • 上位レベルは下位レベルの詳細を知らない
  • コンポーネント間の依存関係は上位レベルから下位レベルに向かう
  • 方針は変更頻度と重要性に基づいてまとめられる
理解度確認のための質問文
  • ソフトウェアシステムにおけるレベルとは何か?
  • コンポーネント間の依存関係はどのような向きになるべきか?
  • 方針をコンポーネントにまとめる際の基準は何か?

第20章ビジネスルール

ビジネスルールは、エンティティ(最重要ビジネスルールと最重要ビジネスデータ)とユースケース(アプリケーション固有のビジネスルール)に分類される。エンティティはビジネスの本質を表し、ユースケースはエンティティを制御する。ユースケースは、リクエストとレスポンスのデータ構造を使って、UIなどの詳細から独立する。ビジネスルールは、再利用可能で独立性の高いコードでなければならない。

印象的なフレーズ
  • 「ビジネスルールは、ソフトウェアシステムが存在する理由である」
  • 「エンティティはビジネスであり、それ以外の何者でもない」
  • 「ビジネスルールはシステムのなかで、最も独立していて、最も再利用可能なコードでなければいけない」
重要なポイント
  • ビジネスルールはエンティティとユースケースに分類される
  • エンティティは最重要ビジネスルールと最重要ビジネスデータを含む
  • ユースケースはアプリケーション固有のビジネスルールを含む
  • ユースケースはリクエストとレスポンスのデータ構造を使って詳細から独立する
  • ビジネスルールは再利用可能で独立性が高くなければならない
理解度確認のための質問文
  • ビジネスルールをエンティティとユースケースに分類する基準は何か?
  • エンティティとユースケースの関係はどのようなものか?
  • ビジネスルールが満たすべき特性は何か?

第21章 叫ぶアーキテクチャ

アプリケーションのアーキテクチャは、システムの本質的な要件(ユースケース)を反映し、そのことを明確に伝えるべきである。アーキテクチャフレームワークやデータベースなどの技術的な決定から独立し、ユースケースを中心に設計する。これにより、技術的な決定を遅らせ、システムの本質を理解しやすくなる。アーキテクチャは、フレームワークに依存せず、ユースケースを重視したテスト可能なものでなければならない。

印象的なフレーズ
  • 「アーキテクトの目的は、求められるシステムを構築・維持するために必要な人材を最小限に抑えること」
  • アーキテクチャフレームワークに関するものではない(そうあるべきではない)」
  • フレームワークはツールであり、生き方ではない」
重要なポイント
理解度確認のための質問文

第22章 クリーンアーキテクチャ

クリーンアーキテクチャは、エンティティ、ユースケースインターフェイスアダプター、フレームワークとドライバの4つの同心円で表される。中心に近いほどビジネスルールなどの上位レベルの方針を、外側に近いほどUIやデータベースなどの下位レベルの詳細を配置する。依存関係は内側から外側に向かうように制限する。これにより、フレームワークから独立し、テスト可能で、UIやデータベースの変更に強いシステムを実現できる。

印象的なフレーズ
  • 「ソフトウェアをレイヤーに分割して、依存性のルールを守れば、本質的にテスト可能なシステムを作り、それがもたらすメリットを受け取ることができる」
  • 「優れたシステムアーキテクチャは、このような決定を従属的かつ遅延可能なものにする」
  • 「ソフトウェアの要素を分離し、お互いのことがわからないように制限するというものである」
重要なポイント
理解度確認のための質問文

第23章 プレゼンターとHumble Object

Humble Objectパターンは、テストしにくい振る舞いとテストしやすい振る舞いを分離するために使用される。GUIビジネスロジックの分離には、Humble ObjectであるViewと、テスト可能なPresenterを使う。同様に、データベースゲートウェイやデータマッパー、サービスリスナーなどにもこのパターンが適用できる。アーキテクチャの境界でHumble Objectパターンを使用すると、システム全体のテスト容易性が向上する。

印象的なフレーズ
  • 「Humble Objectパターンは、ユニットテストを実行する人が、テストしにくい振る舞いとテストしやすい振る舞いを分離するために生み出されたデザインパターンである」
  • 「Viewは、Humble Objectである。こちらはテストが難しい。したがって、このオブジェクトのコードはできるだけシンプルに保っておく」
  • アーキテクチャの境界の近くには、Humble Objectパターンが潜んでいる」
重要なポイント
  • Humble Objectパターンは、テストしにくい振る舞いとテストしやすい振る舞いを分離する
  • GUIビジネスロジックの分離には、Humble ObjectであるViewとテスト可能なPresenterを使う
  • データベースゲートウェイ、データマッパー、サービスリスナーなどにもこのパターンが適用できる
  • アーキテクチャの境界でHumble Objectパターンを使用するとテスト容易性が向上する
理解度確認のための質問文
  • Humble Objectパターンの目的は何か?
  • GUIビジネスロジックを分離するためにどのようなオブジェクトを使うか?
  • Humble Objectパターンを適用することで得られる主な利点は何か?

第24章 部分的な境界

アーキテクチャの本格的な境界の構築にはコストがかかるため、状況に応じて部分的な境界を実装することがある。部分的な境界の実装方法として、独立してコンパイル・デプロイ可能なコンポーネントを準備した上で1つにまとめる方法、片方のみにインターフェイスを置く方法、Facadeパターンを使う方法などがある。部分的な境界の実装には、コストとメリットを考慮し、状況の変化に応じて段階的に進化させることが重要である。

印象的なフレーズ
  • 「本格的なアーキテクチャの境界はコストが高い」
  • 「優れたアーキテクトならば、このような境界はコストが高すぎると判断するだろう。だが、それと同時に、あとで必要になるかもしれないことを考えて、できるだけ境界を残したいとも思うだろう」
  • 「そう、これは一筋縄ではいかないのだ」
重要なポイント
  • 本格的な境界の構築にはコストがかかるため、部分的な境界の実装を検討する
  • 部分的な境界の実装方法には、コンポーネントの準備と統合、片方のみのインターフェイス、Facadeパターンなどがある
  • 部分的な境界の実装では、コストとメリットを考慮し、段階的に進化させることが重要
  • 状況の変化に応じて、境界の実装方法を見直し、適切な判断を下す必要がある
理解度確認のための質問文

1. 本格的なアーキテクチャの境界を実装するコストにはどのようなものがあるか?
2. 部分的な境界を実装する主な方法にはどのようなものがあるか?
3. 部分的な境界の実装において重要な考慮事項は何か?

第25章レイヤーと境界

小規模なシステムでは「UI」「ビジネスルール」「データベース」の3つのレイヤーで十分だが、大規模で複雑なシステムでは、より多くのレイヤーと境界が必要になる。レイヤーは、ユーザーインターフェイスビジネスロジック、永続化メカニズムなどの関心事で分割され、各レイヤーはAPIを通じて通信する。複数の情報の流れが存在し、それらがビジネスロジックで統合される。アーキテクトは、システムの進化に合わせて、適切な粒度でレイヤーと境界を設計し、管理する必要がある。

印象的なフレーズ
  • アーキテクチャの境界があらゆるところに存在することを示している」
  • 「我々アーキテクトは、それがいつ必要になるかに気を配らなければいけない」
  • 「優れたアーキテクトであれば、そうした変化を予見して、適切に進めていくのである」
重要なポイント
  • 複雑なシステムでは、多数のレイヤーと境界が必要になる
  • レイヤーは関心事で分割され、APIを通じて通信する
  • 複数の情報の流れが存在し、ビジネスロジックで統合される
  • アーキテクトは、システムの進化に合わせて、適切な粒度でレイヤーと境界を設計・管理する
  • 境界の実装には、コストと利点を考慮し、適切なタイミングで判断する必要がある
理解度確認のための質問文
  • 複雑なシステムにおいて、レイヤーはどのような基準で分割されるか?
  • レイヤー間の通信はどのように行われるか?
  • アーキテクトがレイヤーと境界の設計・管理において考慮すべき点は何か?

第26章 メインコンポーネント

メインコンポーネントは、システムの他のコンポーネントを作成・調整・監督する役割を持つ。メインコンポーネントは、システムの最下位レベルの方針であり、オペレーティングシステムに直接依存する。また、ファクトリやストラテジーなどのグローバルな要素を生成し、上位レベルのコンポーネントに制御を渡す。メインコンポーネントは、アプリケーションの初期状態や設定を扱い、外部リソースを管理する。メインコンポーネントは、アプリケーションのプラグインとして捉えることができる。

印象的なフレーズ
重要なポイント
理解度確認のための質問文

第27章 サービス:あらゆる存在

サービス指向アーキテクチャSOA)やマイクロサービスアーキテクチャは、サービス間の分離と開発・デプロイの独立性を強調するが、実際にはそれほど分離されておらず、独立性も部分的にしか実現できない。サービスはアーキテクチャを定義するものではなく、アーキテクチャの境界に囲まれた1つまたは複数のコンポーネントである。サービス内部でも、依存関係のルールに従ったコンポーネントアーキテクチャが必要である。サービスは、システムのスケーラビリティや開発の利便性に寄与するが、アーキテクチャにおいては付随的な要素である。

印象的なフレーズ
重要なポイント
理解度確認のための質問文
  • SOAやマイクロサービスが強調する点と、実際の限界は何か?
  • サービスとアーキテクチャの関係はどのようなものか?
  • サービス内部のアーキテクチャ設計において重要な点は何か?

第28章 テスト境界

テストはシステムの不可欠な一部であり、アーキテクチャに関与している。テストは、非常に詳細で具体的であり、テスト対象のコードに依存する。したがって、テストはアーキテクチャの最も外側の円に位置する。テストとシステムの間の結合度が高すぎると、テストの脆弱性が増し、システムの進化が妨げられる。この問題を解決するために、テストAPIを導入し、システムの構造からテストを分離する。テストAPIは、テストがシステムを操作し、検証するためのインターフェイスを提供する。

印象的なフレーズ
  • 「テストはシステムの外側ではない。安定度やリグレッションのメリットを提供するのであれば、テストもうまく設計すべきシステムの一部である」
  • 「テストをシステムの設計にうまく統合しないと、不安定なものになる。システムは硬直化し、変更は困難になるだろう」
  • 「テストAPIの目的は、テストをアプリケーションから分離することである」
重要なポイント
  • テストはシステムの不可欠な一部であり、アーキテクチャに関与している
  • テストはアーキテクチャの最も外側の円に位置し、テスト対象のコードに依存する
  • テストとシステムの高い結合度は、テストの脆弱性を増大させ、システムの進化を妨げる
  • テストAPIを導入し、システムの構造からテストを分離することが重要
  • テストAPIは、テストがシステムを操作し、検証するためのインターフェイスを提供する
理解度確認のための質問文
  • テストはアーキテクチャのどこに位置付けられるか?
  • テストとシステムの高い結合度がもたらす問題は何か?
  • テストAPIの目的と役割は何か?

第29章 クリーン組込みアーキテクチャ

組込みソフトウェアの開発では、ハードウェアの変化に適応し、ソフトウェアの寿命を延ばすことが重要である。そのために、ソフトウェアとハードウェアの依存関係を管理し、ハードウェア抽象化レイヤー(HAL)を導入する。また、プロセッサやOSの詳細をそれぞれ抽象化するプロセッサ抽象化レイヤー(PAL)とOS抽象化レイヤー(OSAL)を設けることで、ソフトウェアの移植性と柔軟性を高める。組込みソフトウェアにもSOLIDの原則を適用し、モジュール間の依存関係を適切に管理する。クリーン組込みアーキテクチャでは、ソフトウェアをターゲットハードウェアやOSから切り離し、オフターゲットでのテストを可能にする。

印象的なフレーズ
  • 「ソフトウェアは消耗しないが、管理できていないファームウェアやハードウェアの依存関係により、ソフトウェアが内部から破壊される可能性がある」
  • 「すべてのコードをファームウェアにすると、プロダクトの長期的な健康のためにならない」
  • 「クリーン組込みアーキテクチャは、プロダクトの長期的な健康のためである」
重要なポイント
  • 組込みソフトウェアの開発では、ハードウェアの変化への適応とソフトウェアの寿命の延長が重要
  • HAL、PAL、OSALを導入し、ソフトウェアとハードウェアの依存関係を管理する
  • 組込みソフトウェアにもSOLIDの原則を適用し、モジュール間の依存関係を適切に管理する
  • クリーン組込みアーキテクチャでは、ソフトウェアをターゲットハードウェアやOSから切り離し、オフターゲットでのテストを可能にする
理解度確認のための質問文
  • 組込みソフトウェアの開発において重要な2つの目標は何か?
  • HAL、PAL、OSALの役割は何か?
  • クリーン組込みアーキテクチャが目指すものは何か?

第V部の重要な概念

1. 依存関係のルール:ソースコードの依存関係は、常に内側(上位レベルの方針)に向かうべきである。
2. 境界:アーキテクチャの境界は、「重要なもの」と「重要ではないもの」の間に引かれ、コンポーネント間の依存関係を管理する。
3. Humble Object パターン:テストしにくい振る舞いとテストしやすい振る舞いを分離するためのデザインパターン
4. ユースケース:システムの本質的な要件を表し、アーキテクチャ設計の中心となるべきもの。
5. 抽象化:具体的な実装の詳細を隠蔽し、モジュールの独立性と柔軟性を高めるための手法。

第V部の要点

第V部では、クリーンアーキテクチャの原則を実際のソフトウェアシステムに適用するための具体的な方法論が提示されている。まず、システムを長期的に維持・発展させるための鍵となる「独立性」の概念が説明され、ユースケース、運用、開発、デプロイの4つの観点から、システムの各部分を独立させることの重要性が強調されている。

また、コンポーネント間の責務を明確に分離し、変更の影響範囲を局所化するための「境界」の概念が紹介され、その適切な設定方法が示されている。具体的には、単一責任の原則(SRP)と閉鎖性共通の原則(CCP)を適用することで、境界線を引くべき箇所を特定できることが説明されている。

さらに、クリーンアーキテクチャの中核をなす4層モデル(エンティティ、ユースケースインターフェイスアダプター、フレームワークとドライバ)が詳細に解説され、各層の役割と相互の関係性が明確化されている。この4層モデルに基づいてシステムを設計することで、ビジネスロジックフレームワークや技術的な詳細を分離し、システムの本質的な価値を守ることができる。

加えて、クリーンアーキテクチャの原則を、モノリシックシステム、コンポーネントベースのシステム、サービス指向のシステムなど、さまざまなアーキテクチャスタイルに適用する方法が示されている。特に、組込みシステムの開発において、ハードウェアとソフトウェアの依存関係を適切に管理する手法が具体的に提示されているのは、大きな特徴と言える。

以上のように、第V部では、クリーンアーキテクチャの原則を実践的に適用するための豊富な知見が提供されている。ただし、これらの原則を過度に追求することで、システムの複雑性が増大したり、開発の生産性が低下したりするリスクもあることには注意が必要である。アーキテクトには、プロジェクトの状況を見極め、適切なレベルでクリーンアーキテクチャの原則を適用することが求められる。

第V部の考察

第V部では、クリーンアーキテクチャの実践的な適用に焦点が当てられ、具体的な設計手法や留意点が詳細に説明されている。特に、システムを長期的に維持・発展させるための重要な概念として、「独立性」と「境界」が紹介され、これらを適切に管理することの重要性が強調されている。

「独立性」に関しては、ユースケース、運用、開発、デプロイの4つの観点から、システムの各部分を独立させることの意義が説明される。これにより、システムの一部の変更が他の部分に与える影響を最小限に抑え、保守性と柔軟性を高めることができる。また、「境界」の概念は、コンポーネント間の責務を明確に分離し、変更の影響範囲を局所化するために重要であると述べられている。

さらに、クリーンアーキテクチャの具体的な構成要素として、エンティティ、ユースケースインターフェイスアダプター、フレームワークとドライバの4つの層が提示され、それぞれの役割と相互の関係性が明確に示されている。この4層モデルに基づいてシステムを設計することで、ビジネスロジックフレームワークやデータベースなどの技術的な詳細を分離し、システムの本質的な価値を保護することができる。

また、クリーンアーキテクチャの原則を組込みシステムの開発に適用する方法が、具体的な事例を交えて説明されているのも特筆すべき点である。ハードウェアとソフトウェアの依存関係を適切に管理するための手法が提示され、組込みシステムの開発者にとって貴重な指針となっている。

一方で、第V部の内容は、かなり専門的で高度な話題が多く、初学者にとっては理解が難しい部分もあるだろう。また、クリーンアーキテクチャの原則を実践するには、プロジェクトの状況を見極め、適切なレベルで適用することが求められる。過度に原則に従うことで、かえってシステムの複雑性が増大したり、開発の生産性が低下したりする可能性もある点には注意が必要である。

とはいえ、総合的に見れば、第V部はクリーンアーキテクチャの実践的な適用に関する非常に有益な情報を提供していると言える。ここで示された原則やテクニックを習得し、自身のプロジェクトに適切に適用することで、長期的に維持・発展可能なソフトウェアシステムを構築することができるだろう。特に、経験豊富なアーキテクトやシステム設計者にとって、第V部の内容は大いに参考になるはずである。

第VI部 詳細

第30章 データベースは詳細

データベースはアーキテクチャの構成要素ではなく、単なるエンティティでデータを保持するツールに過ぎない。データベースはデータモデルとは別物であり、アーキテクチャ的にはデータの表現形式は重要ではない。そのため、アーキテクチャではデータベースの詳細を意識せずに設計を行うべきである。

印象的なフレーズ
  • データベースはドアノブのようなもの
  • データベースは詳細である
  • データモデルこそが重要
重要なポイント
理解度確認のための質問文
  • データベースをアーキテクチャの中心に据えるのはなぜ問題か?
  • アーキテクチャ設計においてデータモデルとデータベースはどのように扱うべきか?
  • アプリケーションはデータベースのデータ構造に縛られるべきか?

第31章 ウェブは詳細

ウェブはアーキテクチャの詳細であり、ビジネスロジックの中心と切り離して考えるべきである。ウェブは単なる入出力デバイスの一種で、60年代からデバイスに依存しないアプリケーションを書くことが求められていた。リッチなUIでもデバイス非依存のアーキテクチャは追求すべきであり、UIとアプリケーションの間の抽象化は可能である。

印象的なフレーズ
  • ウェブは何ひとつ変えなかった
  • ウェブはGUIであり、詳細である
  • UIとアプリの間の抽象化は可能
重要なポイント
  • ウェブはアーキテクチャの詳細である
  • ウェブはデバイスの一種で、デバイス非依存設計が重要
  • UIとアプリケーション間の抽象化は可能で追求すべき
理解度確認のための質問文

第32章 フレームワークは詳細

フレームワークアーキテクチャではなく、便利だが依存してはいけない詳細である。フレームワークの作者とユーザーの関係は不均等で、ユーザーはコミットメントを求められるがリスクを負う。そのため、フレームワークにはある程度距離を置き、ビジネスロジックから切り離すべきである。

印象的なフレーズ
重要なポイント
理解度確認のための質問文

第33章 事例:動画販売サイト

動画販売サイトの例を通じて、ユースケース駆動でコンポーネントを分割し、アクターごとに責務を切り分けるクリーンアーキテクチャの設計プロセスを示した。単一責任の原則と依存関係の方向に基づいてコンポーネントを分割することで、変更に強く、デプロイしやすいアーキテクチャが実現できる。

印象的なフレーズ
  • アクターとユースケースを見つける
  • 方針のレベルで分割する
  • 振る舞いとデータ構造を分離する
重要なポイント
理解度確認のための質問文

第34章 書き残したこと

設計の意図とは裏腹に、実装の詳細で設計が台無しになりやすい。レイヤー、機能、ポートとアダプター、コンポーネントなどの分割手法があるが、不適切なアクセス制御で設計の意図が損なわれる。そのため、コンパイラによるチェックやモジュール分割などの対策が必要である。設計を守るには実装の複雑さに配慮が欠かせない。

印象的なフレーズ
  • 悪魔は実装の詳細に宿る
  • 組織化とカプセル化は別物
  • 理想に走りすぎるな
重要なポイント
  • 設計の意図は実装詳細で台無しになりやすい
  • 設計意図を守るアクセス制御が重要
  • コンパイラチェックやモジュール分割などの対策を取る
  • 設計を守るには実装の複雑さへの配慮が必要
理解度確認のための質問文
  • 設計の意図が実装の詳細で損なわれやすい原因は何か?
  • 設計意図を守るためにはどのようなアクセス制御が重要か?
  • 設計を守るために実装の複雑さにどのように配慮すべきか?

第VI部の重要な概念

  • クリーンアーキテクチャビジネスロジックを詳細から独立させ、変更に強く、テスト可能で、デプロイしやすいソフトウェアアーキテクチャ
  • 詳細:ビジネスロジックから切り離すべき具体的な実装や技術のこと。データベース、フレームワーク、ウェブなどがある。
  • ビジネスロジック:アプリケーションの中核となる業務ルールや処理を指す。ドメインロジックとも呼ばれる。
  • ポートとアダプター:アプリケーションを内部(ドメイン)と外部(Infrastructure)に分け、疎結合アーキテクチャを実現するパターン。
  • インターフェイス分離の原則:クライアントが使用しないメソッドに依存することを避けるため、インターフェイスを小さく具体的な目的に沿って分割すること。
  • 単一責任の原則:モジュールを変更する理由がただ1つになるように、責務を分割してモジュール化すること。
  • 依存関係逆転の原則:上位レベルのポリシーを下位レベルの詳細に依存させず、詳細側がポリシーに依存するようにすること。

第VI部の要点

第VI部では、クリーンアーキテクチャの観点から見た詳細について議論している。まず、データベースやウェブ、フレームワークといった技術的詳細がアーキテクチャの中心であってはならないと主張する。これらは単なる実装の詳細であり、ビジネスロジックから切り離して扱うべきだという。

次に、動画販売サイトの例を通して、クリーンアーキテクチャに基づく設計プロセスを実演している。ユースケース駆動でコンポーネントを分割し、単一責任の原則と依存関係の方向に基づいてコンポーネントを配置することで、変更に強く、デプロイしやすいアーキテクチャが実現できることを示した。

最後に、設計の意図と実装詳細の関係について議論し、不適切なアクセス制御によって設計意図が損なわれやすいことを指摘する。設計を守るには、コンパイラチェックやモジュール分割などの対策とともに、実装の複雑さに配慮することが欠かせないと述べている。

全体を通して、ビジネスロジックを詳細から独立させ、設計意図を守ることの重要性が強調されている。そのためには、適切な設計原則の適用と、実装レベルでの配慮が必要不可欠であるというのが、本部のメッセージと言えるだろう。

第VI部の考察

エンジニアとして、「クリーンアーキテクチャ」の提唱する原則は非常に納得感がある。特に、ビジネスロジックを詳細から独立させることの重要性は、変更に強く、テスト可能で、再利用しやすいソフトウェアを実現する上で欠かせないポイントである。

一方で、現実のソフトウェア開発では、さまざまな制約の中でアーキテクチャ設計を行わなければならないのも事実である。納期やコストの制約、レガシーシステムの存在、チームメンバーのスキルレベルの差など、理想のアーキテクチャを適用することが難しい状況は多々ある。

そのような中で、設計の意図を可能な限り守りつつ、現実的な落とし所を見つけていくことが、アーキテクトに求められるスキルなのである。時には妥協も必要であるが、その場合でも、なぜ妥協するのかをチームで共有し、将来的な改善の余地を残しておくことが大切である。

また、設計意図を守るには、実装レベルの細かい配慮も欠かせない。コードレビューや静的解析ツールの活用など、ソースコードの品質を維持するための地道な活動を継続することが、アーキテクチャを守ることにつながるはずである。

クリーンアーキテクチャの原則は、あくまで設計のガイドラインであり、それをどのようにプロジェクトに適用するかは、エンジニアの創意工夫にかかっている。理想と現実のバランスを取りながら、ビジネスの価値につながるソフトウェアを作り上げていくことが、我々エンジニアの果たすべき責務である。

第VII部 付録・あとがき

付録A アーキテクチャ考古学

著者のソフトウェア開発キャリアの中で、アーキテクチャ的に興味深かったプロジェクトについて解説している。1970年代から1990年代初頭までのプロジェクトで学んだ教訓や失敗から、クリーンアーキテクチャの重要性を示している。境界の設定、モジュール化、インターフェイスの抽象化、プラグインアーキテクチャなどの概念の萌芽が見られる。技術の進歩とともにアーキテクチャも進化してきたが、基本的な原則は変わらないことを強調している。

印象的なフレーズ
  • 「体のありとあらゆる穴からコードがあふれてきた」
  • 「ビッグアーキテクチャの恐竜は消滅した」
重要なポイント
理解度確認のための質問文
  • アーキテクチャ考古学で紹介されたプロジェクトから学べる教訓は何か?
  • 著者の経験の中で、クリーンアーキテクチャの概念の萌芽が見られたのはどのような点か?
  • 技術の進歩とともにアーキテクチャがどのように進化してきたか?

あとがき

1990年代のビッグアーキテクチャの時代から、アジャイル開発の台頭によってソフトウェアアーキテクチャも機敏になったと述べている。しかし、フラジャイルアーキテクチャの問題点を指摘し、設計原則とクリーンアーキテクチャの重要性を訴えている。開発者がアーキテクトのように考え、現在の価値を提供しつつ将来の変更に備えたコードを書くことが求められる。そのためには、設計原則を実践し、チームで共有し、継続的に学習することが必要だと説いている。

印象的なフレーズ
  • 「価値を提供するためにすばやく拡張することはできるが、イノベーションのペースを維持することが非常に難しい設計」
  • 「今日の価値を提供しながら、明日の価値を阻害しないコードを書く」
  • 「本当の旅はここから始まる」
重要なポイント
  • アジャイル開発によってソフトウェアアーキテクチャも機敏になったが、フラジャイルアーキテクチャの問題がある
  • 現在の価値を提供しつつ、将来の変更に備えたコードを書くことが重要
  • 設計原則を実践し、チームで共有し、継続的に学習することが必要
理解度確認のための質問文

第VII部の重要な概念

  • 境界: システムの異なる部分や責務を明確に分離するための概念。適切な境界設定によって、モジュール化やインターフェイスの抽象化が可能になる。
  • モジュール化: システムを独立した機能単位に分割すること。変更の影響範囲を限定し、保守性や拡張性を高める。
  • インターフェイスの抽象化: モジュール間の依存関係を抽象的なインターフェイスを介して行うこと。実装の詳細を隠蔽し、柔軟性を確保する。
  • プラグインアーキテクチャ: 共通のインターフェイスを定義し、異なる実装を動的に差し替え可能にする設計。拡張性と柔軟性に優れている。

第VII部の要点

本書の第VII部では、著者のソフトウェア開発の経験から得られたアーキテクチャに関する知見が語られている。1970年代から1990年代初頭までのプロジェクトを通して、クリーンアーキテクチャの基礎となる概念の萌芽が見られることを示している。時代とともに技術は進歩してきたが、アーキテクチャの基本原則は普遍的であることを強調している。

また、1990年代のビッグアーキテクチャの時代から、アジャイル開発の台頭によってソフトウェアアーキテクチャも機敏になったことに触れている。しかし、フラジャイルアーキテクチャの問題点を指摘し、現在の価値を提供しつつ将来の変更に備えたコードを書くことの重要性を訴えている。そのためには、設計原則を理解し実践すること、チームで知識を共有すること、継続的に学習することが必要不可欠であると説いている。

第VII部の考察

本書の第VII部では、著者のソフトウェア開発の経験を通して、アーキテクチャの重要性と普遍性が語られている。時代とともに技術は進歩し、開発手法も変化してきたが、アーキテクチャの基本原則は変わらないことが強調されている。境界の設定、モジュール化、インターフェイスの抽象化、プラグインアーキテクチャなどの概念は、クリーンアーキテクチャの基礎となるものであり、著者の過去のプロジェクトにおいてもその萌芽が見られる。

また、ビッグアーキテクチャの時代からアジャイル開発の時代への移行について触れ、ソフトウェアアーキテクチャも機敏になったことを指摘している。しかし、フラジャイルアーキテクチャの問題点を指摘し、現在の価値を提供しつつ将来の変更に備えたコードを書くことの重要性を訴えている。

著者の主張は、設計原則とクリーンアーキテクチャの重要性を開発者に理解してもらい、実践につなげてもらうことにあると考えられる。開発者一人一人がアーキテクトのように考え、コードを書くことが求められている。そのためには、設計原則を学び、実践し、チームで知識を共有し、継続的に学習することが不可欠である。

本書の内容は、ソフトウェア開発者にとって示唆に富むものであり、アーキテクチャの重要性を再認識させてくれる。著者の経験に基づく知見は、現代のソフトウェア開発においても十分に通用するものである。一方で、具体的な実践方法やツールについては言及が少なく、読者自身が考えて適用していく必要がある。

また、アーキテクチャの原則を実践することが、必ずしも短期的な生産性の向上につながるわけではない点には注意が必要である。長期的な視点に立ち、継続的にアーキテクチャを改善していくことが重要であろう。

全体を通して、本書はソフトウェア開発者にとって価値ある一冊であり、アーキテクチャに関する理解を深め、実践するための指針を与えてくれる。著者の知見を活かし、クリーンアーキテクチャを目指して日々精進することが、開発者に求められていると言えるだろう。

まとめ

本書は、ソフトウェアアーキテクチャの重要性と、クリーンアーキテクチャの原則を理解し実践するための指針を提供している。著者の豊富な経験に基づく知見は、現代のソフトウェア開発においても十分に通用するものであり、開発者にとって示唆に富む内容となっている。クリーンアーキテクチャを目指して日々の開発に取り組むことで、保守性、拡張性、テスト容易性に優れたソフトウェアを構築することができるだろう。