0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SOLID原則は全部適用しなくていい ― 「痛み駆動」で選ぶ実践的リファクタリング

0
Posted at

この記事で分かること

  • SOLID原則を「全部適用」するとなぜ逆効果になるのか
  • どの原則を、どんな場面で使うべきかの判断フローチャート
  • 5つの原則それぞれの「使いどき」と「見送りどき」
  • 実際のリファクタリングでS + Iだけを適用した実例

はじめに ― 全部適用して失敗した話

「コードが肥大化してきたので、SOLID原則に従ってリファクタリングしよう」

多くのエンジニアが一度は考えることです。しかし、ここに落とし穴があります。5つの原則を教科書通りにすべて適用した結果、コードがかえって複雑になってしまうというケースが少なくないのです。

ある中規模システムのリファクタリングで、クリーンアーキテクチャをフル適用しようとしたことがあります。ドメイン層・ユースケース層・インターフェース層・インフラ層を厳密に分けた結果、ファイル数が3〜4倍に膨れ上がり、もともと1ファイルに収まっていた見通しの悪さを解消するはずが、今度は 「どのファイルに何が書いてあるか分からない」 という別の見通しの悪さが生まれました。

これはSOLID原則に限らず、設計原則全般に言えることです。原則に従うこと自体が目的になってはいけません。

前提知識 ― SOLID原則30秒おさらい

SOLID原則とは、Robert C. Martinが2000年に提唱したオブジェクト指向設計の5つの原則です(頭字語はMichael Feathersの命名)。本の索引のように、「どこに何があるか」を整理するための指針と考えてください。

略称 原則名 一言でいうと
S 単一責任原則(SRP) 1つのクラス/ファイルには1つの責務だけ
O 開放閉鎖原則(OCP) 拡張に開き、修正に閉じる
L リスコフ置換原則(LSP) サブクラスは親クラスと差し替え可能に
I インターフェース分離原則(ISP) 使わないメソッドへの依存を避ける
D 依存性逆転原則(DIP) 具体ではなく抽象に依存する

本題 ― 原則は「痛み」で選ぶ

ここからがこの記事の核心です。

SOLID原則は5つすべてを一度に適用するものではありません。「今、コードのどこが痛いのか」 を起点に、その痛みを解消する最小の原則だけを選びます。

これは「SOLID不要論」ではありません。原則自体は正しいのです。ただし、痛みのないところに薬を塗っても効果はなく、副作用だけが残るということです。

以下のフローチャートで、あなたのコードに今必要な原則を判断できます。

痛みがないなら、適用しないという判断も正解です。

各原則の「使いどき」と「見送りどき」

S(単一責任原則)― ファイルが肥大化したとき

使いどき: 1つのファイルやクラスが複数の理由で変更される状況です。例えば、API定義・ビジネスロジック・データアクセスが1ファイルに混在していて、1,000行を超えている場合。

見送りどき: ファイルが200行以下で、責務が自然にまとまっている場合。無理に分割すると、関連する処理を追うためにファイルを行き来する羽目になります。

# Before: 1ファイルに全部入り
# app.py に API定義 + ビジネスロジック + データ永続化が混在

# After: 責務ごとに分割
# routes/users.py    - ユーザー関連API
# routes/orders.py   - 注文関連API
# routes/products.py - 商品関連API
# services/order_service.py - 注文のビジネスロジック

O(開放閉鎖原則)― if文が増殖するとき

使いどき: 新しいタイプを追加するたびに既存コードにif/switchを追加している場合。通知機能でSlack/Email/Webhookが増えるたびに分岐が増えるような状況です。

見送りどき: 分岐が2〜3個で安定しており、今後増える見込みがない場合。たとえば本番環境と開発環境の切り替えだけなら、Strategyパターンは過剰です。

L(リスコフ置換原則)― 継承が壊れたとき

使いどき: 親クラスを子クラスに差し替えると予期しない動作やエラーが発生する場合。典型例として、Arrayを継承したReadOnlyListpushメソッドが例外を投げるような状況があります。

