名称:kaizen 描述:持续改进、防错和标准化的指南。当用户希望提高代码质量、重构或讨论过程改进时使用此技能。
Kaizen:持续改进
概述
小改进,持续进行。通过设计防错。遵循有效的方法。仅构建所需内容。
核心原则: 许多小改进胜过一个大变更。在设计时预防错误,而非通过修复。
何时使用
始终适用于:
- 代码实现和重构
- 架构和设计决策
- 流程和工作流改进
- 错误处理和验证
哲学: 通过增量进步和预防实现质量,而非通过大量努力追求完美。
四大支柱
1. 持续改进(Kaizen)
小而频繁的改进会累积成重大收益。
原则
增量优于革命性:
- 做出最小可行改进以提高质量
- 一次一个改进
- 每个改进前验证
- 通过小胜利建立势头
始终使代码更好:
- 遇到小问题时立即修复
- 工作时重构(在范围内)
- 更新过时的注释
- 看到死代码时删除
迭代精炼:
- 第一版:使其工作
- 第二版:使其清晰
- 第三版:使其高效
- 不要一次尝试所有三版
<好>
// 迭代1:使其工作
const calculateTotal = (items: Item[]) => {
let total = 0;
for (let i = 0; i < items.length; i++) {
total += items[i].price * items[i].quantity;
}
return total;
};
// 迭代2:使其清晰(重构)
const calculateTotal = (items: Item[]): number => {
return items.reduce((total, item) => {
return total + (item.price * item.quantity);
}, 0);
};
// 迭代3:使其健壮(添加验证)
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('价格和数量必须非负');
}
return total + (item.price * item.quantity);
}, 0);
};
每个步骤都完整、经过测试且工作正常 </好>
<坏>
// 试图一次完成所有事情
const calculateTotal = (items: Item[]): number => {
// 验证、优化、添加功能、处理边缘情况全部一起
if (!items?.length) return 0;
const validItems = items.filter(item => {
if (item.price < 0) throw new Error('负价格');
if (item.quantity < 0) throw new Error('负数量');
return item.quantity > 0; // 还过滤零数量
});
// 加上缓存、日志记录、货币转换...
return validItems.reduce(...); // 一次涉及太多关注点
};
过于复杂、易错、难以验证 </坏>
实践中
实现功能时:
- 从最简单的可工作版本开始
- 添加一个改进(如错误处理、验证等)
- 测试并验证
- 如有时间重复
- 不要立即尝试完美
重构时:
- 一次修复一个代码味道
- 每次改进后提交
- 保持测试通过
- 当“足够好”时停止(收益递减)
代码审查时:
- 建议增量改进(而非重写)
- 优先:关键 → 重要 → 有则更好
- 首先关注高影响变更
- 接受“比之前好”,即使不完美
2. Poka-Yoke(防错)
设计在编译/设计时防止错误的系统,而非运行时。
原则
使错误不可能发生:
- 类型系统捕获错误
- 编译器强制执行契约
- 无效状态不可表示
- 错误尽早捕获(在生产前)
为安全设计:
- 快速失败并大声报错
- 提供有用的错误信息
- 使正确路径明显
- 使错误路径困难
多层防御:
- 类型系统(编译时)
- 验证(运行时、早期)
- 守卫(前置条件)
- 错误边界(优雅降级)
类型系统防错
<好>
// 错误:字符串状态可以是任何值
type OrderBad = {
status: string; // 可以是“pending”、“PENDING”、“pnding”,任何值!
total: number;
};
// 好:只有有效状态可能
type OrderStatus = 'pending' | 'processing' | 'shipped' | 'delivered';
type Order = {
status: OrderStatus;
total: number;
};
// 更好:带相关数据的状态
type Order =
| { status: 'pending'; createdAt: Date }
| { status: 'processing'; startedAt: Date; estimatedCompletion: Date }
| { status: 'shipped'; trackingNumber: string; shippedAt: Date }
| { status: 'delivered'; deliveredAt: Date; signature: string };
// 现在不可能有发货没有跟踪号
类型系统防止整类错误 </好>
<好>
// 使无效状态不可表示
type NonEmptyArray<T> = [T, ...T[]];
const firstItem = <T>(items: NonEmptyArray<T>): T => {
return items[0]; // 总是安全,永远不会未定义!
};
// 调用者必须证明数组非空
const items: number[] = [1, 2, 3];
if (items.length > 0) {
firstItem(items as NonEmptyArray<number>); // 安全
}
函数签名保证安全 </好>
验证防错
<好>
// 错误:使用后验证
const processPayment = (amount: number) => {
const fee = amount * 0.03; // 验证前使用!
if (amount <= 0) throw new Error('无效金额');
// ...
};
// 好:立即验证
const processPayment = (amount: number) => {
if (amount <= 0) {
throw new Error('支付金额必须为正数');
}
if (amount > 10000) {
throw new Error('支付超过允许最大值');
}
const fee = amount * 0.03;
// ... 现在使用安全
};
// 更好:边界验证与品牌类型
type PositiveNumber = number & { readonly __brand: 'PositiveNumber' };
const validatePositive = (n: number): PositiveNumber => {
if (n <= 0) throw new Error('必须为正数');
return n as PositiveNumber;
};
const processPayment = (amount: PositiveNumber) => {
// amount 保证为正数,无需检查
const fee = amount * 0.03;
};
// 在系统边界验证
const handlePaymentRequest = (req: Request) => {
const amount = validatePositive(req.body.amount); // 验证一次
processPayment(amount); // 处处安全使用
};
在边界验证一次,其他处安全 </好>
守卫和前置条件
<好>
// 提前返回防止深度嵌套代码
const processUser = (user: User | null) => {
if (!user) {
logger.error('用户未找到');
return;
}
if (!user.email) {
logger.error('用户邮箱缺失');
return;
}
if (!user.isActive) {
logger.info('用户不活跃,跳过');
return;
}
// 主要逻辑在此,保证用户有效且活跃
sendEmail(user.email, '欢迎!');
};
守卫使假设明确并强制执行 </好>
配置防错
<好>
// 错误:可选配置与不安全默认值
type ConfigBad = {
apiKey?: string;
timeout?: number;
};
const client = new APIClient({ timeout: 5000 }); // apiKey缺失!
// 好:必需配置,早期失败
type Config = {
apiKey: string;
timeout: number;
};
const loadConfig = (): Config => {
const apiKey = process.env.API_KEY;
if (!apiKey) {
throw new Error('需要API_KEY环境变量');
}
return {
apiKey,
timeout: 5000,
};
};
// 如果配置无效,应用在启动时失败,而非请求期间
const config = loadConfig();
const client = new APIClient(config);
在启动时失败,非生产环境 </好>
实践中
设计API时:
- 使用类型约束输入
- 使无效状态不可表示
- 返回Result<T, E>而非抛出
- 在类型中文档前置条件
处理错误时:
- 在系统边界验证
- 使用守卫处理前置条件
- 快速失败并清晰报错
- 记录上下文供调试
配置时:
- 必需而非可选带默认值
- 启动时验证所有配置
- 如果配置无效,部署失败
- 不允许部分配置
3. 标准化工作
遵循已建立的模式。文档化有效方法。使良好实践易于遵循。
原则
一致性优于聪明:
- 遵循现有代码库模式
- 不要重新发明已解决的问题
- 新模式仅在显著更好时使用
- 团队同意新模式
文档随代码共存:
- README用于设置和架构
- CLAUDE.md用于AI编码约定
- 注释解释“为什么”,而非“是什么”
- 示例用于复杂模式
自动化标准:
- 代码检查器强制执行风格
- 类型检查强制执行契约
- 测试验证行为
- CI/CD强制执行质量门
遵循模式
<好>
// 现有代码库API客户端模式
class UserAPIClient {
async getUser(id: string): Promise<User> {
return this.fetch(`/users/${id}`);
}
}
// 新代码遵循相同模式
class OrderAPIClient {
async getOrder(id: string): Promise<Order> {
return this.fetch(`/orders/${id}`);
}
}
一致性使代码库可预测 </好>
<坏>
// 现有模式使用类
class UserAPIClient { /* ... */ }
// 新代码引入不同模式未讨论
const getOrder = async (id: string): Promise<Order> => {
// 打破一致性“因为我偏好函数”
};
不一致性造成混淆 </坏>
错误处理模式
<好>
// 项目标准:Result类型用于可恢复错误
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };
// 所有服务遵循此模式
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('用户未找到') };
}
return { ok: true, value: user };
} catch (err) {
return { ok: false, error: err as Error };
}
};
// 调用者使用一致模式
const result = await fetchUser('123');
if (!result.ok) {
logger.error('获取用户失败', result.error);
return;
}
const user = result.value; // 类型安全!
代码库间标准模式 </好>
文档标准
<好>
/**
* 使用指数退避重试异步操作。
*
* 为什么:网络请求可能暂时失败;重试提高可靠性
* 何时使用:外部API调用、数据库操作
* 何时不使用:用户输入验证、内部函数调用
*
* @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> => {
// 实现...
};
文档化为什么、何时和如何 </好>
实践中
添加新模式前:
- 搜索代码库类似已解决问题
- 检查CLAUDE.md了解项目约定
- 如果打破模式与团队讨论
- 引入新模式时更新文档
编写代码时:
- 匹配现有文件结构
- 使用相同命名约定
- 遵循相同错误处理方法
- 从相同位置导入
审查时:
- 检查与现有代码一致性
- 指向代码库示例
- 建议对齐标准
- 如果新标准出现,更新CLAUDE.md
4. 及时生产(JIT)
构建当前所需内容。不多,不少。避免过早优化和过度工程。
原则
YAGNI(你不会需要它):
- 仅实现当前需求
- 无“以防万一”功能
- 无“我们以后可能需要这个”代码
- 删除推测
最简单的可工作方案:
- 从直接解决方案开始
- 仅当需要时添加复杂性
- 需求变更时重构
- 不预见未来需求
测量后优化:
- 无过早优化
- 优化前分析性能
- 测量变更影响
- 接受“足够好”性能
YAGNI实战
<好>
// 当前需求:记录错误到控制台
const logError = (error: Error) => {
console.error(error.message);
};
简单,满足当前需求 </好>
<坏>
// 为“未来需求”过度工程化
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行代码用于“可能我们需要它”
}
const logError = (error: Error) => {
Logger.getInstance().log('error', error.message);
};
为想象中的未来需求构建 </坏>
何时添加复杂性:
- 当前需求要求它
- 通过使用识别痛点
- 测量的性能问题
- 多个用例出现
<好>
// 从简单开始
const formatCurrency = (amount: number): string => {
return `$${amount.toFixed(2)}`;
};
// 需求演进:支持多货币
const formatCurrency = (amount: number, currency: string): string => {
const symbols = { USD: '$', EUR: '€', GBP: '£' };
return `${symbols[currency]}${amount.toFixed(2)}`;
};
// 需求演进:支持本地化
const formatCurrency = (amount: number, locale: string): string => {
return new Intl.NumberFormat(locale, {
style: 'currency',
currency: locale === 'en-US' ? 'USD' : 'EUR',
}).format(amount);
};
复杂性仅当需要时添加 </好>
过早抽象
<坏>
// 一个用例,但构建通用框架
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行*/ }
class QueryBuilder<T> { /*200行*/ }
// ... 为单个表构建整个ORM
为不确定未来构建巨大抽象 </坏>
<好>
// 当前需求的简单函数
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]);
};
// 当模式在多个实体出现后,再抽象
仅在模式证明跨越3+案例后抽象 </好>
性能优化
<好>
// 当前:简单方法
const filterActiveUsers = (users: User[]): User[] => {
return users.filter(user => user.isActive);
};
// 基准测试显示:1000用户50ms(可接受)
// ✓ 发布,无需优化
// 之后:分析显示此为瓶颈
// 然后通过索引查找或缓存优化
基于测量优化,而非假设 </好>
<坏>
// 过早优化
const filterActiveUsers = (users: User[]): User[] => {
// “这可能慢,所以缓存和索引”
const cache = new WeakMap();
const indexed = buildBTreeIndex(users, 'isActive');
// 100行优化代码
// 增加复杂性,更难维护
// 无证据表明需要
};
为未测量问题提供复杂方案 </坏>
实践中
实现时:
- 解决立即问题
- 使用直接方法
- 抵抗“如果”思维
- 删除推测性代码
优化时:
- 先分析后优化
- 测量前后
- 文档化为何需要优化
- 测试中保留简单版本
抽象时:
- 等待3+相似案例(三规则)
- 使抽象尽可能简单
- 偏好重复而非错误抽象
- 当模式清晰时重构
与命令集成
Kaizen技能指导工作方式。命令提供结构化分析:
/why:根本原因分析(5 Whys)/cause-and-effect:多因素分析(鱼骨图)/plan-do-check-act:迭代改进周期(PDCA)/analyse-problem:全面文档化(A3报告)/analyse:智能方法选择(现场观察/价值流图/浪费)
使用命令进行结构化问题解决。应用技能进行日常开发。
警示标志
违反持续改进:
- “我稍后重构它”(从未发生)
- 留下比发现时更差的代码
- 大爆炸重写而非增量
违反防错:
- “用户应该小心”
- 使用后验证而非前
- 无验证的可选配置
违反标准化工作:
- “我偏好我的方式”
- 不检查现有模式
- 忽略项目约定
违反及时生产:
- “我们可能有一天需要这个”
- 使用前构建框架
- 无测量优化
记住
Kaizen是关于:
- 小而持续的改进
- 通过设计预防错误
- 遵循已验证模式
- 仅构建所需
不是关于:
- 第一次尝试完美
- 大规模重构项目
- 巧妙抽象
- 过早优化
心态: 今天足够好,明天更好。重复。