mcpField
C
code-quality-principles

code-quality-principles

github.com/athola開発343175 回インストール1 日前に更新
リポジトリ

code-quality-principles について

KISS、YAGNI、SOLIDの原則を、Python、Rust、TypeScriptの例とともに解説するコーディングスキルです。リファクタリングでの可読性と保守性の改善を支援します。

主な機能

  1. 01KISS、YAGNI、SOLIDの指針
  2. 02言語別のコード例
  3. 03コードレビュー用チェックリスト
  4. 04原則が衝突する場合の指針

活用シーン

  1. 01リファクタリングによる可読性と保守性の向上
  2. 02不要な複雑さがないかコードをレビュー
  3. 03簡潔さと抽象化のどちらを選ぶか検討

インストール

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

$npx skills add https://github.com/athola/claude-night-market --skill code-quality-principles

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

詳細

コード品質の原則

KISS、YAGNI、SOLID の原則に関するガイダンスと言語ごとの例です。

使用する場面

  • コードの可読性と保守性を高める
  • リファクタリングで SOLID、KISS、YAGNI の原則を適用する

使用しない場面

  • 使い捨てのスクリプトや一度限りのデータ移行
  • 可読性を犠牲にすることが正当化される、パフォーマンスが重要なコード

KISS(Keep It Simple, Stupid)

原則:不要な複雑さを避けます。巧妙な解決策より、分かりやすい解決策を優先します。

ガイドライン
優先するもの避けるもの
シンプルな条件分岐単純なチェックに複雑な正規表現を使う
明示的なコードマジックナンバー/文字列
標準的なパターン巧妙なショートカット
直接的な解決策抽象化しすぎたレイヤー
Python の例
# Bad: Overly clever one-liner
users = [u for u in (db.get(id) for id in ids) if u and u.active and not u.banned]

# Good: Clear and readable
users = []
for user_id in ids:
    user = db.get(user_id)
    if user and user.active and not user.banned:
        users.append(user)
Rust の例
// Bad: Unnecessary complexity
fn process(data: &[u8]) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
    data.iter()
        .map(|&b| b.checked_add(1).ok_or("overflow"))
        .collect::<Result<Vec<_>, _>>()
        .map_err(|e| e.into())
}

// Good: Simple and clear
fn process(data: &[u8]) -> Result<Vec<u8>, &'static str> {
    let mut result = Vec::with_capacity(data.len());
    for &byte in data {
        result.push(byte.checked_add(1).ok_or("overflow")?);
    }
    Ok(result)
}