見送りどき: そもそも継承をほとんど使っていない場合。最近のソフトウェア開発では「Composition over Inheritance(継承より合成)」が主流であり、継承を使わないなら意識する場面も少なくなります。

I(インターフェース分離原則)― 巨大クラスの一部しか使わないとき

使いどき: 巨大なインターフェースやクラスのうち、呼び出し側が一部の機能しか使っていない場合。DatabaseManagerがCRUD・バックアップ・マイグレーションを全部持っているなら、分離の候補です。

見送りどき: 1つのクラスの機能が凝集しており、利用側がほぼすべてのメソッドを使っている場合。無理に分割すると概念的に関連した操作が分断され、かえって理解しづらくなります。

D(依存性逆転原則)― テストが書けないとき

使いどき: テスト時にデータベースやAPIなどの外部依存を差し替えられない場合。DIを導入してモックを注入できるようにします。

見送りどき: 開発者が1人で、テストでのモック差し替えの必要性が低い場合。また、言語やフレームワークが柔軟なモック機構を持つ場合(例: Pythonのunittest.mock)は、DIコンテナまで導入しなくても十分テスタブルです。

実例 ― S + I だけで劇的改善

とある小規模システムのバックエンドを例に見てみましょう。

Before: 全部入りの状態

ファイル 行数 混在している責務
app.py 約1,200行 全APIエンドポイント + ビジネスロジック + バッチ処理
app.js 約2,000行 UI・API通信・状態管理・レンダリング
db.py 約600行 ユーザー・タスク・プロジェクト・通知・ログ管理

適用した原則と判断理由

  • S(単一責任) → ファイルが肥大化している → 採用
  • I(IF分離) → 巨大クラスに複数責務が混在 → 採用
  • O(開放閉鎖) → プラグイン的拡張の予定がない → 見送り
  • L(リスコフ置換) → 継承をほぼ使っていない → 見送り
  • D(依存性逆転) → 開発者1人でDIの恩恵が薄い → 見送り

After: S + I だけ適用した結果

routes/
  users.py      # ユーザーAPI
  tasks.py      # タスクAPI
  projects.py   # プロジェクトAPI
  reports.py    # レポートAPI

stores/
  user_store.py    # ユーザー管理
  task_store.py    # タスク管理
  project_store.py # プロジェクト管理

2つの原則を適用しただけで、各ファイルが200〜300行に収まり、「どこに何があるか」が一目で分かるようになりました。D/O/Lを無理に適用していたら、インターフェース定義・DIコンテナ・ファクトリーが追加され、ファイル数は今の3倍になっていたでしょう。

よくある落とし穴 ― 「おまじないプログラミング」に注意

教科書通りにフル適用するのは、実は経験が浅い段階でよく見られるパターンです。業界ではこれを 「Cargo Cult Programming(おまじないプログラミング)」 と呼ぶことがあります。リチャード・ファインマンの「Cargo Cult Science」に由来する言葉で、形式だけ真似て本質を理解していない状態を指します。

DHH(Ruby on Railsの作者)もSOLID原則への批判的な見解を示しています。特に「責任」や「変更理由」の定義が曖昧で、極端に適用すると凝集性(関連する処理がまとまっている状態)が失われると指摘しています。

大事なのはこの2つの問いです。

  1. 今、何が痛いのか?(例:ファイルが肥大化して見通しが悪い)
  2. その痛みを解消する最小の手段は何か?(例:責務ごとにファイルを分割する)

この2つに答えられれば、使う原則は自然に決まります。

まとめ

  • SOLID原則は5つ全部をセットで適用する必要はない
  • 痛みのないところに原則を適用しても、複雑さが増すだけ
  • 「今何が痛いか」→「その痛みに効く原則はどれか」の順で考える
  • 経験豊富なエンジニアほど、この「適材適所」を自然にやっている
  • 迷ったら、この記事のフローチャートに立ち返ってみてください

原則は道具です。道具箱から全部出して使うのではなく、今の作業に必要なものだけを選んで使う。それがプロのリファクタリングです。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?