見出し画像

Clean Architectureは全てのプログラマにお奨めしたい良著

Clean Architecture 達人に学ぶソフトウェアの構造と設計を読んだので、まとめてみます。コメントやツッコミなどのフィードバックがあればうれしいです。

続編としてクリーンアーキテクチャ本を読むためのポイントという記事を書きました。併せてご覧ください。

なぜ良著?

著者のロバート・C・マーチン(著書読んだことあるかも?)は、50年前から現代に至るまで、様々なアーキテクチャを見て、第一線級として開発し続けてきた経験を元に、どのアーキテクチャでもクリーンにしようとするなら、基本部分は変わらないと言ってて、それらが美味くまとまった本だからです。

いってみればコンピュータ工学について抑えるべきポイントを解説した本であり、The Clean Architectureそのものについてはほとんど割かれていません。それくらい、基本として知るべき事が書かれた本なのです。

最近のアーキテクチャを追いかけている人たちにとっては、どれも割と当たり前の内容でしょう。そういう人は元ネタや、その後の議論を追いかけるだけで事足りるはずです。

前提

本や、この記事に出てくる知識という言葉は、名前や構造など全てを指します。あるモジュールのファイル名や、中のクラス名、メソッドの有無、データの型、中の実装などは全て知識です。

本の構成

そもそもの元ネタは、The Clean Architectureという2012年のブログです。クリーンアーキテクチャ(The Clean Architecture翻訳)という2015年に翻訳された記事もあるので、読んでみるといいかもしれません。

The Clean Architectureは、DDDでもおなじみのレイヤーアーキテクチャの考えと、ヘキサゴナルアーキテクチャ(ポートとアダプタデザインパターン)や、他のいくつかのレイヤーアーキテクチャなどの成果を踏まえた、よりシンプルで強力なアーキテクチャを提唱するものです。

ブログの記事自体がめちゃくちゃシンプルで、The Clean Architectureを構成する要件しか書いていません。

この本は、そのThe Clean Architectureを理解するために必要な要素や背景をまとめたもので、アーキテクチャ論としての、クリーンなアーキテクチャについて理解する為の内容(いわば基本)が大半を占めています。

プログラミングパラダイムの話

3つのプログラミングパラダイム(構造化プログラミング、オブジェクト指向プログラミング、関数型プログラミング)は50年以上前からあったが、それらは本質的には3つの制約を課すものだと述べています。

・ 構造化プログラミングは、GOTOの乱用を排除
・ オブジェクト指向プログラミングは、ポインタ操作(によるポリモーフィズム)を排除
・ 関数型プログラミングでは、代入を排除

最後のは、異論が残りそうなヤツですがそれはさておいて、どのプログラミングパラダイムもいい感じの案配で使い分けると良いと思います。まぁ、現代のプログラミング言語や流行は大体そういう方向性です。

SOLID原則

オブジェクト指向プログラミングでよく出てくるやつです。

SRP(アクター視点から見た単一責務の原則)
OCP(コード自体を修正する必要性をなるべく減らして、アタッチメント的に機能を追加できる設計にしようという原則)
Liskovの置換原則(ポリモーフィズムにおいて、派生先の知識を使わずに済むようにする原則)
Interface分離原則(クラスのような詳細がダダ漏れなものに依存しないようする原則で、インターフェースも利用者にとって必要な最小限のみにする)
依存性逆流の原則(ビジネスロジックなどの上位概念は、より下位にある詳細の知識に依存せず書く原則と、それを実現するためのデザインパターン)

どれも大体は言ってることは似ていて「ある集団はシンプルに保つ」「不必要な知識を露出しない」というものです。

ここでいう詳細とは、RDBやAPIアクセス、ウェブ、フレームワークなどを指しています。ビジネスロジックやドメイン知識といった抽象化された概念とは異なり、実世界との関わりを強く持ったものが詳細です。

これらを守ると疎結合やテスタブル(ユニットテストしやすい)になり、メンテしやすくなるというメリットがあります。

コンポーネント

・ 依存関係で循環してはいけない(グラフでいうなら非循環有向グラフになるようにする)
Stable Dependency Principle

Stable Dependency Principleは、安定してるものに依存しようという原則です。

ある集団はそれが依存している先が少ないほど安定しているし、依存されてるほど安定しています。前者は、依存先が多いとそれだけ依存先の変更に左右されてしまいます。後者は、変更をすると影響が大きいので安定せざるを得ないという理由です。

