🐥

【SOLID原則】単一責任の原則 - SRP

2021/06/10に公開

SOLID原則とは、ソフトウェア設計の5つの原則の頭字語を取ったものです。ソフトウェアをより理解しやすく、より柔軟に、よりメンテナナンス性の高いものにするために考案されました。

  1. 単一責任の原則(Single Responsibility Principle)
  2. オープン・クローズドの原則(Open/closed principle)
  3. リスコフの置換原則(Liskov substitution principle)
  4. インターフェース分離の原則(Interface segregation principle)
  5. 依存性逆転の原則(Dependency inversion principle)

今回はSOLID原則のひとつ、単一責任の原則についてです。

単一責任の原則

個々のモジュール(関数やクラス)は、一つの責任だけを持つべきという原則です。責任は、そのシステムを使うアクター(ユーザやステークホルダー)に対して持ちます。

例えば、次のようなEmployeeクラスがあったとします。
これは単一責任の原則に違反しています。

class Employee {
    /** 経理部門が規定、報告先はCFO */
    const calculatePay = () => {}

    /** 人事部門が規定、報告先はCOO */
    const reporyHours = () => {}

    /** データベース管理者が規定、報告先はCTO */
    const save = () => {}
}

これは複数のアクターに対してのメソッドが存在している状態です。それぞれのメソッドをひとつのクラスに入れると、開発者はすべてのアクターを結合することになります。この結合が原因でCFOチームの何らかの操作が、COOチームの使うものに影響を及ぼしてしまうことがあります。

各メソッドで使われる共通メソッドがあった場合は、仕様の変更を入れる度に影響が出ます。その都度、アクターごとに条件分岐を入れたくなったりとコードが複雑になります。

また、部門ごとに開発チームが分かれていてる場合、同時に同じ箇所を変更していたらソースコードのコンフリクトが起こる可能性があります。

解決策

アクターの異なるコードは分割すべきです。
それぞれのメソッドを別のクラスに移動します。

class PayCalculator {
    const calculatePay = () => {}
}

class HourReporer {
    const reporyHours = () => {}
}

class EmployeeSaver {
    const saveEmployee = () => {}
}

これで3つのクラスはお互いに相手のことを知らない状態になりました。

単一責任の原則に従い、アクターに対する責務を一つにすることで、各モジュールは凝集度が高くなり、機能の修正や仕様変更に強い設計が出来るようになります。

ちなみに凝集度が高いとは、責務・データ・振る舞いの関連が強いということです。

参考

https://postd.cc/solid-principles-every-developer-should-know/

Discussion