kaizen

Documentation & Productivité

Guide for continuous improvement, error proofing, and standardization. Use this skill when the user wants to improve code quality, refactor, or discuss process improvements.

Documentation

Kaizen: Continuous Improvement

Overview

Small improvements, continuously. Error-proof by design. Follow what works. Build only what's needed.

Core principle: Many small improvements beat one big change. Prevent errors at design time, not with fixes.

When to Use

Always applied for:

●Code implementation and refactoring
●Architecture and design decisions
●Process and workflow improvements
●Error handling and validation

Philosophy: Quality through incremental progress and prevention, not perfection through massive effort.

The Four Pillars

1. Continuous Improvement (Kaizen)

Small, frequent improvements compound into major gains.

#### Principles

Incremental over revolutionary:

●Make smallest viable change that improves quality
●One improvement at a time
●Verify each change before next
●Build momentum through small wins

Always leave code better:

●Fix small issues as you encounter them
●Refactor while you work (within scope)
●Update outdated comments
●Remove dead code when you see it

Iterative refinement:

●First version: make it work
●Second pass: make it clear
●Third pass: make it efficient
●Don't try all three at once

// Iteration 1: Make it work
const calculateTotal = (items: Item[]) => {
  let total = 0;
  for (let i = 0; i < items.length; i++) {
    total += items[i].price * items[i].quantity;
  }
  return total;
};

// 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);
};

Each step is complete, tested, and working

// 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
};

Overwhelming, error-prone, hard to verify

#### In Practice

When implementing features:

1.Start with simplest version that works
2.Add one improvement (error handling, validation, etc.)
3.Test and verify
4.Repeat if time permits
5.Don't try to make it perfect immediately

When refactoring:

●Fix one smell at a time
●Commit after each improvement
●Keep tests passing throughout
●Stop when "good enough" (diminishing returns)

When reviewing code:

●Suggest incremental improvements (not rewrites)
●Prioritize: critical → important → nice-to-have
●Focus on highest-impact changes first
●Accept "better than before" even if not perfect

2. Poka-Yoke (Error Proofing)

Design systems that prevent errors at compile/design time, not runtime.

#### Principles

Make errors impossible:

●Type system catches mistakes
●Compiler enforces contracts
●Invalid states unrepresentable
●Errors caught early (left of production)

Design for safety:

●Fail fast and loudly
●Provide helpful error messages
●Make correct path obvious
●Make incorrect path difficult

Defense in layers:

1.Type system (compile time)
2.Validation (runtime, early)
3.Guards (preconditions)
4.Error boundaries (graceful degradation)

#### Type System Error Proofing

// 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

Type system prevents entire classes of errors

// 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
}

Function signature guarantees safety

#### Validation Error Proofing

// 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
};

Validate once at boundary, safe everywhere else

#### Guards and Preconditions

// 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!');
};

Guards make assumptions explicit and enforced

#### Configuration Error Proofing

// 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);

Fail at startup, not in production

#### In Practice

When designing APIs:

●Use types to constrain inputs
●Make invalid states unrepresentable
●Return Result instead of throwing
●Document preconditions in types

When handling errors:

●Validate at system boundaries
●Use guards for preconditions
●Fail fast with clear messages
●Log context for debugging

When configuring:

●Required over optional with defaults
●Validate all config at startup
●Fail deployment if config invalid
●Don't allow partial configurations

3. Standardized Work

Follow established patterns. Document what works. Make good practices easy to follow.

#### Principles

Consistency over cleverness:

●Follow existing codebase patterns
●Don't reinvent solved problems
●New pattern only if significantly better
●Team agreement on new patterns

Documentation lives with code:

●README for setup and architecture
●CLAUDE.md for AI coding conventions
●Comments for "why", not "what"
●Examples for complex patterns

Automate standards:

●Linters enforce style
●Type checks enforce contracts
●Tests verify behavior
●CI/CD enforces quality gates

#### Following Patterns

// 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}`);
  }
}

Consistency makes codebase predictable

// Existing pattern uses classes
class UserAPIClient { /* ... */ }

// New code introduces different pattern without discussion
const getOrder = async (id: string): Promise<Order> => {
// Breaking consistency "because I prefer functions"
};

Inconsistency creates confusion

#### Error Handling Patterns

// 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!

Standard pattern across codebase

#### Documentation Standards

