2019はじめに対象読者は初心者です。個人的にいくつかの書籍を読んで、内容や自分の考えをまとめたものです。C.Martinの著書「アジャイルソフトウェア開発の奥義」では、クラスを変更する理由が複数存在してはならないと説明されていました。「モジュール1はたったひとつのアクター2に対して責務を負うべきである。」とも説明されていました。まとめると、「クラスを変更する理由は複数のアクター起因であってはならない」と言えると思います。単一責任の話の具体例として自分が考えたものは、よくある管理画面、ユーザー画面に別れているものです。作りとしては、見た目上分かれているが、アプリケーションとしては別れていない、モノリシックな構成です(たぶんRails採用しているところにありがち)。単純に捉えて、管理画面側のアクターとして管理者がおり、ユーザー画面側のアクターとしてユーザーがいるとします。商品の登録は管理者が行い、商品の予約をユーザーが行う場合に、下記のようなProductクラスがあった場合、単一責任の原則に違反しています。このProductクラスは、ユーザーが商品を予約できる機能と、管理者が商品を登録できる機能を別々のクラスに分離する対応が必要です。endendなぜ単一責任の原則を守るべきなのかなぜ単一責任の原則を守るべきなのでしょうか?先程の続きで考えてみます。ある日、管理者側のメンバーが登録処理の実装の変更を依頼してきました。開発者は登録処理の変更を正しく行いリリースしました。ところがユーザー画面側で予約処理に不具合が出ているという報告を受けました。開発者は再度修正を入れ、管理画面側でもユーザー画面側でも影響がないことを確認した後リリースして事なきを得ました。この話を聞いてどう思ったでしょうか?開発者が最初のリリースで予約処理への影響を確認しなかったのが悪かったのでしょうか?この話の問題点は、単一責任の原則を破ってしまったことです(テストコードをもっとしっかり書けばとか、例が適当すぎるのは一旦おいておきます)。registerメソッドとreserveメソッドはそれぞれ別のアクター起因で変更が発生します。それにより、どちらかが変更されても別のアクターに対して影響を及ぼすような不具合が発生する可能性があります。この話から見えてくる、単一責任の原則を守ることによる1つ目のメリットは、「変更の影響が他のアクターに及ばない」ことです。「単一責任の原則」が存在しない世界のGodクラス(なんでもできるクラス)のような極端な話を考えると他のメリットも見えてきます。単一責任の原則を守ることによる2つ目のメリットは、「見通しがよく理解しやすい」ことです。具体的にどうすべきだったか?今回の例に関しては、当然「単一責任の原則」を守るべきでした。アプリケーション自体は別れていない状態になってしまっているので、自分なら一旦下記のような形で名前空間を切って実装を分離して対応します。Principle)である単一責任の原則についてまとめてみました。単一責任の原則については、「クラスを変更する理由が複数存在してはならない」で知識が止まっており、具体的にどうすべきという部分が欠けている方も多いと思います(自分はそうでした)。この記事が誰かの理解の助けになれば幸いです。Martinここでのモジュールの定義は「いくつかの関数やデータをまとめた凝集性のあるもの」です。↩︎ここでのアクターの定義は、「変更を望む人たちのグループ」です。2019結論Rubyでは、動的にクラスに生えているメソッドを書き換えられるため、テスタビリティを上げるためにDIを使わない。個人的にはストラテジーパターン使いたいときぐらいしか、DI使わないんじゃないかなーって思っている。Rubyでテスタビリティ向上のためにDIを使わない理由DIを使う理由は、結合度の低下、テスタビリティの向上が主な理由だと思います。一般的な言語の場合には、引数にインターフェースを指定して、インターフェースに依存するようにすることでテスト時にモックオブジェクトを注入できるようにすると思います。Rubyの場合には、動的にクラスに生えているメソッドを書き換えれるためテスタビリティを上げるためにDIをするのは意味がないです。Rubyでは、rspecを用いて下記のように書くだけでクラスのメソッドを書き換えることができます。これによりテスト実行時にはクラスのメソッドの内容が変わった状態でテストが実行されます。Rubyのこの柔軟性により、テストを容易にするためにDIを行うという行為は意味がなくなります。receive(:from_service_account_key).and_return(session)endRubyでDIを使う局面Rubyを使ってDIを使うとしたら、それはストラテジーパターンを使用したいときぐらいだろうと思ってます。最近言語周りで思っていること特定の言語には、特定の言語の流儀があるので、それに従おう。一般論とか、別の言語の流儀の知識だけで、考えずに突き進むのはやめよう。2019はじめに対象読者は初心者です。C.Martinの著書「アジャイルソフトウェア開発の奥義」では、ソフトウェアの構成要素(クラス、モジュール、関数など)は拡張に対して開いていて、修正に対して閉じていなければならないと説明されています。「拡張に対して開いている」とは、雑に言い換えると「機能追加がしやすい」です。「修正に対して閉じている」とは、雑に言い換えると「変更が他の場所に影響を及ぼさない」です。厳密ではないけどわかりやすいであろう言い方としては、「クラスや関数は機能追加しやすく、変更が他の場所に影響を及ぼさない作りになっているべき」です。例開放閉鎖原則の具体例として、自分が考えたものは、くじ引きです。一般くじとプレミアムくじというものがあり、それぞれが違う抽選ロジックを持っているとします。開放閉鎖原則に従って実装したくじ引きのコードは、下記のようになります(インターフェース(publicなメソッド)部分が重要なので細かい部分は除いています)。ProgrammingRailsRubySOLID原則TypeScriptデザインパターン不正行為を。