Posted at

SOLID原則とは!?重要なキーワードをまとめてみました|Clean Architecture 達人に学ぶソフトウェアの構造と設計- ②


はじめに

キーワードまとめ | Clean Architecture 達人に学ぶソフトウェアの構造と設計 - ①

前回書いたこの記事の続きです。

プログラミング言語はツールに過ぎず、重要なのはソフトウェアの設計力だと先輩から聞いたので、早速オススメされた本を読みました。


本の紹介

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

著者のロバート・C・マーチンは、50年前から現代に至るまで、さまざまなアーキテクチャを見てきた凄腕エンジニアです。彼は、どのアーキテクチャでもクリーンにするなら、基本部分は変わらないと言っています。それら彼の長きに渡る知見をうまくまとめた良書です。

言い換えると、コンピューター工学の基本を抑えた内容になっていて、全エンジニアにとって必須とも言える知識を得ることができます!


この記事の目的

本の中でクリーンなアーキテクチャでソフトウェアを開発するために、著者は「SOLID原則」というルールを紹介しています。その「SOLID原則」について、まとめてみました。

簡単にまとめたので詳細については省略していますが、アーキテクチャ学習の導入になれれば幸いです。


「SOLID原則」の概要


SOLID原則を学ぶメリット


  • ソースコードの変更に強いソフトウェアを開発できる

  • 他人がレビューしやすい、読みやすいコードを書くことができる


5つの原則の頭文字を取って S O L I D


単一責任の原則(SSR : Single Responsibility Principle)

変更する理由が同じものは集める、変更する理由が違うものは分ける。これはつまり、1つのサブシステムやモジュール、クラス、関数などに、変更する理由が2つ以上あるようではいけない。


オープン・クローズドの原則(OCP : Open-Closed Principle)

ソフトウェアを変更しやすくするために、既存のコードの変更よりも新しいコードの追加によってシステムの振る舞いを変更できるように設計すべき。


リスコフの置換原則(LSP : Liskov Substitution Principle)

交換可能なパーツを使ってソフトウェアシステムを構築するなら、個々のパーツが交換可能になるよう契約のもと開発しなければならないということ。


インターフェイス分離の法則(ISP : Interface Segregation Principle)

使っていないものへの依存は禁止する。


依存関係逆転の原則(DIP : Dependency Inversion Principle)

上位レベルの方針の実装コードは、下位レベルの詳細の実装コードに依存すべきではなく、逆に詳細側へと依存すべき。


まとめ

原則の1つ1つの名前を覚える必要はなく、「SOLID」とは何かざっくりと感じてもらえれば嬉しいです。個人的には、変更に強くて、他人にとって読みやすく再利用性の高いソフトウェアを開発するためには、小さく必要なものだけを使って抽象度の高いモジュールを開発するべきだと解釈しました。


SSR : 単一責任の原則

「どのモジュールもたった1つのことだけを行うべき」という解釈は間違い。

SSRとは、「モジュールを変更する理由はたった1つであるべき」という原則。つまり、ソースコードを変更する理由が同じであれば、それらは1つとして扱う。

(参考)プログラマが知るべき97のこと - 単一責任原則


SRPに違反するクラスの具体例

給料計算のアルゴリズムが同じだからといって、開発者は重複を嫌い、営業部と企画部の給料計算のメソッドを1つに切り出しました。しかし、数ヶ月後、企画部の給料計算の方法が変更されたが、営業部と企画部の給料計算アルゴリズムが同じになったと気付かれないまま給料が支払われ、数億円もの損失が発生した。

つまり、メソッドのアクターが違うならば共通している部分があっても共通化してはならず、SSRに基づいて別ものとして考えることが、のちの仕様変更に対して強い設計といえる。


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

ちょっとした拡張のために大量に既存コードの置き換えが必要な設計は大失敗している。

既存の成果物を変更しないで拡張できるソフトウェア設計にすべきである。そのためには、コンポーネントの依存関係を階層構造にして、上位レベルのコンポーネントが下位レベルのコンポーネントの変更の影響を受けないようにするべきである。

つまり、コンポーネントの依存方向を単一方向にすべき。

(参考)オープン・クローズドの原則の重要性について


具体例

アプリケーションのビジネスルールを含むような最上位コンポーネントは、Database、Controller、View等に変更があっても関係がない作りにするべき。

「A → B → C」とコンポーネントが依存していたら、Cの変更は、AとBに影響することとなるためビジネスルールがCのコンポーネントになる。

Aの変更は、B、Cにとって関係がないような設計にするべき。


LSP : リスコフの置換原則

基底クラスから派生したクラスは、望ましくない挙動を一切伴わずに、常に基底クラスと置き換え可能でなければならない。SがTの派生型であるとすると、プログラム内における型Tのオブジェクトは、プログラム内の望ましいプロパティを一切変更することなく、型Sのオブジェクトに置き換え可能である。

実践的に書くと、派生クラスは基底クラスを継承するときに、常に基底クラスの挙動を一切変えないようにすべきであるということです。

Railsで学ぶSOLID(3)リスコフの置換原則(翻訳)

リスコフの置換原則とその違反を実例を踏まえて解説


ISP : インターフェイス分離の法則

必要としないモジュールに依存しない。ソースコードの依存関係においては、再コンパイルや再デプロイを強制されるので明らかに有害である。

(参考)インターフェイス分離の原則


具体例

複数のユーザーが同じクラスを使っていると考えて、UserAはA、UserBはB、UserCはCを使っているとした場合、UserAは使用しないB、Cにも依存していることになる。UserB、UserCも然り。それらの必要としない依存関係を防ぐために各操作をインターフェイスに分離するべき。


DIP: 依存関係逆転の法則

ソースコードの依存性が具象モジュールを参照してはいけない。

ただし、標準ライブラリは他のライブラリに比べて非常に安定しているし、変更されることはほとんどなくコントロールされているので、依存することは仕方がない。そのような理由から、DIPを考えるときはOSやプラットフォーム周りは気にしないことが多い。


  • 変化しやすい具象クラスを参照しない。その代わりに抽象インターフェイスを参照する。

  • 具象関数はオーバーライドしない。具象関数はソースコードの依存を要求する。そのために抽象関数へ変え、それらに依存するべき。

  • 変化する具象を名指しで参照してはならない。

Railsで学ぶSOLID(5)依存関係逆転の原則(翻訳)


さいごに

最後まで読んでいただき有難うございました。

SOLIDについて知るたびに自分が書いていたコードは、SOLIDを違反しまくっていたことに気付かされました。プログラミング言語を学んでいて、抽象クラスを書く意味がわかりませんでしたが、これを読んてやっと理解できました。

なんだか脱初心者へ一歩近づいた気がしました。

今後は、これらの原則を踏まえてソースコードへ落とし込んでみようと思います。またよろしくお願い致します。