何回かに分けてSOLID原則についてまとめていきます。今回はその第1回としてSOLID原則のS、単一責任の原則についてまとめます。なお、似た内容を述べらた閉鎖性共通の原則についても触れ、共通のポイントについてまとめます。
SOLID原則
- S:単一責任の原則(SRP:Single Responsibility Principle)
- O:オープン・クローズドの原則(OCP:Open-Closed Principle)
- L:リスコフの置換原則(LSP:Liskov Substitution Principle)
- I:インターフェース分離の原則(ISP:Interface Segregation Principle)
- D:依存関係逆転の原則(DIP:Dependency Inversion Principle)
単一責任の原則とは
「モジュールはたった一つのアクターに対して責務を負うべきである」
この原則での各用語は下記の意味です。
- モジュール=関数やデータの集まり
- アクター=変更や改善を要望してくるステークホルダーやユーザー
すごくざっくり言い換えると、機能の変更責任者は機能ごとに1人ずつにしておくべきだという原則ですね。
閉鎖性共通の原則
同じ理由、同じタイミングで変更されるクラスをコンポーネントにまとめること。変更の理由やタイミングが異なるクラスは、別のコンポーネントに分けること。
こちらは単一責任の原則をコンポーネントを対象として言い換えた原則です。コンポーネントとモジュールの違いについての説明は割愛しますが、どちらもソフトウェアの部品を指しています。
2つの原則の共通点
これらの原則の共通点は同じタイミング、同じ理由で変更するものはひとまとめにすることと述べている点にあります。
なぜこのようなことが重要なのか、1つの例を使ってその重要性について考えてみます。
例:原則に反して1つ機能に対してアクターが複数いたらどうなるか
原則に反する構成とした場合の懸念として変更の衝突が考えられます。例えば、下の図のような3つの関数で構成される機能があったとします。
構成
Function Cは”Date”の情報を出力する関数であり、Function A,Bは自関数内の処理でDateを利用するために、Function Cに依存しています。
アクターと機能の関係
Function AとBは変更を要求するアクターが個別にいますが、Function Cに対してはFunction AとBのアクターが要求を出すことになります。
この例では、Function Cが原則に反している状態です。
どんな問題がおこるか?
ある時、AのアクターがFunction Aの出力結果を変えたいという要求を出したとします。変更にはFunction Cの出力するDateを変更する必要があると検討の結果わかりました。しかしこの時、Function BがCを利用していることに気が付かないまま、Function Cを変更してしまいました。すると、Function Bの出力結果は期待と異なってしまう、いわゆるバグになってしまいました。
補足
Cの変更をかける際に、BもCに依存していることに気が付かなかったことがバグの原因だとする考え方もあると思います。しかしこの原則では、ソフトウェアの構造によってそういった機会を未然に防ぐことができることを述べたものであり、人間はミスをするということを前提に考えれば「気が付かなかったのが悪い」というのは根本的な原因を指し示す言葉として適切ではないでしょう。
まとめ
単一責任の原則と閉鎖性共通の原則の2つを取り上げ、各原則が述べる共通のメッセージについて例を用いてまとめてみました。
上記の例以外にも、単一責任の原則に反するユースケースは考えられます。
皆さんの開発するソフトウェアをこの原則に照らし合わせてみると、意外なほころびにいち早く気が付くことができるかもしれませんね。
参考書籍
Clean Architecture(著:Robert C.Martin,2018)
コメント