設計原則

一言で

コードの変更容易性・可読性・保守性を保つ基本原則。特定アーキテクチャに依存せず全プロジェクトで適用。

4つの基本原則

DRY Don't Repeat Yourself
同じロジックを複数箇所に書かない
KISS Keep It Simple
シンプルに書く。巧妙なコードより読めるコード
YAGNI You Aren't Gonna Need It
今必要ない機能を先回りして作らない
SoC Separation of Concerns
UI・ビジネスロジック・データを分離

SOLID 5原則

SRP Single Responsibility
1つのクラス・関数は1つの責務だけ
OCP Open/Closed
拡張には開き、修正には閉じる
LSP Liskov Substitution
子クラスは親クラスの代わりに使える
ISP Interface Segregation
太いインターフェースを細かく分ける
DIP Dependency Inversion
上位モジュールは下位モジュールに依存しない。インターフェースを間に挟む

いつ使うか

対象
全プロジェクト — 適用しない理由はない
コードレビューの判断基準として
⚠️過剰適用(3行のスクリプトにSOLIDを持ち込む等)

違反例 → 修正例(Python)

# ❌ 悪い例: 1関数・多重責務 + DRY違反
def process_order_send_email_update_stock(order):
    total = sum(item["price"] * item["qty"] for item in order["items"])
    import smtplib
    smtp = smtplib.SMTP("smtp.example.com")
    smtp.sendmail("shop@example.com", order["email"], f"合計: {total}円")
    for item in order["items"]:
        stock[item["id"]] -= item["qty"]

# ✅ 良い例: 責務を分離(SRP + DIP)
from typing import Protocol
class EmailSender(Protocol):
    def send(self, to: str, body: str) -> None: ...
class StockRepository(Protocol):
    def decrement(self, item_id: str, qty: int) -> None: ...

def calculate_total(items: list[OrderItem]) -> float:
    return sum(item.price * item.qty for item in items)

def process_order(items, email: EmailSender, stock: StockRepository):
    total = calculate_total(items)
    for item in items:
        stock.decrement(item.id, item.qty)

違反例 → 修正例(TypeScript)

// ❌ 悪い例: 新しい決済方法を追加するたびに書き換える(OCP違反)
function processPayment(method: string, amount: number) {
  if (method === "credit") { /* クレジットカード処理 */ }
  else if (method === "bank") { /* 銀行振込処理 */ }
  // 新しい方法を追加するにはここを変更 → OCP違反
}

// ✅ 良い例: 拡張には開き、修正には閉じる(OCP)
interface PaymentProcessor {
  process(amount: number): Promise;
}
class CreditCardProcessor implements PaymentProcessor { /* ... */ }
class BankTransferProcessor implements PaymentProcessor { /* ... */ }

class CheckoutService {
  constructor(private processor: PaymentProcessor) {}  // DIP
  async checkout(amount: number) {
    await this.processor.process(amount);
  }
}

組み合わせ

TDD — SRPを守るとテストが書きやすい クリーンアーキテクチャ — DIPが前提 DDD — SRP・ISPでドメインモデル設計 CI/CD — OCPを守るとCIが壊れにくい
CLAUDE.md用プロンプト:
## 設計原則
- DRY: 同じロジックを2箇所に書かない。共通関数・クラスに抽出
- KISS: 複雑な解決策よりシンプルな方を選ぶ
- YAGNI: 今必要ない機能を先回りして実装しない
- SRP: 1つの関数・クラスは1つの責務だけ持つ
- DIP: ビジネスロジックから外部API・DBを直接呼ばない(Protocol/Interfaceを挟む)
← 開発手法セレクタに戻る ← ガイド一覧に戻る