YAGNI(You Aren't Gonna Need It)

原則:実際に必要になるまでは機能を実装しません。

ガイドライン
することしないこと
現在の問題を解決する仮定上の将来に備えて作り込む
3つ目のユースケースが現れたら追加する1つのユースケースのために抽象化を作る
デッドコードを削除する「念のため」のコードを残す
実用最小限の解決策時期尚早な最適化
Python の例
# Bad: Premature abstraction for one use case
class AbstractDataProcessor:
    def process(self, data): ...
    def validate(self, data): ...
    def transform(self, data): ...


class CSVProcessor(AbstractDataProcessor):
    def process(self, data):
        return self.transform(self.validate(data))


# Good: Simple function until more cases appear
def process_csv(data: list[str]) -> list[dict]:
    return [parse_row(row) for row in data if row.strip()]
TypeScript の例
// Bad: Over-engineered config system
interface ConfigProvider<T> {
  get<K extends keyof T>(key: K): T[K];
  set<K extends keyof T>(key: K, value: T[K]): void;
  watch<K extends keyof T>(key: K, callback: (v: T[K]) => void): void;
}

// Good: Simple config for current needs
const config = {
  apiUrl: process.env.API_URL || 'http://localhost:3000',
  timeout: 5000,
};

SOLID の原則

単一責任の原則

各モジュール/クラスには、変更する理由が1つだけあるべきです。

# Bad: Multiple responsibilities
class UserManager:
    def create_user(self, data): ...
    def send_welcome_email(self, user): ...  # Email responsibility
    def generate_report(self, users): ...  # Reporting responsibility


# Good: Separated responsibilities
class UserRepository:
    def create(self, data): ...


class EmailService:
    def send_welcome(self, user): ...


class UserReportGenerator:
    def generate(self, users): ...
開放/閉鎖の原則

拡張に対して開き、変更に対して閉じているべきです。

# Bad: Requires modification for new types
def calculate_area(shape):
    if shape.type == "circle":
        return 3.14 * shape.radius**2
    elif shape.type == "rectangle":
        return shape.width * shape.height
    # Must modify to add new shapes


# Good: Extensible without modification
from abc import ABC, abstractmethod


class Shape(ABC):
    @abstractmethod
    def area(self) -> float: ...


class Circle(Shape):
    def __init__(self, radius: float):
        self.radius = radius

    def area(self) -> float:
        return 3.14 * self.radius**2
リスコフの置換原則

サブタイプは、その基底型と置き換え可能でなければなりません。

# Bad: Violates LSP - Square changes Rectangle behavior
class Rectangle:
    def set_width(self, w):
        self.width = w

    def set_height(self, h):
        self.height = h


class Square(Rectangle):  # Breaks when used as Rectangle
    def set_width(self, w):
        self.width = self.height = w  # Unexpected side effect


# Good: Separate types with common interface
class Shape(ABC):
    @abstractmethod
    def area(self) -> float: ...


class Rectangle(Shape):
    def __init__(self, width: float, height: float): ...


class Square(Shape):
    def __init__(self, side: float): ...
インターフェース分離の原則

クライアントは、使用しないインターフェースに依存すべきではありません。

// Bad: Fat interface
interface Worker {
  work(): void;
  eat(): void;
  sleep(): void;
}

// Good: Segregated interfaces
interface Workable {
  work(): void;
}

interface Feedable {
  eat(): void;
}

// Clients only implement what they need
class Robot implements Workable {
  work(): void { /* ... */ }
}
依存関係逆転の原則

具象ではなく、抽象に依存します。

# Bad: Direct dependency on concrete class
class OrderService:
    def __init__(self):
        self.db = PostgresDatabase()  # Tight coupling


# Good: Depend on abstraction
from abc import ABC, abstractmethod


class Database(ABC):
    @abstractmethod
    def save(self, data): ...


class OrderService:
    def __init__(self, db: Database):
        self.db = db  # Injected abstraction

クイックリファレンス

原則問いかけること危険信号
KISS「もっとシンプルな方法はないか?」単純な問題に複雑な解決策を使っている
YAGNI「今これが必要か?」仮定上のユースケースに備えて作り込んでいる
SRP「変更する理由は何か?」クラスが複数の役割を担っている
OCP「変更せずに拡張できるか?」型ごとの switch 文
LSP「サブタイプで基底型を置き換えられるか?」オーバーライドしたメソッドに副作用がある
ISP「クライアントはすべてのメソッドを必要としているか?」空のメソッド実装
DIP「抽象に依存しているか?」ビジネスロジック内に new キーワードがある

原則が衝突する場合

  1. KISS と SOLID:小規模なプロジェクトでは KISS を優先します。複雑さが増すにつれて、SOLID のパターンを追加します。
  2. YAGNI と DIP:実装が2つ以上できるまでは、抽象化を追加しません。
  3. 可読性と DRY:誤った抽象化をするより、少し重複させることを優先します。

コードレビューへの統合

コードレビューでは、次の点を確認します。

  • 不要な複雑さがない(KISS)
  • 先走った機能がない(YAGNI)
  • 各クラスの責任が1つである(SRP)
  • 巨大なクラスがない(500行超)
  • 依存関係は生成するのではなく、注入されている(DIP)

検証: 行数を確認するには wc -l <file> を実行し、ファイルごとのクラス数を数えるには rg -c "class " <file>(または grep -c "class " <file>)を実行します。

関連スキル

  • imbue:karpathy-principles - 「シンプルさ優先」の原則は、Karpathy が観察した LLM によるコーディングの落とし穴から導かれた4原則の統合として、KISS、YAGNI、SOLID をまとめています
  • ゲートとスキルの連携グラフ全体については、docs/quality-gates.md#skill-level-quality-gate-composition を参照してください

終了条件

  • 提案されたコード変更はすべて、統合レビューのチェックリストに照らして確認されています。不要な複雑さがない(KISS)、推測に基づく機能がない(YAGNI)、各クラスが単一の責任を持つ(SRP)、500行を超えるゴッドクラスがない、依存関係は生成せず注入する(DIP)
  • KISS と SOLID が競合する場合、解決方法が文書化されています。小規模なプロジェクトでは KISS を優先し、複雑さが増すにつれて SOLID のパターンを適用します。選択は明示されており、暗黙ではありません
  • 変更したファイルに対して wc -l <file> を実行し、ファイルが 500 行を超える場合(ゴッドクラスのしきい値)は結果を記録しています
  • テスト用のモック境界として機能する場合を除き、実装が 1 つしかない新しい抽象化は導入されていません

コメント