Guide for continuous improvement, error proofing, and standardization. Use this skill when the user wants to improve code quality, refactor, or discuss process improvements.
Add this skill
npx mdskills install sickn33/kaizenComprehensive philosophy guide with clear TypeScript examples demonstrating iterative improvement patterns
1---2name: kaizen3description: Guide for continuous improvement, error proofing, and standardization. Use this skill when the user wants to improve code quality, refactor, or discuss process improvements.4---56# Kaizen: Continuous Improvement78## Overview910Small improvements, continuously. Error-proof by design. Follow what works. Build only what's needed.1112**Core principle:** Many small improvements beat one big change. Prevent errors at design time, not with fixes.1314## When to Use1516**Always applied for:**1718- Code implementation and refactoring19- Architecture and design decisions20- Process and workflow improvements21- Error handling and validation2223**Philosophy:** Quality through incremental progress and prevention, not perfection through massive effort.2425## The Four Pillars2627### 1. Continuous Improvement (Kaizen)2829Small, frequent improvements compound into major gains.3031#### Principles3233**Incremental over revolutionary:**3435- Make smallest viable change that improves quality36- One improvement at a time37- Verify each change before next38- Build momentum through small wins3940**Always leave code better:**4142- Fix small issues as you encounter them43- Refactor while you work (within scope)44- Update outdated comments45- Remove dead code when you see it4647**Iterative refinement:**4849- First version: make it work50- Second pass: make it clear51- Third pass: make it efficient52- Don't try all three at once5354<Good>55```typescript56// Iteration 1: Make it work57const calculateTotal = (items: Item[]) => {58 let total = 0;59 for (let i = 0; i < items.length; i++) {60 total += items[i].price * items[i].quantity;61 }62 return total;63};6465// Iteration 2: Make it clear (refactor)66const calculateTotal = (items: Item[]): number => {67return items.reduce((total, item) => {68return total + (item.price \* item.quantity);69}, 0);70};7172// Iteration 3: Make it robust (add validation)73const calculateTotal = (items: Item[]): number => {74if (!items?.length) return 0;7576return items.reduce((total, item) => {77if (item.price < 0 || item.quantity < 0) {78throw new Error('Price and quantity must be non-negative');79}80return total + (item.price \* item.quantity);81}, 0);82};8384````85Each step is complete, tested, and working86</Good>8788<Bad>89```typescript90// Trying to do everything at once91const calculateTotal = (items: Item[]): number => {92 // Validate, optimize, add features, handle edge cases all together93 if (!items?.length) return 0;94 const validItems = items.filter(item => {95 if (item.price < 0) throw new Error('Negative price');96 if (item.quantity < 0) throw new Error('Negative quantity');97 return item.quantity > 0; // Also filtering zero quantities98 });99 // Plus caching, plus logging, plus currency conversion...100 return validItems.reduce(...); // Too many concerns at once101};102````103104Overwhelming, error-prone, hard to verify105</Bad>106107#### In Practice108109**When implementing features:**1101111. Start with simplest version that works1122. Add one improvement (error handling, validation, etc.)1133. Test and verify1144. Repeat if time permits1155. Don't try to make it perfect immediately116117**When refactoring:**118119- Fix one smell at a time120- Commit after each improvement121- Keep tests passing throughout122- Stop when "good enough" (diminishing returns)123124**When reviewing code:**125126- Suggest incremental improvements (not rewrites)127- Prioritize: critical → important → nice-to-have128- Focus on highest-impact changes first129- Accept "better than before" even if not perfect130131### 2. Poka-Yoke (Error Proofing)132133Design systems that prevent errors at compile/design time, not runtime.134135#### Principles136137**Make errors impossible:**138139- Type system catches mistakes140- Compiler enforces contracts141- Invalid states unrepresentable142- Errors caught early (left of production)143144**Design for safety:**145146- Fail fast and loudly147- Provide helpful error messages148- Make correct path obvious149- Make incorrect path difficult150151**Defense in layers:**1521531. Type system (compile time)1542. Validation (runtime, early)1553. Guards (preconditions)1564. Error boundaries (graceful degradation)157158#### Type System Error Proofing159160<Good>161```typescript162// Error: string status can be any value163type OrderBad = {164 status: string; // Can be "pending", "PENDING", "pnding", anything!165 total: number;166};167168// Good: Only valid states possible169type OrderStatus = 'pending' | 'processing' | 'shipped' | 'delivered';170type Order = {171status: OrderStatus;172total: number;173};174175// Better: States with associated data176type Order =177| { status: 'pending'; createdAt: Date }178| { status: 'processing'; startedAt: Date; estimatedCompletion: Date }179| { status: 'shipped'; trackingNumber: string; shippedAt: Date }180| { status: 'delivered'; deliveredAt: Date; signature: string };181182// Now impossible to have shipped without trackingNumber183184````185Type system prevents entire classes of errors186</Good>187188<Good>189```typescript190// Make invalid states unrepresentable191type NonEmptyArray<T> = [T, ...T[]];192193const firstItem = <T>(items: NonEmptyArray<T>): T => {194 return items[0]; // Always safe, never undefined!195};196197// Caller must prove array is non-empty198const items: number[] = [1, 2, 3];199if (items.length > 0) {200 firstItem(items as NonEmptyArray<number>); // Safe201}202````203204Function signature guarantees safety205</Good>206207#### Validation Error Proofing208209<Good>210```typescript211// Error: Validation after use212const processPayment = (amount: number) => {213 const fee = amount * 0.03; // Used before validation!214 if (amount <= 0) throw new Error('Invalid amount');215 // ...216};217218// Good: Validate immediately219const processPayment = (amount: number) => {220if (amount <= 0) {221throw new Error('Payment amount must be positive');222}223if (amount > 10000) {224throw new Error('Payment exceeds maximum allowed');225}226227const fee = amount \* 0.03;228// ... now safe to use229};230231// Better: Validation at boundary with branded type232type PositiveNumber = number & { readonly \_\_brand: 'PositiveNumber' };233234const validatePositive = (n: number): PositiveNumber => {235if (n <= 0) throw new Error('Must be positive');236return n as PositiveNumber;237};238239const processPayment = (amount: PositiveNumber) => {240// amount is guaranteed positive, no need to check241const fee = amount \* 0.03;242};243244// Validate at system boundary245const handlePaymentRequest = (req: Request) => {246const amount = validatePositive(req.body.amount); // Validate once247processPayment(amount); // Use everywhere safely248};249250````251Validate once at boundary, safe everywhere else252</Good>253254#### Guards and Preconditions255256<Good>257```typescript258// Early returns prevent deeply nested code259const processUser = (user: User | null) => {260 if (!user) {261 logger.error('User not found');262 return;263 }264265 if (!user.email) {266 logger.error('User email missing');267 return;268 }269270 if (!user.isActive) {271 logger.info('User inactive, skipping');272 return;273 }274275 // Main logic here, guaranteed user is valid and active276 sendEmail(user.email, 'Welcome!');277};278````279280Guards make assumptions explicit and enforced281</Good>282283#### Configuration Error Proofing284285<Good>286```typescript287// Error: Optional config with unsafe defaults288type ConfigBad = {289 apiKey?: string;290 timeout?: number;291};292293const client = new APIClient({ timeout: 5000 }); // apiKey missing!294295// Good: Required config, fails early296type Config = {297apiKey: string;298timeout: number;299};300301const loadConfig = (): Config => {302const apiKey = process.env.API_KEY;303if (!apiKey) {304throw new Error('API_KEY environment variable required');305}306307return {308apiKey,309timeout: 5000,310};311};312313// App fails at startup if config invalid, not during request314const config = loadConfig();315const client = new APIClient(config);316317````318Fail at startup, not in production319</Good>320321#### In Practice322323**When designing APIs:**324- Use types to constrain inputs325- Make invalid states unrepresentable326- Return Result<T, E> instead of throwing327- Document preconditions in types328329**When handling errors:**330- Validate at system boundaries331332- Use guards for preconditions333- Fail fast with clear messages334- Log context for debugging335336**When configuring:**337- Required over optional with defaults338- Validate all config at startup339- Fail deployment if config invalid340- Don't allow partial configurations341342### 3. Standardized Work343Follow established patterns. Document what works. Make good practices easy to follow.344345#### Principles346347**Consistency over cleverness:**348- Follow existing codebase patterns349- Don't reinvent solved problems350- New pattern only if significantly better351- Team agreement on new patterns352353**Documentation lives with code:**354- README for setup and architecture355- CLAUDE.md for AI coding conventions356- Comments for "why", not "what"357- Examples for complex patterns358359**Automate standards:**360- Linters enforce style361- Type checks enforce contracts362- Tests verify behavior363- CI/CD enforces quality gates364365#### Following Patterns366367<Good>368```typescript369// Existing codebase pattern for API clients370class UserAPIClient {371 async getUser(id: string): Promise<User> {372 return this.fetch(`/users/${id}`);373 }374}375376// New code follows the same pattern377class OrderAPIClient {378 async getOrder(id: string): Promise<Order> {379 return this.fetch(`/orders/${id}`);380 }381}382````383384Consistency makes codebase predictable385</Good>386387<Bad>388```typescript389// Existing pattern uses classes390class UserAPIClient { /* ... */ }391392// New code introduces different pattern without discussion393const getOrder = async (id: string): Promise<Order> => {394// Breaking consistency "because I prefer functions"395};396397````398Inconsistency creates confusion399</Bad>400401#### Error Handling Patterns402403<Good>404```typescript405// Project standard: Result type for recoverable errors406type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };407408// All services follow this pattern409const fetchUser = async (id: string): Promise<Result<User, Error>> => {410 try {411 const user = await db.users.findById(id);412 if (!user) {413 return { ok: false, error: new Error('User not found') };414 }415 return { ok: true, value: user };416 } catch (err) {417 return { ok: false, error: err as Error };418 }419};420421// Callers use consistent pattern422const result = await fetchUser('123');423if (!result.ok) {424 logger.error('Failed to fetch user', result.error);425 return;426}427const user = result.value; // Type-safe!428````429430Standard pattern across codebase431</Good>432433#### Documentation Standards434435<Good>436```typescript437/**438 * Retries an async operation with exponential backoff.439 *440 * Why: Network requests fail temporarily; retrying improves reliability441 * When to use: External API calls, database operations442 * When not to use: User input validation, internal function calls443 *444 * @example445 * const result = await retry(446 * () => fetch('https://api.example.com/data'),447 * { maxAttempts: 3, baseDelay: 1000 }448 * );449 */450const retry = async <T>(451 operation: () => Promise<T>,452 options: RetryOptions453): Promise<T> => {454 // Implementation...455};456```457Documents why, when, and how458</Good>459460#### In Practice461462**Before adding new patterns:**463464- Search codebase for similar problems solved465- Check CLAUDE.md for project conventions466- Discuss with team if breaking from pattern467- Update docs when introducing new pattern468469**When writing code:**470471- Match existing file structure472- Use same naming conventions473- Follow same error handling approach474- Import from same locations475476**When reviewing:**477478- Check consistency with existing code479- Point to examples in codebase480- Suggest aligning with standards481- Update CLAUDE.md if new standard emerges482483### 4. Just-In-Time (JIT)484485Build what's needed now. No more, no less. Avoid premature optimization and over-engineering.486487#### Principles488489**YAGNI (You Aren't Gonna Need It):**490491- Implement only current requirements492- No "just in case" features493- No "we might need this later" code494- Delete speculation495496**Simplest thing that works:**497498- Start with straightforward solution499- Add complexity only when needed500- Refactor when requirements change501- Don't anticipate future needs502503**Optimize when measured:**504505- No premature optimization506- Profile before optimizing507- Measure impact of changes508- Accept "good enough" performance509510#### YAGNI in Action511512<Good>513```typescript514// Current requirement: Log errors to console515const logError = (error: Error) => {516 console.error(error.message);517};518```519Simple, meets current need520</Good>521522<Bad>523```typescript524// Over-engineered for "future needs"525interface LogTransport {526 write(level: LogLevel, message: string, meta?: LogMetadata): Promise<void>;527}528529class ConsoleTransport implements LogTransport { /_... _/ }530class FileTransport implements LogTransport { /_ ... _/ }531class RemoteTransport implements LogTransport { /_ ..._/ }532533class Logger {534private transports: LogTransport[] = [];535private queue: LogEntry[] = [];536private rateLimiter: RateLimiter;537private formatter: LogFormatter;538539// 200 lines of code for "maybe we'll need it"540}541542const logError = (error: Error) => {543Logger.getInstance().log('error', error.message);544};545546````547Building for imaginary future requirements548</Bad>549550**When to add complexity:**551- Current requirement demands it552- Pain points identified through use553- Measured performance issues554- Multiple use cases emerged555556<Good>557```typescript558// Start simple559const formatCurrency = (amount: number): string => {560 return `$${amount.toFixed(2)}`;561};562563// Requirement evolves: support multiple currencies564const formatCurrency = (amount: number, currency: string): string => {565 const symbols = { USD: '$', EUR: '€', GBP: '£' };566 return `${symbols[currency]}${amount.toFixed(2)}`;567};568569// Requirement evolves: support localization570const formatCurrency = (amount: number, locale: string): string => {571 return new Intl.NumberFormat(locale, {\n style: 'currency',572 currency: locale === 'en-US' ? 'USD' : 'EUR',573 }).format(amount);574};575````576577Complexity added only when needed578</Good>579580#### Premature Abstraction581582<Bad>583```typescript584// One use case, but building generic framework585abstract class BaseCRUDService<T> {586 abstract getAll(): Promise<T[]>;587 abstract getById(id: string): Promise<T>;588 abstract create(data: Partial<T>): Promise<T>;589 abstract update(id: string, data: Partial<T>): Promise<T>;590 abstract delete(id: string): Promise<void>;591}592593class GenericRepository<T> { /_300 lines _/ }594class QueryBuilder<T> { /_ 200 lines_/ }595// ... building entire ORM for single table596597````598Massive abstraction for uncertain future599</Bad>600601<Good>602```typescript603// Simple functions for current needs604const getUsers = async (): Promise<User[]> => {605 return db.query('SELECT * FROM users');606};607608const getUserById = async (id: string): Promise<User | null> => {609 return db.query('SELECT * FROM users WHERE id = $1', [id]);610};611612// When pattern emerges across multiple entities, then abstract613````614615Abstract only when pattern proven across 3+ cases616</Good>617618#### Performance Optimization619620<Good>621```typescript622// Current: Simple approach623const filterActiveUsers = (users: User[]): User[] => {624 return users.filter(user => user.isActive);625};626627// Benchmark shows: 50ms for 1000 users (acceptable)628// ✓ Ship it, no optimization needed629630// Later: After profiling shows this is bottleneck631// Then optimize with indexed lookup or caching632633````634Optimize based on measurement, not assumptions635</Good>636637<Bad>638```typescript639// Premature optimization640const filterActiveUsers = (users: User[]): User[] => {641 // "This might be slow, so let's cache and index"642 const cache = new WeakMap();643 const indexed = buildBTreeIndex(users, 'isActive');644 // 100 lines of optimization code645 // Adds complexity, harder to maintain646 // No evidence it was needed647};\648````649650Complex solution for unmeasured problem651</Bad>652653#### In Practice654655**When implementing:**656657- Solve the immediate problem658- Use straightforward approach659- Resist "what if" thinking660- Delete speculative code661662**When optimizing:**663664- Profile first, optimize second665- Measure before and after666- Document why optimization needed667- Keep simple version in tests668669**When abstracting:**670671- Wait for 3+ similar cases (Rule of Three)672- Make abstraction as simple as possible673- Prefer duplication over wrong abstraction674- Refactor when pattern clear675676## Integration with Commands677678The Kaizen skill guides how you work. The commands provide structured analysis:679680- **`/why`**: Root cause analysis (5 Whys)681- **`/cause-and-effect`**: Multi-factor analysis (Fishbone)682- **`/plan-do-check-act`**: Iterative improvement cycles683- **`/analyse-problem`**: Comprehensive documentation (A3)684- **`/analyse`**: Smart method selection (Gemba/VSM/Muda)685686Use commands for structured problem-solving. Apply skill for day-to-day development.687688## Red Flags689690**Violating Continuous Improvement:**691692- "I'll refactor it later" (never happens)693- Leaving code worse than you found it694- Big bang rewrites instead of incremental695696**Violating Poka-Yoke:**697698- "Users should just be careful"699- Validation after use instead of before700- Optional config with no validation701702**Violating Standardized Work:**703704- "I prefer to do it my way"705- Not checking existing patterns706- Ignoring project conventions707708**Violating Just-In-Time:**709710- "We might need this someday"711- Building frameworks before using them712- Optimizing without measuring713714## Remember715716**Kaizen is about:**717718- Small improvements continuously719- Preventing errors by design720- Following proven patterns721- Building only what's needed722723**Not about:**724725- Perfection on first try726- Massive refactoring projects727- Clever abstractions728- Premature optimization729730**Mindset:** Good enough today, better tomorrow. Repeat.731
Full transparency — inspect the skill content before installing.