solid-review
コードベースのSOLID原則違反を分析します。以下のトリガーで起動できます:「SOLID review」「architecture review」「check design」「find violations」。
description の原文を見る
Analyze codebase for SOLID principle violations. Triggers: 'SOLID review', 'architecture review', 'check design', 'find violations'.
SKILL.md 本文
SOLID レビュースキル
SOLID 原則違反を検出し、可能な限り自動修正を含めた実行可能なレポートを生成します。
自律動作モード
このスキルは以下の動作で 自律的に 動作します:
事前確認なしに自動的に適用:
| 問題 | 自動修正 |
|---|---|
具体的なコレクション型(ArrayList → List) | フィールド型を変更 |
| Public → package-private(内部クラス) | 可視性を削減 |
| サービス依存性のインターフェース不足 | インターフェースを抽出 |
| ロージェネリック型 | 型パラメータを追加 |
人間の判断に委ねる:
| 問題 | 理由 |
|---|---|
| 大規模クラスの分割が必要 | 複数の妥当なアプローチが存在 |
| 複雑な instanceof チェーン | Strategy パターン設計が必要 |
| Fat インターフェースの分割 | API 設計の決定が必要 |
引数
<path>- 分析対象ディレクトリ(デフォルト:src/main/java)--scope-file <path>- scope.json へのパス(premerge から)--changed- main 以降に変更されたファイルのみ--principle SRP|OCP|LSP|ISP|DIP- 1 つの原則に焦点を当てる
ステップ 0:スコープをロード
# Check if invoked from premerge (scope file exists)
if [[ -f .review-output/scope.json ]]; then
SCOPE=$(jq -r '.scope' .review-output/scope.json)
FILES=$(jq -r '.files[]' .review-output/scope.json | grep "\.java$")
echo "Using scope: $SCOPE ($(echo "$FILES" | wc -l) Java files)"
echo "$FILES" > /tmp/files.txt
elif [[ "$1" == "--changed" ]]; then
# Legacy --changed flag
MAIN=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@' || echo "main")
git diff --name-only $(git merge-base $MAIN HEAD) --name-only -- "*.java" > /tmp/files.txt
else
# Default: analyze src/main/java
find ${1:-src/main/java} -name "*.java" > /tmp/files.txt
fi
閾値
CLAUDE.md の ## SOLID Thresholds セクションから読み込むか、以下のデフォルト値を使用します:
| メトリクス | 中 | 高 |
|---|---|---|
| クラス当たりの行数 | 300 | 500 |
| public メソッド数 | 10 | 15 |
| 依存性(@Inject) | 5 | 8 |
| インターフェースメソッド | 7 | 10 |
| instanceof チェック | 2 | 4 |
原則と検出
S - 単一責任の原則
違反:クラスが複数の変更理由を持つ。
for f in $(cat /tmp/files.txt); do
lines=$(wc -l < "$f")
methods=$(grep -c "public.*(" "$f")
injects=$(grep -c "@Inject" "$f")
[[ $lines -gt 500 ]] && echo "HIGH: $f - $lines lines"
[[ $methods -gt 15 ]] && echo "HIGH: $f - $methods public methods"
[[ $injects -gt 8 ]] && echo "HIGH: $f - $injects dependencies"
done
修正方法:クラス抽出、モジュール抽出、ファサードパターン
O - オープン・クローズドの原則
違反:動作を追加するためにコードを修正する必要がある。
for f in $(cat /tmp/files.txt); do
instanceof=$(grep -c "instanceof" "$f")
switches=$(grep -c "switch\s*(" "$f")
elseif=$(grep -c "else if" "$f")
[[ $instanceof -gt 4 ]] && echo "HIGH: $f - $instanceof instanceof"
[[ $switches -gt 2 ]] && echo "MEDIUM: $f - $switches switches"
[[ $elseif -gt 4 ]] && echo "MEDIUM: $f - $elseif else-if chain"
done
修正方法:Strategy パターン、Factory パターン、プラグインアーキテクチャ
L - リスコフの置換原則
違反:サブクラスが親のコントラクトを破る。
for f in $(cat /tmp/files.txt); do
# Override that throws
grep -A5 "@Override" "$f" | grep -q "UnsupportedOperationException" && \
echo "HIGH: $f - Override throws UnsupportedOperationException"
# Override returns null
grep -A10 "@Override" "$f" | grep -q "return null" && \
echo "MEDIUM: $f - Override returns null"
done
修正方法:コンポジションの活用、インターフェース抽出
I - インターフェース分離の原則
違反:クライアントが使用しないメソッドに依存する。
for f in $(cat /tmp/files.txt); do
if grep -q "^public interface" "$f"; then
methods=$(grep -cE "^\s+\w+.*\(.*\);" "$f")
[[ $methods -gt 10 ]] && echo "HIGH: $f - $methods methods (fat interface)"
fi
# Empty implementations
if grep -q "implements" "$f"; then
empty=$(grep -cE "\{\s*\}" "$f")
[[ $empty -gt 0 ]] && echo "HIGH: $f - $empty empty method bodies"
fi
done
修正方法:インターフェース分割、Adapter パターン
D - 依存性逆転の原則
違反:具体的な実装に依存しており、抽象化に依存していない。
for f in $(cat /tmp/files.txt); do
# Direct instantiation
grep -n "new \w\+\(Service\|Repository\|Client\)\s*(" "$f" && \
echo "HIGH: $f - Direct instantiation"
# Concrete collections
grep -n "private\s\+\(ArrayList\|HashMap\)\s*<" "$f" && \
echo "MEDIUM: $f - Concrete collection type"
# Framework in core
if [[ "$f" == *"engine-core"* ]]; then
grep -n "import io\.quarkus\|import jakarta\." "$f" | grep -v validation && \
echo "HIGH: $f - Framework import in core"
fi
done
修正方法:依存性注入、インターフェース抽出
出力
solid-review.json を生成します:
{
"meta": { "path": "src/main/java", "filesAnalyzed": 50, "analyzedAt": "..." },
"summary": {
"SRP": { "high": 1, "medium": 2 },
"OCP": { "high": 0, "medium": 1 },
"LSP": { "high": 0, "medium": 0 },
"ISP": { "high": 1, "medium": 0 },
"DIP": { "high": 2, "medium": 3 }
},
"findings": [...],
"hotspots": [
{ "file": "UserService.java", "violations": ["SRP", "DIP"], "priority": 1 }
],
"grade": "C"
}
サマリーを表示
## SOLID レビュー
**ファイル**: 50 | **評価**: C
| 原則 | 高 | 中 |
|-----------|------|--------|
| 単一責任の原則 | 1 | 2 |
| オープン・クローズドの原則 | 0 | 1 |
| リスコフの置換原則 | 0 | 0 |
| インターフェース分離の原則 | 1 | 0 |
| 依存性逆転の原則 | 2 | 3 |
### ホットスポット(リファクタリング優先度)
1. **UserService.java** - SRP, DIP(3 件の発見)
2. **OrderProcessor.java** - OCP(2 件の発見)
### トップ修正項目
1. [DIP] PaymentService のインターフェースを抽出
2. [SRP] UserService を分割 → UserAuthService + UserProfileService
3. [OCP] OrderProcessor の型 switch を Strategy に置き換え
評価
| 評価 | 基準 |
|---|---|
| A | 高がなし、中が 5 以下 |
| B | 高がなし、中が 10 以下 |
| C | 高が 2 以下、中が 15 以下 |
| D | 高が 5 以下 |
| F | 高が 5 超 |
他のスキルとの連携
連携リクエストの送信
SOLID 違反がより広い影響を持つ場合:
| 発見事項 | 対象スキル | リクエスト |
|---|---|---|
| SRP 違反がセキュリティリスクを生み出す | security-review | 大規模クラスの詳細スキャン |
| リファクタリングからのアーキテクチャ変更 | write-docs | アーキテクチャドキュメントを更新 |
| 新しいインターフェースを抽出 | write-docs | 新しい API コントラクトを文書化 |
| リファクタリングコードのテスト欠落 | test-coverage | カバレッジを優先化 |
連携リクエストの受信
他のスキルがアーキテクチャの懸念事項をフラグする場合:
{
"collaborationNeeded": [
{
"skill": "solid-review",
"reason": "security-review でフラグされた複雑なクラス",
"files": ["PaymentProcessor.java"],
"analysis": "SRP 違反による攻撃面の拡大"
}
]
}
対応:複雑さを低減させるための具体的なリファクタリング推奨事項を提供します。
連携を含めた出力
{
"findings": [...],
"collaborationRequests": [
{
"targetSkill": "write-docs",
"reason": "アーキテクチャ変更 - UserAuthService を抽出",
"suggestedContent": {
"section": "architecture.md",
"change": "新しいサービス境界を文書化"
}
}
],
"fixesApplied": [
{
"file": "UserService.java",
"line": 15,
"change": "ArrayList → List(DIP 修正)",
"autoFixed": true
}
]
}
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- samanthaci
- ライセンス
- MIT
- 最終更新
- 2026/2/6
Source: https://github.com/samanthaci/stormstack / ライセンス: MIT