Open3

設計力を上げるための習慣づくり

https://tech.quartetcom.co.jp/2017/10/30/building-up-basic-skills-of-program-design/
  • 設計力を伸ばすために

    • 物事を、何らかの観点で分類・整理する力
    • 論理的に筋道を整えて主張を述べる力(論証力)
    • とりうる立場を複数検討し、それぞれの立場から見る力(批判的思考力)
  • 名前付けの理由を説明するトレーニング

    • すべての要素に対して、なぜそれを選んだのかという理由を求める
    • クラスやメソッドについては、他の候補がなかったか、他の候補と比較して良いと考える理由も求める
  • 仕様変更対応トレーニング

    • 入力値の与えられ方の別仕様
    • 結果の表示の仕方の別仕様
    • 問題の解き方における別ルール
    • 大きなデータ量への対応

https://speakerdeck.com/hidenorigoto/solidfalseyuan-ze-tutedonnahuunishi-ufalse
  • 設計
    • どのように処理を分けるか
      • Entity(データ)
      • DTO
      • Form(フォームから送られるデータをまとめたクラス)
      • DAO
      • Repository(データ操作)
      • Resolver(どのバリエーションを利用するかを解決)
      • Controller
        • シンプルに__invokeメソッドのみが基本
        • 多くともデフォルトのCRUDアクションのみ
      • Presenter(表示処理)
    • 批判的な思考
      • ○○という仕様追加があった場合に修正が容易になっているか
      • 検討すべき根拠がある部分のみ
    • オープンクローズドの原則
      • 既存のコードを修正せずに新しいコードを追加するだけで目的を達成できる状態になっていること
      • 着眼点
        • バリエーションからコードを保護する
        • バリエーションによって変化する部分はどこか
        • バリエーションの軸に沿ってまとめられているか
    • 単一責任の原則
      • 1つのクラスに1つの役割(機能)
      • クラスを変更する理由が2つ以上存在してはならない
      • 誤ったDRY適用による密結合を避ける
        • DRY原則とは
          • 1つの知識(コンセプト、概念)は、システム内で1箇所で明確に表現されないといけない
          • コードの重複があってもDRY原則違反でない(可能性は高いが)
            • 過度な共通化により分かりづらい命名になっている場合、明確な表現でないため×
            • 同じ概念であれば共通化してよい(同じ理由で1つを修正するともうひとつも修正することになるか)
          • http://blog.a-way-out.net/blog/2021/01/13/what-dry-principle-is/
    • リスコフの置換原則
      • 子クラスが親クラスと同じ動作を実行できない場合、バグになる可能性がある
      • 子クラスは、親クラスと同じリクエストを処理し、同じ結果か、同様の結果を提供できなければならない
      • 継承のダメな使い方
        • メソッド共有のための継承
          • 様々な派生クラスでの使い方に対応するために、共通メソッドに引数が追加されていく
          • 共通メソッドが別の共通メソッドを呼び出す
          • 共通メソッドがどんどん増えていく
        • メンバ変数の共有のための継承
        • 機能追加・機能変更のための継承
      • 継承の良い使い方
        • Template Method パターン では、子クラスは親クラスで指定されたメソッドを実装するだけなので安全→abstractを使う場合、abstractメソッド以外もメソッドを作れてしまうので共通化の罠にハマる可能性があるので辞めた方がよさそう
        • Strategy パターン や高階関数
      • 以下の条件を満たすとリスコフの置換原則を満たす

継承

継承を利用するケースは、大枠の処理は同じだが細部のバリエーションが異なる場合で
同じ処理を「共通化」させたくて利用することが多いと思われます。
(親クラスに処理が入る場合をイメージしています。abstractをinterfaceとして利用するケースもあると思いますが、それならinterfaceを利用するのが良いと思うので考慮から外します)

この「共通化」を行う場合には下記のようなデメリットがあり拡張に向かない性質があります。

下記に当てはまる場合は継承を利用することは問題ないと思いますが
実際そう言い切れることはなかなかないと思うので
「継承は禁止」というのは過激にしても慎重に利用する必要があるとは思います。

  • 親クラスが独立している
    • 子クラスに影響して親クラスに変更が入ることがないことが確実
    • ex.ライブラリを継承して利用する等
  • 使い捨て(拡張しない)のコード(小規模な場合)

継承のデメリット

継承のデメリットとしては

  • 親クラスを意識しないといけない
    • 親クラスのメソッドを子クラスでオーバーライドしたとき、出力結果が親クラスと同程度、または厳しくなっているかを意識する必要がある(親クラスより緩くなっていると利用側で不具合が起きる可能性がある為):リスコフの置換原則
  • 拡張に向かない
    • 子クラスに対応させるために親クラスの引数・条件分岐が増えてしまう(複雑化)
    • 複数の子クラスが出来てしまうと親クラスを修正したときの影響範囲が見えづらい(複雑化)

継承の代替

バリエーション部分を別クラスとして切り出し利用する

ログインするとコメントできます