単一責任の原則についての個人的なまとめ

はじめに

対象読者は初心者です。

個人的にいくつかの書籍を読んで、内容や自分の考えをまとめたものです。

単一責任の原則とは

Robert C.Martinの著書「アジャイルソフトウェア開発の奥義」では、

クラスを変更する理由が複数存在してはならない

と説明されていました。

一方で、比較的最近の彼の著書である「クリーンアーキテクチャ」では、

「モジュール[1]はたったひとつのアクター[2]に対して責務を負うべきである。」

とも説明されていました。

まとめると、「クラスを変更する理由は複数のアクター起因であってはならない」と言えると思います。

単一責任の話の具体例として自分が考えたものは、よくある管理画面、ユーザー画面に別れているものです。

作りとしては、見た目上分かれているが、アプリケーションとしては別れていない、モノリシックな構成です(たぶんRails採用しているところにありがち)。

単純に捉えて、管理画面側のアクターとして管理者がおり、ユーザー画面側のアクターとしてユーザーがいるとします。

商品の登録は管理者が行い、商品の予約をユーザーが行う場合に、下記のようなProductクラスがあった場合、単一責任の原則に違反しています。

このProductクラスは、ユーザーが商品を予約できる機能と、管理者が商品を登録できる機能を別々のクラスに分離する対応が必要です。

class Product  
  def register(name, price)  
     # 登録の処理  
  end  

  def reserve(user_id)  
    # 予約の処理  
  end  
end  

なぜ単一責任の原則を守るべきなのか

なぜ単一責任の原則を守るべきなのでしょうか?

先程の続きで考えてみます。

ある日、管理者側のメンバーが登録処理の実装の変更を依頼してきました。開発者は登録処理の変更を正しく行いリリースしました。ところがユーザー画面側で予約処理に不具合が出ているという報告を受けました。開発者は再度修正を入れ、管理画面側でもユーザー画面側でも影響がないことを確認した後リリースして事なきを得ました。

この話を聞いてどう思ったでしょうか?
開発者が最初のリリースで予約処理への影響を確認しなかったのが悪かったのでしょうか?

この話の問題点は、単一責任の原則を破ってしまったことです(テストコードをもっとしっかり書けばとか、例が適当すぎるのは一旦おいておきます)。

registerメソッドとreserveメソッドはそれぞれ別のアクター起因で変更が発生します。それにより、どちらかが変更されても別のアクターに対して影響を及ぼすような不具合が発生する可能性があります。
この話から見えてくる、単一責任の原則を守ることによる1つ目のメリットは、「変更の影響が他のアクターに及ばない」ことです。

「単一責任の原則」が存在しない世界のGodクラス(なんでもできるクラス)のような極端な話を考えると他のメリットも見えてきます。
単一責任の原則を守ることによる2つ目のメリットは、「見通しがよく理解しやすい」ことです。

具体的にどうすべきだったか?

今回の例に関しては、当然「単一責任の原則」を守るべきでした。
アプリケーション自体は別れていない状態になってしまっているので、自分なら一旦下記のような形で名前空間を切って実装を分離して対応します。

module User  
  class Product  
    def reserve(user_id)  
      # 予約の処理  
    end  
  end  
end  

module Admin  
  class Product  
    def register(name, price)  
     # 登録の処理  
    end  
  end  
end  

終わりに

今回はSOLIDのS(Single Responsibility Principle)である単一責任の原則についてまとめてみました。

たぶん単一責任の原則については、「クラスを変更する理由が複数存在してはならない」で知識が止まっており、具体的にどうすべきという部分が欠けている方も多いと思います(自分はそうでした)。

この記事が誰かの理解の助けになれば幸いです。

参考

  • アジャイルソフトウェア開発の奥義 Robet C.Martin
  • Clean Architecture Robert C.Martin

脚注

1: ここでのモジュールの定義は「いくつかの関数やデータをまとめた凝集性のあるもの」です。
2: ここでのアクターの定義は、「変更を望む人たちのグループ」です。