mcpField
S
solid

solid

github.com/krzysztofsurdy開発2968 回インストール1 週間前に更新
リポジトリ

solid について

オブジェクト指向コードにおける SOLID の五原則を解説するソフトウェア設計スキルです。保守性や拡張性の問題を診断し、的を絞った設計変更を検討できます。

主な機能

  1. 01単一責任の原則に関する指針
  2. 02開放閉鎖の原則による拡張
  3. 03リスコフの置換原則の確認
  4. 04インターフェース分離の指針
  5. 05依存性逆転の原則に関する指針
  6. 06原則間の関係とよくある誤解

活用シーン

  1. 01責務が多すぎるクラスの診断
  2. 02既存動作を拡張する機能の設計
  3. 03継承関係とインターフェース境界の確認
  4. 04具体的な実装詳細への依存の削減

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/krzysztofsurdy/code-virtuoso --skill solid

インストール後、Claude Code で/solidを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
dip.md
isp.md
lsp.md
ocp.md
srp.md

詳細

SOLID 原則

システムの保守、テスト、拡張を容易にする、オブジェクト指向設計の5つの基本原則です。Robert C. Martin(Uncle Bob)がこれらの考え方を体系化し、Michael FeathersがSOLIDという頭字語を考案しました。

原則一覧

原則概要参照
S: 単一責任クラスが変更される理由は1つだけにするreference
O: オープン/クローズド拡張に対して開き、変更に対して閉じるreference
L: リスコフの置換サブタイプは基底型と置き換え可能でなければならないreference
I: インターフェース分離汎用インターフェースを1つ設けるより、用途に特化したインターフェースを複数設けるreference
D: 依存関係逆転具象ではなく抽象に依存するreference

SOLIDが重要な理由

SOLIDに従わないと、コードベースには次のような問題が徐々に生じます。

  • 硬直性:1つの変更が、無関係な多くのモジュールに波及します
  • 脆弱性:ある領域を変更すると、一見関係のない別の領域が壊れます
  • 再利用困難性:コンポーネントが密接に絡み合い、再利用のために切り出すのが現実的ではありません
  • 粘着性:設計に沿って正しく作業するより、設計を回避する場当たり的な対応のほうが簡単になります

SOLIDは、明確な境界、明示的な契約、拡張のための定義済みポイントによって、それぞれの問題に対処します。

簡易判断ガイド

症状違反している可能性がある原則対処法
クラスが多くのことを行っているSRP役割を絞ったクラスに分割する
機能の追加に既存クラスの編集が必要OCPポリモーフィズムまたはストラテジーを導入する
親クラスの代わりに使うとサブクラスが壊れるLSP継承階層を修正するか、コンポジションを使う
クラスが使わないメソッドの実装を強いられるISPインターフェースを小さく分割する
高水準モジュールが低水準の詳細をインポートしているDIP抽象化レイヤーを導入する

簡単な例

SRP:変更前と変更後
// BEFORE: Class handles both user data AND email sending
class UserService {
    public function createUser(string $name, string $email): void { /* ... */ }
    public function sendWelcomeEmail(string $email): void { /* ... */ }
}

// AFTER: Each class has one responsibility
class UserService {
    public function __construct(private UserNotifier $notifier) {}
    public function createUser(string $name, string $email): void {
        // persist user...
        $this->notifier->welcomeNewUser($email);
    }
}

class UserNotifier {
    public function welcomeNewUser(string $email): void { /* ... */ }
}
OCP:変更せずに拡張する
interface DiscountPolicy {
    public function calculate(float $total): float;
}

class PercentageDiscount implements DiscountPolicy {
    public function __construct(private float $rate) {}
    public function calculate(float $total): float {
        return $total * $this->rate;
    }
}

// Adding a new discount type requires NO changes to existing code
class FlatDiscount implements DiscountPolicy {
    public function __construct(private float $amount) {}
    public function calculate(float $total): float {
        return min($this->amount, $total);
    }
}
DIP:抽象に依存する
// High-level policy depends on abstraction, not on database details
interface OrderRepository {
    public function save(Order $order): void;
}

class PlaceOrderHandler {
    public function __construct(private OrderRepository $repository) {}
    public function handle(PlaceOrderCommand $cmd): void {
        $order = Order::create($cmd->items);
        $this->repository->save($order);
    }
}

原則間の関係

5つの原則は互いに補強し合います。

  • SRP + ISP:どちらも、クラスやインターフェースの責務を1つに絞ります
  • OCP + DIP:抽象化によって、変更せずに拡張できるようになります
  • LSP + OCP:ポリモーフィズムによる拡張が機能するのは、サブタイプを正しく置き換えられる場合に限られます
  • ISP + DIP:適切に分離されたインターフェースにより、必要な抽象にだけ依存しやすくなります

よくある誤解

  • 「クラスごとにメソッドは1つ」:SRPが意味するのは「変更する理由を1つにする」ことであり、メソッドを1つだけにすることではありません。同じ責務に関わるメソッドであれば、クラスに複数あってもかまいません。
  • 「既存コードは絶対に変更しない」:OCPはバグ修正を禁止するものではありません。「新しい振る舞い」を、既存の正常に動作するコードを変更せずに追加できるようにするという意味です。
  • 「常にインターフェースを使う」:DIPが求めるのは抽象への依存です。基底クラスが適切な抽象となる場合もあります。2つ目の実装が決して作られないクラスに、インターフェースを作る必要はありません。
  • 「継承は悪いもの」:LSPは継承を避けるよう求めるものではありません。サブタイプを置き換え可能な状態に保つために、継承を「正しく」行うルールを定めています。

ベストプラクティス

  • SOLIDは段階的に取り入れましょう。一度にすべてをリファクタリングしないでください
  • SOLIDを診断ツールとして使いましょう。コードの変更が難しいときは、どの原則に違反しているか確認してください
  • デザインパターンと組み合わせましょう。Strategy(OCP)、Adapter(DIP)、Decorator(OCP)は、SOLIDの考え方を直接実装したものです
  • まずテストを書きましょう。TDDはSOLIDに準拠した設計を促します
  • 言語の厳密な型付けや不変性の機能(readonlyまたはfinalフィールド、不変の値型、列挙型、sealed型)を使い、コンパイラーによって設計を強制しましょう

コメント