はじめに
今回は、「Clean Architecture 達人に学ぶソフトウェアの構造と設計(以下 本書)」を読んで、個人的に刺さった箇所をまとめました。
エンジニアの方にはとてもおすすめできる本ですね。
明日から生かせそうなノウハウを学ぶことができました。
それではまず、本書の内容について軽く触れていきます。
どんな内容?
一言でいうと、「設計のベストプラクティスが学べる本」です!
著者は Robert C. Martin(別名 アンクル・ボブ) さんです。
アンクル・ボブは1970年代からプログラマでした。
その長いキャリアの中で、ソフトウェアと関わり続けてきた経験談が本書に散りばめられています。
ここ最近エンジニアになった身としては、そういった昔話がとても興味深かったです!
以下、本書の内容を引用しつつ、個人的に刺さった箇所についてまとめていきます。
ソフトウェアの基本は1960年台から変わっていない
現代のソフトウェアを過去のものと比べて気づくことがもうひとつある。
使われている素材は今も昔も変わっていない。
if文やwhileループなどが同じように使われている。
今どきの言語は、いろいろなことができるように思えますが、本質的には変わっていないということです。
書いているコードが同じなので、アーキテクチャのルールも同じです。
ひとつだけ違うのは、「我々現代人はルールを言語化できた」ということです。
本書では、これからこの「アーキテクチャのルール」について述べていくことになります。
設計 = アーキテクチャ
著者は、アーキテクチャは設計と同じである、と述べています。
設計とは何か?
アーキテクチャとは何か?
両者の違いは何か?
本書の目的は、こうした混乱を切り捨て、設計とアーキテクチャについて最終的な定義をすることである。
まずは、両者に違いがないことから主張したい。
何も違いはないのだ。
設計 = アーキテクチャ、ということです。
優れたアーキテクチャとは?
優れたアーキテクチャとは、「最小限の労力で構築・保守が可能」な設計のことです。
ソフトウェアアーキテクチャの目的は、求められるシステムを構築・保守するために必要な人材を最小限に抑えることである。
設計の品質は、顧客のニーズを満たすために必要な労力で計測できる。
必要な労力が少なく、システムのライフタイム全体で低く保たれているならば、その設計は優れている。
ソフトウェアはソフトでいなければならない
ソフトウェアは、ステークホルダーの変更に応じられるよう、ソフトにしておかなければなりません。
ソフトウェアは「ソフト」になるように考案されたものだ。
マシンの振る舞いを簡単に変更する手段になることを目的としたものである。
(中略)
つまり、簡単に変更できなければいけない。
ステークホルダーが機能を変更したいと思えば、その変更は簡単にできるようになっておくべきだ。
ソフトウェアに関する、とても本質的な主張ですね。
オブジェクト指向とは何か?
オブジェクト指向(OO:Object Oriented)、について本書の中で明確に定義されています。
OOとは、「ポリモーフィズムを使用することで、システムにあるすべてのソースコードの依存関係を絶対的に制御する能力」である。
これにより、アーキテクトは「プラグインアーキテクチャ」を作成できる。
これは、上位レベルの方針を含んだモジュールを下位レベルの詳細を含んだモジュールから独立させることである。
依存関係については今後も頻出します。
上位レベルのモジュールは、下位レベルのモジュールに依存しないようにすべき、と述べられています。
設計の5原則
設計を行う上で、意識すべき5つの原則があります。
原則名 | 内容 |
---|---|
単一責任の原則 | 個々のモジュールを変更する理由がたった一つになるようにすべき |
オープン・クローズドの原則 | 既存コードの変更よりも新規コードの追加によってシステムの振る舞いを変更できるようにすべき |
リスコフの原則 | 個々のパーツが交換可能となるようにすべき |
インターフェイス分離の原則 | 使っていないものへの依存を回避すべき |
依存関係逆転の原則 | 上位レベルのコードは下位レベルに依存しないようにすべき |
ソフトウェアの振る舞いは、拡張できるようにすべきである
こちらは「オープン・クローズドの原則」に関する記述です。
ソフトウェアの振る舞いは、既存の成果物を変更せず拡張できるようにすべきである、ということだ。
これこそが、我々がソフトウェアアーキテクチャを学ぶ根本的な理由だ。
ちょっとした拡張のために大量の書き換えが必要になるようなら、そのソフトウェアシステムのアーキテクトは大失敗への道を進んでいることになる。
拡張可能な設計!
肝に銘じます!
インターフェイスは分離させよ
こちらは「インターフェイス分離の原則」に関する記述です。
必要としないモジュールに依存することは一般的に有害とされる。
ソースコードの依存関係においては、再コンパイルや再デプロイを強制されるので明らかに有害であることがわかる。
だが、さらに上位のアーキテクチャレベルにおいても有害なのだ。
この辺りは今どきのフレームワークを採用していればあまり気にする必要はないかもしれません。
「最小の構成で実装する」という視点は持っておこう、と思いました。
再利用・リリース等価の原則(REP)
こちらはコンポーネントについての記述です。
ソフトウェアコンポーネントを再利用したくても、リリースプロセスでそのコンポーネントを追跡していなかったり、リリース番号がついていなかったりすると、うまく再利用できない。
再利用できない理由は単純で、リリース番号がついていなければ、再利用するコンポーネントの互換性を確認できないからだ。
開発者はコンポーネントの新しいリリースが出たことを知る必要があるし、そのリリースで何が変わったかも知る必要がある。
まさにGitがこの役割を果たしていますね!
当たり前のように使っているGitに、あらためて感謝します。
ちなみに本書では、コンポーネントを「デプロイの単位」と定義しています。
(Javaならjarファイル、Rubyならgemファイルなど)
循環依存は避けよ
コンポーネントは循環依存してはいけません。
コンポーネントの依存構造をきちんと管理しておく必要がある。
循環依存があってはいけない。
もし循環依存があれば「二日酔い症候群」は避けられない。
循環依存とは、コンポーネント同士が互いに依存し合っている関係をいいます。
「二日酔い症候群」とは、「昨日までは動いていたはずなのに、なぜか今日は動かないプログラム」のことを指します。
(あるあるですよね)
安定依存の原則
安定度の高い方向に依存すること。
安定度の高い、とはどういうコンポーネントでしょうか?
本書では、「多数のコンポーネントから依存されたコンポーネント」は安全度が高い、と述べられています。
ただ、すべてのコンポーネントに高い安全性は必要ありません。
基本的には、変更しやすいコンポーネントを変更しにくいコンポーネントに依存させる、という考え方で良いでしょう。
デプロイの重要性
アーキテクチャを考える上で、デプロイについての配慮は必要不可欠です。
ソフトウェアシステムが効果を生み出すためには、デプロイ可能な状態でなければいけない。
デプロイのコストが高ければ、その分だけシステムの有用性は低下する。
ソフトウェアアーキテクチャの目的は、システムを単一のアクションで簡単にデプロイできるようにすることである。
今でいう「CD」にあたりますかね。
以前の現場で、デプロイの際にFTPでファイルをサーバーにアップロードするという手順を指定されていたのですが、毎回苦痛で仕方なかったのを思い出しました……
設計の段階からデプロイまで考えておくのが重要ですね。
選択肢を残しておく
ソフトウェアをソフトに保つには、できるだけ長い期間、できるだけ多くの選択肢を残すことである。
では、「残すべき選択肢」とは何だろうか?
それは、重要ではない詳細である。
例えば、下記項目は「詳細」なので、早々に決めるのは良くない、と記載があります。
- データベース
- サーバー
- フレームワーク
- 通信プロトコル
他にも、「RDBを採用するかの決定を後回しにしてリリースした」といったエピソードも紹介されていました。
思考停止で決めてしまうのは良くない、という教訓ですね。
重複 = 悪、とは限らない
実装をしていると、処理内容が重複しているソースコードを共通化したい、と感じることがあります。
しかし本書では、軽々しく重複を共通化すべきではない、と論じています。
画面構成が同じ2つのユースケースを見ていこう。
おそらくアーキテクトはコードを共有したい衝動にかられるはずだ。
だが、本当にそうすべきだろうか?
これは本物の重複なのか?
偶然の重複なのか?
同じような処理に見えたとしても、安易に共通化してしまうと後々困ったことになるかもしれません。
別のコードに分かれているのには何か理由があるかもしれない、という意識を持つべきですね。
ビジネスルールがシステムの中心である
ビジネスルールとは、ビジネスマネーを生み出したり節約したりするルールや手続きのことだ。
(中略)
ビジネスルールは、ソフトウェアシステムが存在する理由である。
中心的な機能である。
お金を生み出したり節約したりするコードを保持したものである。
いわば、家宝である。
(中略)
ビジネスルールはシステムのなかで、最も独立していて、最も再利用可能なコードでなければいけないのだ。
商用のシステムである以上、根幹にはビジネスルールがある、という考え方です。
アメリカのこうしたビジネス文化は見習いたいものですね。
フレームワークはツールである
本書では、フレームワークに任せきりにはすべきでない、と記載されています。
アーキテクチャはフレームワークに関するものではない(そうあるべきではない)。
アーキテクチャはフレームワークから提供されるものではない。
フレームワークは使用するツールであり、アーキテクチャが従うものではない。
(中略)
たとえば、ヘルスケアシステムを構築しているならば、新しく参加したプログラマがソースリポジトリを見たときに、「ああ、これはヘルスケアシステムだ」と思えるようにしておくべきである。
フレームワークに使われるのではなく、フレームワークを使う、という意志を持とう、と決意しました。
変化しやすいものには依存するな
こちらは、テストについての記述です。
脆弱なテストは、システムを硬直化させるという悪影響を及ぼす。
システムを少し変更しただけで大量のテストが失敗するとなると、開発者は変更するのをためらうだろう。
(中略)
ソフトウェア設計の第一のルールは、その理由がテスト容易性だろうと何だろうと、常に同じである。
それは、変化しやすいものに依存しないだ。
たとえばブラウザ上で行うテストなどは変化しやすいので注意すべきです。
解決策として筆者は、「APIを活用してテストを行うべき」と述べています。
WEBアプリでいう、フロントエンドとサーバーサイドを分離すべき、という考えに近いでしょうか。
実際、のちの章で筆者は下記のように述べています。
GUIは詳細である。
ウェブはGUIである。
したがって、ウェブは詳細である。
アーキテクトとしては、こうした詳細をビジネスロジックの中心から切り離しておきたい。
設計の段階では、ウェブ画面(デザイン)に依存しないように気をつけましょう。
フレームワークと結婚するな!
本書では、フレームワークはよく考えて使うべき、と述べられています。
フレームワークを使うことは問題ない。
ただし、結合しないことが大切だ。
(中略)
自分のアプリケーションで何らかのフレームワークを使うことに決めた時点で、そのアプリケーションはフレームワークに縛られることになるのだと認識しておく必要がある。
幸いのときも、災いのときも、豊かなときも、貧しいときも、健やかなるときも、病めるときも、ほかのすべてを犠牲にしてでも、そのフレームワークを使うことになる。
色々と考えさせられるメッセージですね……!
publicには気をつけろ
publicアクセス修飾子は気軽に使ってはいけない、と本書では述べられています。
開発者は何も考えず、本能的にpublicを使っているように見える。
(中略)
せっかくプログラミング言語が提供してくれているカプセル化の仕組みを活用できていないということだ。
具象実装クラスを直接インスタンス化するような、アーキテクチャスタイルに違反したコードを防ぐ手段が一切なくなってしまう。
(中略)
もしJavaアプリケーションですべての型をpublicにしたら、パッケージは単なる組織化(フォルダのようなグループ化)の手段でしかなくなり、もはやカプセル化はできなくなる。
(中略)
すべての型がpublicであれば、Javaのパッケージはどうでもいい話になってしまう。
確かに、フレームワークを使用していると「基本的にはpublicを使用するものだ」と思ってしまいがちです。
アクセス修飾子は、適切な範囲を指定しましょう。
アクセス範囲を絞れば絞るほど、依存性を減らせます。
依存性が減れば、よりアーキテクチャの原則に沿ったシステムを組み立てられることでしょう。
おわりに
以上、「Clean Architecture 達人に学ぶソフトウェアの構造と設計」の内容をまとめながら個人的に刺さった部分についてお伝えしました。
エンジニアである以上、設計の機会は幾度となく訪れます。
そんな時の指針になる本だと感じました。
もし気になりましたら、ぜひ一度お手にとってみてください!
明日から役に立つ知見が得られるはずです。