component-flattening-analysis について
component-flattening-analysisは、コードベースのコンポーネント階層を分析し、特にルート名前空間の孤立クラスを見つけるスキルです。名前空間を可視化し、フラット化のリファクタリングを提案・実行して、参照とテストを確認します。
主な機能
- 01名前空間とコンポーネント階層のマッピング
- 02ルート名前空間の孤立クラス検出
- 03統合・分割・共有コード戦略の比較
- 04リファクタリング手順と工数の見積もり
- 05参照の更新と変更の検証
活用シーン
- 01コードベースの階層違反の監査
- 02拡張されたルート名前空間内のソースファイル特定
- 03コンポーネントの統合または分割の計画
- 04名前空間のリファクタリングと依存参照の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ tech-leads-club/ agent-skills --skill component-flattening-analysisインストール後、Claude Code で/component-flattening-analysisを入力して読み込まれたか確認します。
同梱ファイルQUICK-REFERENCE.mdREADME.md
詳細
コンポーネントのフラット化分析
このスキルは、コンポーネント階層の問題を特定し、ディレクトリ/名前空間構造においてコンポーネントがリーフノードとしてのみ存在するようにするとともに、ルート名前空間から孤立したクラスを取り除きます。
使用方法
クイックスタート
コードベースの分析を依頼します。
- 「ルート名前空間内の孤立したクラスを見つけて」
- 「コンポーネント階層をフラット化して」
- 「フラット化が必要なコンポーネントを特定して」
- 「階層の問題がないかコンポーネント構造を分析して」
使用例
例 1:孤立したクラスを見つける
User: "Find orphaned classes in root namespaces"
The skill will:
1. Scan component namespaces for hierarchy issues
2. Identify orphaned classes in root namespaces
3. Detect components built on top of other components
4. Suggest flattening strategies
5. Create refactoring plan
例 2:コンポーネントをフラット化する
User: "Flatten component hierarchies in this codebase"
The skill will:
1. Identify components with hierarchy issues
2. Analyze orphaned classes
3. Suggest consolidation or splitting strategies
4. Create refactoring plan
5. Estimate effort
例 3:コンポーネント構造を分析する
User: "Analyze component structure for hierarchy issues"
The skill will:
1. Map component namespace structure
2. Identify root namespaces with code
3. Find components built on components
4. Flag hierarchy violations
5. Provide recommendations
手順
- 構造をスキャンする:コンポーネントの名前空間階層をマッピングします
- 問題を特定する:孤立したクラスとコンポーネントのネストを見つけます
- 選択肢を分析する:フラット化の方針(統合または分割)を決定します
- 計画を作成する:手順を含むリファクタリング計画を生成します
- 実行する:コンポーネントをリファクタリングして階層をなくします
使用する場面
次のような場合にこのスキルを適用します。
- 共通のドメインコンポーネントを集約した後(パターン 2)
- コンポーネントの依存関係を決定する前(パターン 4)
- コンポーネントにネストされた構造がある場合
- ルート名前空間内の孤立したクラスを探す場合
- ドメインのグループ化に備える場合
- コンポーネント構造を整理する場合
- コンポーネントがリーフノードのみになるようにする場合
主な概念
コンポーネントの定義
コンポーネントは、ディレクトリ/名前空間構造のリーフノードによって識別されます。
- リーフノード:ソースファイルを含む最も深いディレクトリ
- コンポーネント:リーフノードの名前空間にあるソースコードファイル
- サブドメイン:拡張された親名前空間
重要なルール:コンポーネントはリーフノードとしてのみ存在します。名前空間が拡張された場合、親はコンポーネントではなくサブドメインになります。
ルート名前空間
ルート名前空間とは、拡張された名前空間ノードです。
- 拡張:その下に別の名前空間ノードが追加されている状態
- 例:
ss.surveyがss.survey.templatesに拡張されている - 結果:
ss.surveyはルート名前空間(サブドメイン)になります
孤立したクラス
孤立したクラスとは、ルート名前空間内にあるソースファイルです。
- 場所:ルート名前空間(リーフノードではないノード)
- 問題:関連付け可能なコンポーネントがありません
- 解決策:リーフノードの名前空間(コンポーネント)に移動します
例:
ss.survey/ ← Root namespace (extended by .templates)
├── Survey.js ← Orphaned class (in root namespace)
└── templates/ ← Component (leaf node)
└── Template.js
フラット化の方針
方針 1:下位を統合する
- リーフノードからルート名前空間にコードを移動します
- ルート名前空間がコンポーネントになります
- 例:
ss.survey.templates→ss.surveyに移動します
方針 2:上位を分割する
- ルート名前空間から新しいリーフノードにコードを移動します
- ルート名前空間から新しいコンポーネントを作成します
- 例:
ss.surveyをss.survey.create+ss.survey.processに分割します
方針 3:共有コードを移動する
- 共有コードを専用のコンポーネントに移動します
.sharedコンポーネントを作成します- 例:
ss.surveyの共有コードをss.survey.sharedに移動します
分析プロセス
フェーズ 1:コンポーネント構造をマッピングする
ディレクトリ/名前空間構造をスキャンし、階層を特定します。
-
名前空間ツリーをマッピングする
- すべての名前空間のツリーを構築します
- 親子関係を特定します
- リーフノード(コンポーネント)に印を付けます
-
ルート名前空間を特定する
- 拡張された名前空間を見つけます
- ルート名前空間(サブドメイン)として印を付けます
- それらを拡張している名前空間を記録します
-
ソースファイルの場所を特定する
- 各名前空間にあるすべてのソースファイルを見つけます
- ファイルを名前空間の場所に対応付けます
- ルート名前空間内のファイルを特定します
構造マッピングの例:
## Component Structure Map
ss.survey/ ← ルート名前空間(拡張済み) ├── Survey.js ← 孤立したクラス ├── SurveyProcessor.js ← 孤立したクラス └── templates/ ← コンポーネント(リーフノード) ├── EmailTemplate.js └── SMSTemplate.js
ss.ticket/ ← ルート名前空間(拡張済み) ├── Ticket.js ← 孤立したクラス ├── assign/ ← コンポーネント(リーフノード) │ └── TicketAssign.js └── route/ ← コンポーネント(リーフノード) └── TicketRoute.js
フェーズ 2:孤立したクラスを特定する
ルート名前空間にあるソースファイルを見つけます。
-
ルート名前空間をスキャンする
- 各ルート名前空間にソースファイルがあるか確認します
- 孤立したファイルを特定します
- ルート名前空間ごとに孤立したファイル数を数えます
-
孤立したクラスを分類する
- 共有コード:共通ユーティリティ、インターフェース、抽象クラス
- ドメインコード:コンポーネントに含めるべきビジネスロジック
- 混在:共有コードとドメインコードの組み合わせ
-
影響を評価する
- 孤立したファイルはいくつありますか?
- どのような機能が含まれていますか?
- どのコンポーネントがそれらに依存していますか?
孤立したクラスの検出例:
## Orphaned Classes Found
### Root Namespace: ss.survey
**Orphaned Files** (5 files):
- Survey.js (domain code - survey creation)
- SurveyProcessor.js (domain code - survey processing)
- SurveyValidator.js (shared code - validation)
- SurveyFormatter.js (shared code - formatting)
- SurveyConstants.js (shared code - constants)
**Classification**:
- Domain Code: 2 files (should be in components)
- Shared Code: 3 files (should be in .shared component)
**Dependencies**: Used by ss.survey.templates component
フェーズ 3:フラット化の選択肢を分析する
各ルート名前空間に最適なフラット化戦略を決定します。
-
選択肢 1:下位を統合する
- リーフノードのコードをルート名前空間に移動します
- ルート名前空間がコンポーネントになります
- 使用する場合:リーフノードが小さく、関連する機能である場合
-
選択肢 2:分割する
- ルート名前空間のコードを新しいリーフノードに移動します
- ルートから複数のコンポーネントを作成します
- 使用する場合:ルート名前空間に個別の機能領域がある場合
-
選択肢 3:共有コードを移動する
- 共有コードを
.sharedコンポーネントに抽出します - ドメインコードはルートに残すか、分割します
- 使用する場合:ルート名前空間に共有ユーティリティがある場合
- 共有コードを
フラット化分析の例:
## Flattening Options Analysis
### Root Namespace: ss.survey
**Current State**:
- Root namespace: 5 orphaned files
- Leaf component: ss.survey.templates (7 files)
**Option 1: Consolidate Down** ✅ Recommended
- Move templates code into ss.survey
- Result: Single component ss.survey
- Effort: Low (7 files to move)
- Rationale: Templates are small, related to survey functionality
**Option 2: Split Up**
- Create ss.survey.create (2 files)
- Create ss.survey.process (1 file)
- Create ss.survey.shared (3 files)
- Keep ss.survey.templates (7 files)
- Effort: High (multiple components to create)
- Rationale: More granular, but may be over-engineering
**Option 3: Move Shared Code**
- Create ss.survey.shared (3 shared files)
- Keep domain code in root (2 files)
- Keep ss.survey.templates (7 files)
- Effort: Medium
- Rationale: Separates shared from domain, but still has hierarchy
フェーズ 4:フラット化計画を作成する
各ルート名前空間のリファクタリング計画を作成します。
-
戦略を選択する
- 最適なフラット化の選択肢を選びます
- 作業量、複雑さ、保守性を考慮します
-
リファクタリング手順を計画する
- 移動するファイルを列挙します
- 移動先の名前空間を特定します
- 更新が必要な依存関係を記録します
-
作業量を見積もる
- リファクタリングにかかる時間
- リスク評価
- テスト要件
フラット化計画の例:
## Flattening Plan
### Priority: High
**Root Namespace: ss.survey**
**Strategy**: Consolidate Down
**Steps**:
1. Move files from ss.survey.templates/ to ss.survey/
- EmailTemplate.js
- SMSTemplate.js
- [5 more files]
2. Update imports in dependent components
- Update references from ss.survey.templates._ to ss.survey._
3. Remove ss.survey.templates/ directory
4. Update namespace declarations
- Change namespace from ss.survey.templates to ss.survey
5. Run tests to verify changes
**Effort**: 2-3 days
**Risk**: Low (templates are self-contained)
**Dependencies**: None
フェーズ 5:フラット化を実行する
リファクタリングを実施します。
-
ファイルを移動する
- ソースファイルを移動先の名前空間に移動します
- ファイルパスとインポートを更新します
-
参照を更新する
- 依存するコンポーネント内のインポートを更新します
- 名前空間の宣言を更新します
- ディレクトリー構造を更新します
-
変更を検証する
- テストを実行します
- 壊れた参照がないか確認します
- コンポーネント構造を検証します
出力形式
孤立したクラスのレポート
## Orphaned Classes Analysis
### Root Namespace: ss.survey
**Status**: ⚠️ Has Orphaned Classes
**Orphaned Files** (5 files):
- Survey.js (domain code)
- SurveyProcessor.js (domain code)
- SurveyValidator.js (shared code)
- SurveyFormatter.js (shared code)
- SurveyConstants.js (shared code)
**Leaf Components**:
- ss.survey.templates (7 files)
**Issue**: Root namespace contains code but is extended by leaf component
**Recommendation**: Consolidate templates into root namespace
コンポーネント階層の問題
## Component Hierarchy Issues
| Root Namespace | Orphaned Files | Leaf Components | Issue | Recommendation |
| -------------- | -------------- | ------------------------------- | -------------------- | ---------------- |
| ss.survey | 5 | 1 (templates) | Has orphaned classes | Consolidate down |
| ss.ticket | 45 | 2 (assign, route) | Large orphaned code | Split up |
| ss.reporting | 0 | 3 (tickets, experts, financial) | No issue | ✅ OK |
フラット化計画
## Flattening Plan
### Priority: High
**ss.survey** → Consolidate Down
- Move 7 files from templates to root
- Effort: 2-3 days
- Risk: Low
### Priority: Medium
**ss.ticket** → Split Up
- Create ss.ticket.maintenance (30 files)
- Create ss.ticket.completion (10 files)
- Create ss.ticket.shared (5 files)
- Effort: 1 week
- Risk: Medium
分析チェックリスト
構造のマッピング:
- すべての名前空間階層をマッピングしました
- ルート名前空間を特定しました
- すべてのソースファイルを見つけました
- リーフノード(コンポーネント)に印を付けました
孤立したクラスの検出:
- ルート名前空間をスキャンしてソースファイルを確認しました
- 孤立したクラスを特定しました
- 孤立したクラスを分類しました(共有/ドメイン/混在)
- 影響と依存関係を評価しました
フラット化分析:
- 統合の選択肢を分析しました
- 分割の選択肢を分析しました
- 共有コードの抽出の選択肢を分析しました
- 各ルート名前空間に最適な戦略を選択しました
計画の作成:
- フラット化戦略を選択しました
- リファクタリング手順を作成しました
- 作業量とリスクを見積もりました
- 作業に優先順位を付けました
実行:
- ファイルを移動先の名前空間に移動しました
- インポートと参照を更新しました
- 名前空間の宣言を更新しました
- テストで変更を検証しました
実装に関する注意事項
Node.js/Express アプリケーションの場合
コンポーネントは通常 services/ ディレクトリーにあります。
services/
├── survey/ ← Root namespace (extended)
│ ├── Survey.js ← Orphaned class
│ └── templates/ ← Component (leaf node)
│ └── Template.js
フラット化:
- 統合:
templates/のファイルをsurvey/に移動します - 分割:
survey/create/とsurvey/process/を作成します - 共有:ユーティリティ用に
survey/shared/を作成します
Java アプリケーションの場合
コンポーネントはパッケージ構造で特定します。
com.company.survey ← Root package (extended)
├── Survey.java ← Orphaned class
└── templates/ ← Component (leaf package)
└── Template.java
フラット化:
- 統合:
templatesクラスをsurveyパッケージに移動します - 分割:
survey.createとsurvey.processパッケージを作成します - 共有:
survey.sharedパッケージを作成します
検出戦略
コードを含むルート名前空間を見つける:
// Find root namespaces containing source files
function findRootNamespacesWithCode(namespaces, sourceFiles) {
const rootNamespaces = namespaces.filter((ns) => {
// Check if namespace has been extended
const hasChildren = namespaces.some((n) => n.startsWith(ns + '.') || n.startsWith(ns + '/'))
// Check if namespace contains source files
const hasFiles = sourceFiles.some((f) => f.namespace === ns)
return hasChildren && hasFiles
})
return rootNamespaces
}
孤立したクラスを見つける:
// Find orphaned classes in root namespaces
function findOrphanedClasses(rootNamespaces, sourceFiles) {
const orphaned = []
rootNamespaces.forEach((rootNs) => {
const files = sourceFiles.filter((f) => f.namespace === rootNs)
orphaned.push({
rootNamespace: rootNs,
files: files,
count: files.length,
})
})
return orphaned
}
フィットネス関数
コンポーネントをフラット化した後、自動チェックを作成します。
ルート名前空間にソースコードを置かない
// Alert if source code exists in root namespace
function checkRootNamespaceCode(namespaces, sourceFiles) {
const violations = []
namespaces.forEach((ns) => {
// Check if namespace has been extended
const hasChildren = namespaces.some((n) => n.startsWith(ns + '.') || n.startsWith(ns + '/'))
if (hasChildren) {
// Check if namespace contains source files
const files = sourceFiles.filter((f) => f.namespace === ns)
if (files.length > 0) {
violations.push({
namespace: ns,
files: files.map((f) => f.name),
issue: 'Root namespace contains source files (orphaned classes)',
})
}
}
})
return violations
}
コンポーネントは末端ノードにのみ配置する
// Ensure components exist only as leaf nodes
function validateComponentStructure(namespaces, sourceFiles) {
const violations = []
// Find all leaf nodes (components)
const leafNodes = namespaces.filter((ns) => {
return !namespaces.some((n) => n.startsWith(ns + '.') || n.startsWith(ns + '/'))
})
// Check that all source files are in leaf nodes
sourceFiles.forEach((file) => {
if (!leafNodes.includes(file.namespace)) {
violations.push({
file: file.name,
namespace: file.namespace,
issue: 'Source file not in leaf node (component)',
})
}
})
return violations
}
ベストプラクティス
推奨事項 ✅
- コンポーネントが末端ノードにのみ存在するようにします
- ルート名前空間から孤立したクラスを削除します
- 機能に基づいてフラット化の方法を選択します
- 機能に関連性がある場合は統合します
- 機能が異なる場合は分割します
- 共通コードを
.sharedコンポーネントに抽出します - フラット化後、すべての参照を更新します
- テストで変更を検証します
禁止事項 ❌
- ルート名前空間に孤立したクラスを残さないでください
- ほかのコンポーネントの上にコンポーネントを作成しないでください
- ファイルの移動後にインポートの更新を省略しないでください
- 影響を分析せずにフラット化しないでください
- フラット化の方法に一貫性を欠かせないでください
- フラット化の際に共通コードを無視しないでください
- リファクタリング後のテストを省略しないでください
よくあるパターン
パターン 1:単純な統合
変更前:
ss.survey/
├── Survey.js ← Orphaned
└── templates/ ← Component
└── Template.js
変更後:
ss.survey/ ← Component (leaf node)
├── Survey.js
└── Template.js
パターン 2:機能別の分割
変更前:
ss.ticket/ ← Root namespace
├── Ticket.js ← Orphaned (45 files)
├── assign/ ← Component
└── route/ ← Component
変更後:
ss.ticket/ ← Subdomain
├── maintenance/ ← Component
│ └── Ticket.js
├── completion/ ← Component
│ └── TicketCompletion.js
├── assign/ ← Component
└── route/ ← Component
パターン 3:共通コードの抽出
変更前:
ss.survey/ ← Root namespace
├── Survey.js ← Domain code
├── SurveyValidator.js ← Shared code
└── templates/ ← Component
変更後:
ss.survey/ ← Component
├── Survey.js
└── shared/ ← Component
└── SurveyValidator.js
次のステップ
コンポーネントをフラット化した後:
- コンポーネントの依存関係を特定するパターンを適用する - 結合度を分析します
- コンポーネントドメインを作成する - コンポーネントをドメインにグループ化します
- ドメインサービスを作成する - ドメインをサービスとして抽出します
注記
- コンポーネントは末端ノードにのみ存在する必要があります
- コードを含むルート名前空間は問題の原因になります
- フラット化によりコンポーネントが明確になります
- 機能に基づいてフラット化の方法を選択します
- 共通コードは専用のコンポーネントに配置します
- ファイルの移動後は必ず参照を更新します
- フラット化後は十分にテストします