ここでいう依存とは、知識を利用すること全てになります。

・ 自分より安定したものに依存するようにする(もし不安定なものを参照したいなら、安定した部分を抜き出したラッパー経由でアクセスするなどする)
・ 依存先は自分よりも安定したもので、なるべくより安定なものに依存する
・ 安定度は大体抽象度と同じになる(厳密に気にしても仕方ないけど、指針にはなるかも)

最近話題のスパゲティコードの件は、大体が安定に関する原則を守れていないことと、その前提となる適切な集団作りに失敗していることに起因します。

アーキテクチャ

アーキテクチャとは目的に沿ったシステムを作るために、システムの線引き(境界)と境界面をどう扱えば、変更に強いものになるか?です。

詳細(フレームワークとかRDBとかウェブとかその他)にあたるものの決定を出来うるかぎり先延ばしにする。その為にバウンダリなどを用いた抽象化を活用する。そうしておけば最悪乗り換える時でも変更は最小限に抑えられる。

境界の設定と境界面の取り扱い方をマスターしようぜという話です。

レイヤー

・ 同じような抽象度、密結合グループを適切にまとめて境界を引くと層になる
・ ユースケース(のレイヤー)とかは独立的に書ける
・ 正しく機能するレイヤーであればテスタブルになりやすい

クリーンアーキテクチャ

著者のブログで提唱してるアーキテクチャであるThe Clean Architectureです。

・ レイヤーアーキテクチャの一種
・ 円で表現される(が、あれはただのコンセプト図なので注意)
・ 円の内側(抽象・ロジック)は外(詳細)の知識に一切依存しない、一方通行にする(ports & adapters パターンによる依存性の逆流を活用する)
・ 境界を渡るオブジェクトはプレインなもの(JSならJSONableだし、JavaならPOJO)にする
・ 境界を渡るオブジェクトは境界内側の知識に沿ったオブジェクトにする
・ それぞれのレイヤーは基本的には、とてもテスタブルになる

エンティティ層とユースケース層を分けなくてもいいケースは、普通にありそうだし、最も外側の層は要らない可能性も普通にありそうです。がっつりエンタープライズなシステムを作るなら、4層+αになるでしょうが、2層だけでも十分価値がありますし、練習するならそこから始めるといいでしょう。

そもそも、クリーンアーキテクチャで有名なよく見かける図は、ただのコンセプト図なので、実際のシステムにおいては様々な構成があり得ます。思考停止せずに、それでいてクリーンにする原則(ここまでに出てきた全ての話)を破らないように、システムをアーキテクトしましょう。

ここで直接は書いていませんが、詳細にあたる interface & adapters 層なんかも、横に依存するのは避けるべきです(これまでのクリーンなアーキテクチャの原則で考えると、横には超えるべきではない境界があるでしょう)

Hambleオブジェクトパターン

テスタブルなものと、そうじゃないものを分離しとくと便利というデザインパターンです。

本の例ではViewとPresenterという分け方をしていてViewはテストしづらいHambleオブジェクトであり、Presenterは、Viewからテスタブルな部分を抽出したものとしています。

まとめ

プログラミングパラダイムに感謝を捧げながら設計の基本を守ればクリーンになるし、レイヤーを疎結合にして、依存を一方通行にすればテスタブルにもなるし、変更にも強くしやすいという理解をしています。

FacebookのFLUXも、循環はするものの依存性を一方通行にすることで、これまでの双方向性がもたらす組み合わせ爆発的な無秩序を防ぐアイデアで、有用性が大きく実証されています。おそらくウェブ開発でも随所で役立つものでしょう。

必要なことは、適切なグルーピングと抽象化をして、早すぎる詳細決定を排除することです。(早すぎる抽象化も、早すぎる最適化もどっちもダメ!という話ですね)

今後、もっとかみ砕いた上で詳細な記事を書いたり、TypeScriptで実現するクリーンアーキテクチャの記事(と技術同人誌)を書く予定です。

間違いなどあればご指摘いただけると幸いです。他感想、コメントなどいただければ幸いです。

Clean Architecture 達人に学ぶソフトウェアの構造と設計

続編としてクリーンアーキテクチャ本を読むためのポイントという記事を書きました。併せてご覧ください。

この記事が気に入ったらサポートをしてみませんか?