/**
 * 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 <T>(
  operation: () => Promise<T>,
  options: RetryOptions
): Promise<T> => {
  // Implementation...
};

Documents why, when, and how

#### In Practice

Before adding new patterns:

●Search codebase for similar problems solved
●Check CLAUDE.md for project conventions
●Discuss with team if breaking from pattern
●Update docs when introducing new pattern

When writing code:

●Match existing file structure
●Use same naming conventions
●Follow same error handling approach
●Import from same locations

When reviewing:

●Check consistency with existing code
●Point to examples in codebase
●Suggest aligning with standards
●Update CLAUDE.md if new standard emerges

4. Just-In-Time (JIT)

Build what's needed now. No more, no less. Avoid premature optimization and over-engineering.

#### Principles

YAGNI (You Aren't Gonna Need It):

●Implement only current requirements
●No "just in case" features
●No "we might need this later" code
●Delete speculation

Simplest thing that works:

●Start with straightforward solution
●Add complexity only when needed
●Refactor when requirements change
●Don't anticipate future needs

Optimize when measured:

●No premature optimization
●Profile before optimizing
●Measure impact of changes
●Accept "good enough" performance

#### YAGNI in Action

// Current requirement: Log errors to console
const logError = (error: Error) => {
  console.error(error.message);
};

Simple, meets current need

// Over-engineered for "future needs"
interface LogTransport {
  write(level: LogLevel, message: string, meta?: LogMetadata): Promise<void>;
}

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);
};

Building for imaginary future requirements

When to add complexity:

●Current requirement demands it
●Pain points identified through use
●Measured performance issues
●Multiple use cases emerged

// 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, {\n    style: 'currency',
    currency: locale === 'en-US' ? 'USD' : 'EUR',
  }).format(amount);
};

Complexity added only when needed

#### Premature Abstraction

// One use case, but building generic framework
abstract class BaseCRUDService<T> {
  abstract getAll(): Promise<T[]>;
  abstract getById(id: string): Promise<T>;
  abstract create(data: Partial<T>): Promise<T>;
  abstract update(id: string, data: Partial<T>): Promise<T>;
  abstract delete(id: string): Promise<void>;
}

class GenericRepository<T> { /_300 lines _/ }
class QueryBuilder<T> { /_ 200 lines_/ }
// ... building entire ORM for single table

Massive abstraction for uncertain future

// 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

Abstract only when pattern proven across 3+ cases

#### Performance Optimization

// 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

Optimize based on measurement, not assumptions

// 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
};\

Complex solution for unmeasured problem

#### In Practice

When implementing:

●Solve the immediate problem
●Use straightforward approach
●Resist "what if" thinking
●Delete speculative code

When optimizing:

●Profile first, optimize second
●Measure before and after
●Document why optimization needed
●Keep simple version in tests

When abstracting:

●Wait for 3+ similar cases (Rule of Three)
●Make abstraction as simple as possible
●Prefer duplication over wrong abstraction
●Refactor when pattern clear

Integration with Commands

The Kaizen skill guides how you work. The commands provide structured analysis:

●/why: Root cause analysis (5 Whys)
●/cause-and-effect: Multi-factor analysis (Fishbone)
●/plan-do-check-act: Iterative improvement cycles
●/analyse-problem: Comprehensive documentation (A3)
●/analyse: Smart method selection (Gemba/VSM/Muda)

Use commands for structured problem-solving. Apply skill for day-to-day development.

Red Flags

Violating Continuous Improvement:

●"I'll refactor it later" (never happens)
●Leaving code worse than you found it
●Big bang rewrites instead of incremental

Violating Poka-Yoke:

●"Users should just be careful"
●Validation after use instead of before
●Optional config with no validation

Violating Standardized Work:

●"I prefer to do it my way"
●Not checking existing patterns
●Ignoring project conventions

Violating Just-In-Time:

●"We might need this someday"
●Building frameworks before using them
●Optimizing without measuring

Remember

Kaizen is about:

●Small improvements continuously
●Preventing errors by design
●Following proven patterns
●Building only what's needed

Not about:

●Perfection on first try
●Massive refactoring projects
●Clever abstractions
●Premature optimization

Mindset: Good enough today, better tomorrow. Repeat.

Utiliser l'Agent kaizen - Outil & Compétence IA | Skills Catalogue | Skills Catalogue