kaizen:kaizen について
kaizen:kaizenは、実装、リファクタリング、設計、エラー処理に継続的改善の原則を適用する開発向けスキルです。小さく検証可能な変更、エラー予防、既存パターンの順守、必要な範囲に絞った実装を重視します。
主な機能
- 01小さく検証可能な改善を促進
- 02型とバリデーションによるエラー予防
- 03既存のプロジェクトパターンを重視
- 04先回りした複雑化を抑制
- 05構造化分析コマンドと日常業務を連携
活用シーン
- 01範囲を絞ったコード改善
- 02テストを通した状態でのリファクタリング
- 03バリデーションとエラー処理の設計
- 04早すぎる抽象化や最適化の回避
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ w95/ awesome-claude-corporate-skills --skill kaizen:kaizenインストール後、Claude Code で/kaizen:kaizenを入力して読み込まれたか確認します。
詳細
改善:継続的な改善
継続的な改善の考え方を適用します。小さな改善を繰り返し提案し、エラーを防ぐ設計を行い、確立されたパターンに従い、過剰な設計を避けます。品質とシンプルさを高めるために自動的に適用されます。
概要
小さな改善を継続的に行います。設計によってエラーを防ぎます。効果が実証されている方法に従います。必要なものだけを作ります。
基本原則: 大きな変更を一度に行うより、小さな改善を積み重ねるほうが効果的です。修正で対処するのではなく、設計段階でエラーを防ぎます。
使用するタイミング
常に適用する対象:
- コードの実装とリファクタリング
- アーキテクチャと設計上の判断
- プロセスとワークフローの改善
- エラー処理と検証
考え方: 大規模な努力で完璧を目指すのではなく、段階的な進歩と予防によって品質を高めます。
4つの柱
1. 継続的な改善(カイゼン)
小さく頻繁な改善を積み重ねることで、大きな成果につながります。
原則
抜本的な変更より段階的な改善:
- 品質を高める、実行可能な最小限の変更を行います
- 一度に一つの改善を行います
- 次の変更に進む前に、それぞれの変更を検証します
- 小さな成功を積み重ねて弾みをつけます
コードを常により良い状態にする:
- 気づいた小さな問題はその場で修正します
- 作業中にリファクタリングします(範囲内で)
- 古くなったコメントを更新します
- 不要なコードを見つけたら削除します
段階的に改善する:
- 1回目:動くようにします
- 2回目:わかりやすくします
- 3回目:効率的にします
- 3つすべてを一度に実現しようとしないでください
// Iteration 2: Make it clear (refactor) const calculateTotal = (items: Item[]): number => { return items.reduce((total, item) => { return total + (item.price * item.quantity); }, 0); };
// Iteration 3: Make it robust (add validation) const calculateTotal = (items: Item[]): number => { if (!items?.length) return 0;
return items.reduce((total, item) => { if (item.price < 0 || item.quantity < 0) { throw new Error('Price and quantity must be non-negative'); } return total + (item.price * item.quantity); }, 0); };
各ステップが完了し、テスト済みで、動作しています
</Good>
<Bad>
```typescript
// Trying to do everything at once
const calculateTotal = (items: Item[]): number => {
// Validate, optimize, add features, handle edge cases all together
if (!items?.length) return 0;
const validItems = items.filter(item => {
if (item.price < 0) throw new Error('Negative price');
if (item.quantity < 0) throw new Error('Negative quantity');
return item.quantity > 0; // Also filtering zero quantities
});
// Plus caching, plus logging, plus currency conversion...
return validItems.reduce(...); // Too many concerns at once
};
手に負えず、エラーが起きやすく、検証も困難です
実践
機能を実装するとき:
- 動作する最もシンプルなバージョンから始めます
- 改善を一つ加えます(エラー処理、検証など)
- テストして検証します
- 時間に余裕があれば繰り返します
- すぐに完璧なものを作ろうとしないでください
リファクタリングするとき:
- コードの問題を一度に一つ修正します
- 改善のたびにコミットします
- 作業中はテストが通る状態を保ちます
- 「十分良い」状態になったら終了します(労力に対する効果が小さくなるため)
コードをレビューするとき:
- 書き換えではなく、段階的な改善を提案します
- 優先順位を付けます:重大 → 重要 → できれば対応
- 最も効果の大きい変更から取り組みます
- 完璧でなくても、以前より「良くなっている」状態を受け入れます
2. ポカヨケ(エラー防止)
実行時ではなく、コンパイル時や設計時にエラーを防ぐシステムを設計します。
原則
エラーが起きないようにする:
- 型システムでミスを検出します
- コンパイラーで契約を強制します
- 無効な状態を表現できないようにします
- 本番環境に入る前の早い段階でエラーを検出します
安全性を考慮して設計する:
- 早期に、明確に失敗させます
- 役立つエラーメッセージを表示します
- 正しい方法を明確にします
- 誤った方法を取りにくくします
多層防御:
- 型システム(コンパイル時)
- 検証(実行時、早期)
- ガード(事前条件)
- エラー境界(適切な縮退)
型システムによるエラー防止
```typescript // Error: string status can be any value type OrderBad = { status: string; // Can be "pending", "PENDING", "pnding", anything! total: number; };// Good: Only valid states possible type OrderStatus = 'pending' | 'processing' | 'shipped' | 'delivered'; type Order = { status: OrderStatus; total: number; };
// Better: States with associated data type Order = | { status: 'pending'; createdAt: Date } | { status: 'processing'; startedAt: Date; estimatedCompletion: Date } | { status: 'shipped'; trackingNumber: string; shippedAt: Date } | { status: 'delivered'; deliveredAt: Date; signature: string };
// Now impossible to have shipped without trackingNumber
型システムによって、さまざまな種類のエラーを防ぎます
</Good>
<Good>
```typescript
// Make invalid states unrepresentable
type NonEmptyArray<T> = [T, ...T[]];
const firstItem = <T>(items: NonEmptyArray<T>): T => {
return items[0]; // Always safe, never undefined!
};
// Caller must prove array is non-empty
const items: number[] = [1, 2, 3];
if (items.length > 0) {
firstItem(items as NonEmptyArray<number>); // Safe
}
関数シグネチャによって安全性を保証します
検証によるエラー防止
```typescript // Error: Validation after use const processPayment = (amount: number) => { const fee = amount * 0.03; // Used before validation! if (amount <= 0) throw new Error('Invalid amount'); // ... };// Good: Validate immediately const processPayment = (amount: number) => { if (amount <= 0) { throw new Error('Payment amount must be positive'); } if (amount > 10000) { throw new Error('Payment exceeds maximum allowed'); }
const fee = amount * 0.03; // ... now safe to use };
// Better: Validation at boundary with branded type type PositiveNumber = number & { readonly __brand: 'PositiveNumber' };
const validatePositive = (n: number): PositiveNumber => { if (n <= 0) throw new Error('Must be positive'); return n as PositiveNumber; };
const processPayment = (amount: PositiveNumber) => { // amount is guaranteed positive, no need to check const fee = amount * 0.03; };
// Validate at system boundary const handlePaymentRequest = (req: Request) => { const amount = validatePositive(req.body.amount); // Validate once processPayment(amount); // Use everywhere safely };
境界で一度検証すれば、ほかの場所では安全に扱えます
</Good>
#### ガードと事前条件
<Good>
```typescript
// Early returns prevent deeply nested code
const processUser = (user: User | null) => {
if (!user) {
logger.error('User not found');
return;
}
if (!user.email) {
logger.error('User email missing');
return;
}
if (!user.isActive) {
logger.info('User inactive, skipping');
return;
}
// Main logic here, guaranteed user is valid and active
sendEmail(user.email, 'Welcome!');
};
ガードによって前提を明示し、確実に適用します
設定によるエラー防止
```typescript // Error: Optional config with unsafe defaults type ConfigBad = { apiKey?: string; timeout?: number; };const client = new APIClient({ timeout: 5000 }); // apiKey missing!
// Good: Required config, fails early type Config = { apiKey: string; timeout: number; };
const loadConfig = (): Config => { const apiKey = process.env.API_KEY; if (!apiKey) { throw new Error('API_KEY environment variable required'); }
return { apiKey, timeout: 5000, }; };
// App fails at startup if config invalid, not during request const config = loadConfig(); const client = new APIClient(config);
本番環境ではなく、起動時に失敗させます
</Good>
#### 実践
**APIを設計するとき:**
- 型を使って入力を制約します
- 無効な状態を表現できないようにします
- 例外をスローする代わりに Result<T, E> を返します
- 事前条件を型で表現します
**エラーを処理するとき:**
- システム境界で検証します
- 事前条件にガードを使用します
- 明確なメッセージとともに早期に失敗させます
- デバッグに必要なコンテキストをログに記録します
**設定するとき:**
- デフォルト値付きの任意設定より、必須設定を優先します
- 起動時にすべての設定を検証します
- 設定が無効ならデプロイを失敗させます
- 不完全な設定を許可しません
### 3. 標準化された作業
確立されたパターンに従います。効果が実証された方法を文書化します。優れた実践を簡単に取り入れられるようにします。
#### 原則
**巧妙さより一貫性:**
- 既存のコードベースのパターンに従う
- 解決済みの問題を作り直さない
- 新しいパターンは、明らかに優れている場合にのみ採用する
- 新しいパターンはチームの合意を得てから採用する
**ドキュメントはコードとともに:**
- README にはセットアップとアーキテクチャを書く
- AI のコーディング規約は CLAUDE.md に書く
- コメントには「何を」ではなく「なぜ」を書く
- 複雑なパターンには例を示す
**標準を自動化する:**
- リンターでスタイルを強制する
- 型チェックで契約を強制する
- テストで動作を検証する
- CI/CD で品質ゲートを強制する
#### パターンへの従い方
<Good>
```typescript
// Existing codebase pattern for API clients
class UserAPIClient {
async getUser(id: string): Promise<User> {
return this.fetch(`/users/${id}`);
}
}
// New code follows the same pattern
class OrderAPIClient {
async getOrder(id: string): Promise<Order> {
return this.fetch(`/orders/${id}`);
}
}
一貫性があるとコードベースが予測可能になる
```typescript // Existing pattern uses classes class UserAPIClient { /* ... */ }// New code introduces different pattern without discussion const getOrder = async (id: string): Promise => { // Breaking consistency "because I prefer functions" };
一貫性の欠如は混乱を生む
</Bad>
#### エラーハンドリングのパターン
<Good>
```typescript
// Project standard: Result type for recoverable errors
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };
// All services follow this pattern
const fetchUser = async (id: string): Promise<Result<User, Error>> => {
try {
const user = await db.users.findById(id);
if (!user) {
return { ok: false, error: new Error('User not found') };
}
return { ok: true, value: user };
} catch (err) {
return { ok: false, error: err as Error };
}
};
// Callers use consistent pattern
const result = await fetchUser('123');
if (!result.ok) {
logger.error('Failed to fetch user', result.error);
return;
}
const user = result.value; // Type-safe!
コードベース全体で標準的なパターンを使う
ドキュメントの標準
```typescript /** * Retries an async operation with exponential backoff. * * Why: Network requests fail temporarily; retrying improves reliability * When to use: External API calls, database operations * When not to use: User input validation, internal function calls * * @example * const result = await retry( * () => fetch('https://api.example.com/data'), * { maxAttempts: 3, baseDelay: 1000 } * ); */ const retry = async ( operation: () => Promise, options: RetryOptions ): Promise => { // Implementation... }; ``` なぜ、いつ、どのように行うかを文書化する実践
新しいパターンを追加する前に:
- 同様の問題がコードベース内で解決済みかを検索する
- プロジェクトの規約について CLAUDE.md を確認する
- パターンから外れる場合はチームと相談する
- 新しいパターンを導入したらドキュメントを更新する
コードを書くとき:
- 既存のファイル構成に合わせる
- 同じ命名規則を使う
- 同じエラーハンドリングの方法に従う
- 同じ場所からインポートする
レビューするとき:
- 既存のコードとの一貫性を確認する
- コードベース内の例を示す
- 標準に合わせるよう提案する
- 新しい標準が生まれたら CLAUDE.md を更新する
4. Just-In-Time (JIT)
今必要なものだけを作る。多すぎず、少なすぎず。早すぎる最適化や過剰な設計を避けます。
原則
YAGNI (You Aren't Gonna Need It):
- 現在の要件に必要な機能だけを実装する
- 「念のため」の機能は作らない
- 「将来必要になるかもしれない」コードは書かない
- 推測に基づく部分は削除する
最も単純で動く解決策:
- まずは単純な解決策から始める
- 必要になったときにだけ複雑さを加える
- 要件が変わったらリファクタリングする
- 将来の必要性を先回りして考えない
計測してから最適化する:
- 早すぎる最適化をしない
- 最適化の前にプロファイリングする
- 変更の影響を計測する
- 「十分に良い」性能で満足する
実際のYAGNI
```typescript // Current requirement: Log errors to console const logError = (error: Error) => { console.error(error.message); }; ``` 単純で、現在のニーズを満たしている ```typescript // Over-engineered for "future needs" interface LogTransport { write(level: LogLevel, message: string, meta?: LogMetadata): Promise; }class ConsoleTransport implements LogTransport { /... / } class FileTransport implements LogTransport { / ... / } class RemoteTransport implements LogTransport { / .../ }
class Logger { private transports: LogTransport[] = []; private queue: LogEntry[] = []; private rateLimiter: RateLimiter; private formatter: LogFormatter;
// 200 lines of code for "maybe we'll need it" }
const logError = (error: Error) => { Logger.getInstance().log('error', error.message); };
架空の将来要件のために作り込んでいる
</Bad>
**複雑さを加えるべきとき:**
- 現在の要件がそれを必要とするとき
- 使用を通じて問題点が明らかになったとき
- 計測によって性能問題が確認されたとき
- 複数のユースケースが出てきたとき
<Good>
```typescript
// Start simple
const formatCurrency = (amount: number): string => {
return `$${amount.toFixed(2)}`;
};
// Requirement evolves: support multiple currencies
const formatCurrency = (amount: number, currency: string): string => {
const symbols = { USD: '$', EUR: '€', GBP: '£' };
return `${symbols[currency]}${amount.toFixed(2)}`;
};
// Requirement evolves: support localization
const formatCurrency = (amount: number, locale: string): string => {
return new Intl.NumberFormat(locale, {
style: 'currency',
currency: locale === 'en-US' ? 'USD' : 'EUR',
}).format(amount);
};
必要になったときにだけ複雑さを加えている
早すぎる抽象化
```typescript // One use case, but building generic framework abstract class BaseCRUDService { abstract getAll(): Promise; abstract getById(id: string): Promise; abstract create(data: Partial): Promise; abstract update(id: string, data: Partial): Promise; abstract delete(id: string): Promise; }class GenericRepository { /300 lines / } class QueryBuilder { / 200 lines/ } // ... building entire ORM for single table
不確かな将来のための大げさな抽象化
</Bad>
<Good>
```typescript
// Simple functions for current needs
const getUsers = async (): Promise<User[]> => {
return db.query('SELECT * FROM users');
};
const getUserById = async (id: string): Promise<User | null> => {
return db.query('SELECT * FROM users WHERE id = $1', [id]);
};
// When pattern emerges across multiple entities, then abstract
パターンが3件以上のケースで実証されたときにだけ抽象化する
性能の最適化
```typescript // Current: Simple approach const filterActiveUsers = (users: User[]): User[] => { return users.filter(user => user.isActive); };// Benchmark shows: 50ms for 1000 users (acceptable) // ✓ Ship it, no optimization needed
// Later: After profiling shows this is bottleneck // Then optimize with indexed lookup or caching
推測ではなく計測に基づいて最適化している
</Good>
<Bad>
```typescript
// Premature optimization
const filterActiveUsers = (users: User[]): User[] => {
// "This might be slow, so let's cache and index"
const cache = new WeakMap();
const indexed = buildBTreeIndex(users, 'isActive');
// 100 lines of optimization code
// Adds complexity, harder to maintain
// No evidence it was needed
};
計測されていない問題に対する複雑な解決策
実践
実装するとき:
- 目の前の問題を解決する
- 素直なアプローチを使う
- 「もし〜だったら」という発想に流されない
- 推測に基づくコードは削除する
最適化するとき:
- 先にプロファイリングし、その後に最適化する
- 前後で計測する
- 最適化が必要な理由を文書化する
- 単純な版をテストとして残しておく
抽象化するとき:
- 類似のケースが3件以上そろうまで待つ(Rule of Three)
- 抽象化はできるだけ単純にする
- 誤った抽象化よりも重複を選ぶ
- パターンが明確になったらリファクタリングする
コマンドとの連携
Kaizen スキルは作業の進め方を導きます。コマンドは構造化された分析を提供します:
/why: 根本原因分析(5 Whys)/cause-and-effect: 多要因分析(特性要因図)/plan-do-check-act: 反復的な改善サイクル/analyse-problem: 包括的なドキュメント作成(A3)/analyse: 適切な手法の選択(現地現物/VSM/ムダ)
構造化された問題解決にはコマンドを使い、日々の開発にはスキルを適用してください。
レッドフラッグ
継続的改善に違反する例:
- 「あとでリファクタリングしよう」(実際にはやられない)
- 見つけたときより悪い状態でコードを残す
- 段階的に進めず、一気に書き直す(ビッグバン書き換え)
ポカヨケに違反する例:
- 「ユーザーが気をつければいい」
- 使用後に検証し、使用前には検証しない
- 検証のないオプション設定
標準作業に違反する例:
- 「自分のやり方でやりたい」
- 既存のパターンを確認しない
- プロジェクトの規約を無視する
ジャスト・イン・タイムに違反する例:
- 「いつか必要になるかもしれない」
- 使う前にフレームワークを作り込む
- 計測せずに最適化する
覚えておくこと
カイゼンとは:
- 小さな改善を継続的に積み重ねること
- 設計によってエラーを未然に防ぐこと
- 実証済みのパターンに従うこと
- 必要なものだけを作ること
カイゼンではないもの:
- 最初から完璧を目指すこと
- 大規模なリファクタリングプロジェクト
- 巧妙な抽象化
- 早すぎる最適化
マインドセット: 今日は十分に良く、明日はより良く。これを繰り返す。