code-simplification
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCode Simplification
代码简化
Inspired by the Claude Code Simplifier plugin. Adapted here as a model-agnostic, process-driven skill for any AI coding agent.
灵感来源于 Claude Code Simplifier plugin,此处适配为可用于任意AI编码Agent的模型无关、流程驱动的技能。
Overview
概述
Simplify code by reducing complexity while preserving exact behavior. The goal is not fewer lines — it's code that is easier to read, understand, modify, and debug. Every simplification must pass a simple test: "Would a new team member understand this faster than the original?"
在完全保留代码行为的前提下通过降低复杂度来简化代码。我们的目标不是减少代码行数,而是让代码更易读、易懂、易修改、易调试。每一处简化都需要通过一个简单的测试:"新的团队成员能比读原版代码更快理解这段代码吗?"
When to Use
适用场景
- After a feature is working and tests pass, but the implementation feels heavier than it needs to be
- During code review when readability or complexity issues are flagged
- When you encounter deeply nested logic, long functions, or unclear names
- When refactoring code written under time pressure
- When consolidating related logic scattered across files
- After merging changes that introduced duplication or inconsistency
When NOT to use:
- Code is already clean and readable — don't simplify for the sake of it
- You don't understand what the code does yet — comprehend before you simplify
- The code is performance-critical and the "simpler" version would be measurably slower
- You're about to rewrite the module entirely — simplifying throwaway code wastes effort
- 功能已开发完成且测试通过,但实现逻辑比必要的更繁重
- 代码评审过程中发现了可读性或复杂度问题
- 遇到深度嵌套的逻辑、过长的函数或者表意不明的命名
- 重构赶工完成的代码
- 整合散落在多个文件中的相关逻辑
- 合并了引入重复代码或不一致性的变更之后
不适用场景:
- 代码已经足够整洁可读——不要为了简化而简化
- 你还没理解代码的功能——先搞懂再简化
- 代码是性能关键型的,所谓的"更简单"版本运行速度会明显更慢
- 你正打算完全重写这个模块——简化即将废弃的代码是浪费精力
The Five Principles
五大原则
1. Preserve Behavior Exactly
1. 完全保留代码行为
Don't change what the code does — only how it expresses it. All inputs, outputs, side effects, error behavior, and edge cases must remain identical. If you're not sure a simplification preserves behavior, don't make it.
ASK BEFORE EVERY CHANGE:
→ Does this produce the same output for every input?
→ Does this maintain the same error behavior?
→ Does this preserve the same side effects and ordering?
→ Do all existing tests still pass without modification?不要改变代码的功能——只改变代码的表达形式。所有输入、输出、副作用、错误行为、边界 case 都必须保持完全一致。如果你不确定某一处简化是否会改变代码行为,就不要做这个改动。
ASK BEFORE EVERY CHANGE:
→ Does this produce the same output for every input?
→ Does this maintain the same error behavior?
→ Does this preserve the same side effects and ordering?
→ Do all existing tests still pass without modification?2. Follow Project Conventions
2. 遵循项目规范
Simplification means making code more consistent with the codebase, not imposing external preferences. Before simplifying:
1. Read CLAUDE.md / project conventions
2. Study how neighboring code handles similar patterns
3. Match the project's style for:
- Import ordering and module system
- Function declaration style
- Naming conventions
- Error handling patterns
- Type annotation depthSimplification that breaks project consistency is not simplification — it's churn.
简化意味着让代码和代码库的其余部分更一致,而不是强加外部的偏好。简化前:
1. Read CLAUDE.md / project conventions
2. Study how neighboring code handles similar patterns
3. Match the project's style for:
- Import ordering and module system
- Function declaration style
- Naming conventions
- Error handling patterns
- Type annotation depth破坏项目一致性的简化不是简化,而是无效改动。
3. Prefer Clarity Over Cleverness
3. 清晰优先于巧妙
Explicit code is better than compact code when the compact version requires a mental pause to parse.
typescript
// UNCLEAR: Dense ternary chain
const label = isNew ? 'New' : isUpdated ? 'Updated' : isArchived ? 'Archived' : 'Active';
// CLEAR: Readable mapping
function getStatusLabel(item: Item): string {
if (item.isNew) return 'New';
if (item.isUpdated) return 'Updated';
if (item.isArchived) return 'Archived';
return 'Active';
}typescript
// UNCLEAR: Chained reduces with inline logic
const result = items.reduce((acc, item) => ({
...acc,
[item.id]: { ...acc[item.id], count: (acc[item.id]?.count ?? 0) + 1 }
}), {});
// CLEAR: Named intermediate step
const countById = new Map<string, number>();
for (const item of items) {
countById.set(item.id, (countById.get(item.id) ?? 0) + 1);
}如果简洁版本的代码需要停顿思考才能读懂,那么显式代码优于简洁代码。
typescript
// UNCLEAR: Dense ternary chain
const label = isNew ? 'New' : isUpdated ? 'Updated' : isArchived ? 'Archived' : 'Active';
// CLEAR: Readable mapping
function getStatusLabel(item: Item): string {
if (item.isNew) return 'New';
if (item.isUpdated) return 'Updated';
if (item.isArchived) return 'Archived';
return 'Active';
}typescript
// UNCLEAR: Chained reduces with inline logic
const result = items.reduce((acc, item) => ({
...acc,
[item.id]: { ...acc[item.id], count: (acc[item.id]?.count ?? 0) + 1 }
}), {});
// CLEAR: Named intermediate step
const countById = new Map<string, number>();
for (const item of items) {
countById.set(item.id, (countById.get(item.id) ?? 0) + 1);
}4. Maintain Balance
4. 保持平衡
Simplification has a failure mode: over-simplification. Watch for these traps:
- Inlining too aggressively — removing a helper that gave a concept a name makes the call site harder to read
- Combining unrelated logic — two simple functions merged into one complex function is not simpler
- Removing "unnecessary" abstraction — some abstractions exist for extensibility or testability, not complexity
- Optimizing for line count — fewer lines is not the goal; easier comprehension is
简化有一个失败模式:过度简化。注意避免以下陷阱:
- 过度激进的内联——移除了用来给概念命名的辅助函数会让调用位置更难读
- 合并无关逻辑——把两个简单函数合并成一个复杂函数并不会更简单
- 移除"不必要"的抽象——有些抽象是为了扩展性或可测试性存在的,不是为了增加复杂度
- 追求代码行数最少——更少的行数不是目标,更容易理解才是
5. Scope to What Changed
5. 限定改动范围
Default to simplifying recently modified code. Avoid drive-by refactors of unrelated code unless explicitly asked to broaden scope. Unscoped simplification creates noise in diffs and risks unintended regressions.
默认只简化最近修改过的代码。除非明确要求扩大范围,否则不要随意重构无关代码。无范围限制的简化会在diff中产生噪音,还会带来意外回归的风险。
The Simplification Process
简化流程
Step 1: Understand Before Touching (Chesterton's Fence)
步骤1:改动前先理解(切斯特顿围栏原则)
Before changing or removing anything, understand why it exists. This is Chesterton's Fence: if you see a fence across a road and don't understand why it's there, don't tear it down. First understand the reason, then decide if the reason still applies.
BEFORE SIMPLIFYING, ANSWER:
- What is this code's responsibility?
- What calls it? What does it call?
- What are the edge cases and error paths?
- Are there tests that define the expected behavior?
- Why might it have been written this way? (Performance? Platform constraint? Historical reason?)
- Check git blame: what was the original context for this code?If you can't answer these, you're not ready to simplify. Read more context first.
在修改或删除任何内容之前,先理解它为什么存在。这就是切斯特顿围栏原则:如果你看到路中间有一道围栏,却不知道它为什么存在,不要直接把它拆掉。先搞懂存在的原因,再判断这个原因是否还成立。
BEFORE SIMPLIFYING, ANSWER:
- What is this code's responsibility?
- What calls it? What does it call?
- What are the edge cases and error paths?
- Are there tests that define the expected behavior?
- Why might it have been written this way? (Performance? Platform constraint? Historical reason?)
- Check git blame: what was the original context for this code?如果你回答不了这些问题,说明你还没做好简化的准备,先去了解更多上下文。
Step 2: Identify Simplification Opportunities
步骤2:识别简化机会
Scan for these patterns — each one is a concrete signal, not a vague smell:
Structural complexity:
| Pattern | Signal | Simplification |
|---|---|---|
| Deep nesting (3+ levels) | Hard to follow control flow | Extract conditions into guard clauses or helper functions |
| Long functions (50+ lines) | Multiple responsibilities | Split into focused functions with descriptive names |
| Nested ternaries | Requires mental stack to parse | Replace with if/else chains, switch, or lookup objects |
| Boolean parameter flags | | Replace with options objects or separate functions |
| Repeated conditionals | Same | Extract to a well-named predicate function |
Naming and readability:
| Pattern | Signal | Simplification |
|---|---|---|
| Generic names | | Rename to describe the content: |
| Abbreviated names | | Use full words unless the abbreviation is universal ( |
| Misleading names | Function named | Rename to reflect actual behavior |
| Comments explaining "what" | | Delete the comment — the code is clear enough |
| Comments explaining "why" | | Keep these — they carry intent the code can't express |
Redundancy:
| Pattern | Signal | Simplification |
|---|---|---|
| Duplicated logic | Same 5+ lines in multiple places | Extract to a shared function |
| Dead code | Unreachable branches, unused variables, commented-out blocks | Remove (after confirming it's truly dead) |
| Unnecessary abstractions | Wrapper that adds no value | Inline the wrapper, call the underlying function directly |
| Over-engineered patterns | Factory-for-a-factory, strategy-with-one-strategy | Replace with the simple direct approach |
| Redundant type assertions | Casting to a type that's already inferred | Remove the assertion |
扫描以下模式——每一个都是具体的信号,不是模糊的坏味道:
结构复杂度:
| 模式 | 信号 | 简化方案 |
|---|---|---|
| 深度嵌套(3层及以上) | 控制流难以跟踪 | 将条件提取为守卫子句或辅助函数 |
| 过长函数(超过50行) | 承担了多个职责 | 拆分为多个命名清晰的单一职责函数 |
| 嵌套三元表达式 | 需要在脑中维护调用栈才能读懂 | 替换为if/else链、switch或查找对象 |
| 布尔参数标志 | | 替换为配置对象或独立的函数 |
| 重复条件判断 | 多个位置出现相同的 | 提取为命名清晰的谓词函数 |
命名和可读性:
| 模式 | 信号 | 简化方案 |
|---|---|---|
| 通用命名 | | 重命名为描述内容的名字: |
| 缩写命名 | | 使用完整单词,除非是通用缩写( |
| 误导性命名 | 名为 | 重命名以反映实际行为 |
| 解释"做了什么"的注释 | | 删除注释——代码本身已经足够清晰 |
| 解释"为什么这么做"的注释 | | 保留这些注释——它们承载了代码无法表达的意图 |
冗余:
| 模式 | 信号 | 简化方案 |
|---|---|---|
| 重复逻辑 | 多个位置出现相同的5行以上代码 | 提取为公共函数 |
| 死代码 | 不可达分支、未使用变量、被注释的代码块 | 确认确实无用后删除 |
| 不必要的抽象 | 没有提供任何价值的包装层 | 内联包装层,直接调用底层函数 |
| 过度设计的模式 | 为工厂再建工厂、只有一个实现的策略模式 | 替换为简单直接的实现方式 |
| 冗余类型断言 | 转换为已经被推断出的类型 | 移除类型断言 |
Step 3: Apply Changes Incrementally
步骤3:增量应用改动
Make one simplification at a time. Run tests after each change. Submit refactoring changes separately from feature or bug fix changes. A PR that refactors and adds a feature is two PRs — split them.
FOR EACH SIMPLIFICATION:
1. Make the change
2. Run the test suite
3. If tests pass → commit (or continue to next simplification)
4. If tests fail → revert and reconsiderAvoid batching multiple simplifications into a single untested change. If something breaks, you need to know which simplification caused it.
The Rule of 500: If a refactoring would touch more than 500 lines, invest in automation (codemods, sed scripts, AST transforms) rather than making the changes by hand. Manual edits at that scale are error-prone and exhausting to review.
一次只做一处简化。每次改动后都运行测试。重构改动要和功能或bug修复改动分开提交。 同时包含重构和新增功能的PR应该拆分为两个PR。
FOR EACH SIMPLIFICATION:
1. Make the change
2. Run the test suite
3. If tests pass → commit (or continue to next simplification)
4. If tests fail → revert and reconsider不要把多个简化合并成一个未测试的批量改动。如果出了问题,你需要知道是哪一处简化导致的。
500行规则: 如果一次重构要修改超过500行代码,优先使用自动化工具(codemods、sed脚本、AST转换),不要手动修改。这种规模的手动修改容易出错,评审也非常消耗精力。
Step 4: Verify the Result
步骤4:验证结果
After all simplifications, step back and evaluate the whole:
COMPARE BEFORE AND AFTER:
- Is the simplified version genuinely easier to understand?
- Did you introduce any new patterns inconsistent with the codebase?
- Is the diff clean and reviewable?
- Would a teammate approve this change?If the "simplified" version is harder to understand or review, revert. Not every simplification attempt succeeds.
所有简化完成后,退一步整体评估:
COMPARE BEFORE AND AFTER:
- Is the simplified version genuinely easier to understand?
- Did you introduce any new patterns inconsistent with the codebase?
- Is the diff clean and reviewable?
- Would a teammate approve this change?如果"简化"后的版本更难理解或评审,就回滚。不是每一次简化尝试都会成功。
Language-Specific Guidance
语言特定指导
TypeScript / JavaScript
TypeScript / JavaScript
typescript
// SIMPLIFY: Unnecessary async wrapper
// Before
async function getUser(id: string): Promise<User> {
return await userService.findById(id);
}
// After
function getUser(id: string): Promise<User> {
return userService.findById(id);
}
// SIMPLIFY: Verbose conditional assignment
// Before
let displayName: string;
if (user.nickname) {
displayName = user.nickname;
} else {
displayName = user.fullName;
}
// After
const displayName = user.nickname || user.fullName;
// SIMPLIFY: Manual array building
// Before
const activeUsers: User[] = [];
for (const user of users) {
if (user.isActive) {
activeUsers.push(user);
}
}
// After
const activeUsers = users.filter((user) => user.isActive);
// SIMPLIFY: Redundant boolean return
// Before
function isValid(input: string): boolean {
if (input.length > 0 && input.length < 100) {
return true;
}
return false;
}
// After
function isValid(input: string): boolean {
return input.length > 0 && input.length < 100;
}typescript
// SIMPLIFY: Unnecessary async wrapper
// Before
async function getUser(id: string): Promise<User> {
return await userService.findById(id);
}
// After
function getUser(id: string): Promise<User> {
return userService.findById(id);
}
// SIMPLIFY: Verbose conditional assignment
// Before
let displayName: string;
if (user.nickname) {
displayName = user.nickname;
} else {
displayName = user.fullName;
}
// After
const displayName = user.nickname || user.fullName;
// SIMPLIFY: Manual array building
// Before
const activeUsers: User[] = [];
for (const user of users) {
if (user.isActive) {
activeUsers.push(user);
}
}
// After
const activeUsers = users.filter((user) => user.isActive);
// SIMPLIFY: Redundant boolean return
// Before
function isValid(input: string): boolean {
if (input.length > 0 && input.length < 100) {
return true;
}
return false;
}
// After
function isValid(input: string): boolean {
return input.length > 0 && input.length < 100;
}Python
Python
python
undefinedpython
undefinedSIMPLIFY: Verbose dictionary building
SIMPLIFY: Verbose dictionary building
Before
Before
result = {}
for item in items:
result[item.id] = item.name
result = {}
for item in items:
result[item.id] = item.name
After
After
result = {item.id: item.name for item in items}
result = {item.id: item.name for item in items}
SIMPLIFY: Nested conditionals with early return
SIMPLIFY: Nested conditionals with early return
Before
Before
def process(data):
if data is not None:
if data.is_valid():
if data.has_permission():
return do_work(data)
else:
raise PermissionError("No permission")
else:
raise ValueError("Invalid data")
else:
raise TypeError("Data is None")
def process(data):
if data is not None:
if data.is_valid():
if data.has_permission():
return do_work(data)
else:
raise PermissionError("No permission")
else:
raise ValueError("Invalid data")
else:
raise TypeError("Data is None")
After
After
def process(data):
if data is None:
raise TypeError("Data is None")
if not data.is_valid():
raise ValueError("Invalid data")
if not data.has_permission():
raise PermissionError("No permission")
return do_work(data)
undefineddef process(data):
if data is None:
raise TypeError("Data is None")
if not data.is_valid():
raise ValueError("Invalid data")
if not data.has_permission():
raise PermissionError("No permission")
return do_work(data)
undefinedReact / JSX
React / JSX
tsx
// SIMPLIFY: Verbose conditional rendering
// Before
function UserBadge({ user }: Props) {
if (user.isAdmin) {
return <Badge variant="admin">Admin</Badge>;
} else {
return <Badge variant="default">User</Badge>;
}
}
// After
function UserBadge({ user }: Props) {
const variant = user.isAdmin ? 'admin' : 'default';
const label = user.isAdmin ? 'Admin' : 'User';
return <Badge variant={variant}>{label}</Badge>;
}
// SIMPLIFY: Prop drilling through intermediate components
// Before — consider whether context or composition solves this better.
// This is a judgment call — flag it, don't auto-refactor.tsx
// SIMPLIFY: Verbose conditional rendering
// Before
function UserBadge({ user }: Props) {
if (user.isAdmin) {
return <Badge variant="admin">Admin</Badge>;
} else {
return <Badge variant="default">User</Badge>;
}
}
// After
function UserBadge({ user }: Props) {
const variant = user.isAdmin ? 'admin' : 'default';
const label = user.isAdmin ? 'Admin' : 'User';
return <Badge variant={variant}>{label}</Badge>;
}
// SIMPLIFY: Prop drilling through intermediate components
// Before — consider whether context or composition solves this better.
// This is a judgment call — flag it, don't auto-refactor.Common Rationalizations
常见借口
| Rationalization | Reality |
|---|---|
| "It's working, no need to touch it" | Working code that's hard to read will be hard to fix when it breaks. Simplifying now saves time on every future change. |
| "Fewer lines is always simpler" | A 1-line nested ternary is not simpler than a 5-line if/else. Simplicity is about comprehension speed, not line count. |
| "I'll just quickly simplify this unrelated code too" | Unscoped simplification creates noisy diffs and risks regressions in code you didn't intend to change. Stay focused. |
| "The types make it self-documenting" | Types document structure, not intent. A well-named function explains why better than a type signature explains what. |
| "This abstraction might be useful later" | Don't preserve speculative abstractions. If it's not used now, it's complexity without value. Remove it and re-add when needed. |
| "The original author must have had a reason" | Maybe. Check git blame — apply Chesterton's Fence. But accumulated complexity often has no reason; it's just the residue of iteration under pressure. |
| "I'll refactor while adding this feature" | Separate refactoring from feature work. Mixed changes are harder to review, revert, and understand in history. |
| 借口 | 现实 |
|---|---|
| "它能正常运行,没必要动" | 难读的可运行代码出问题时也很难修。现在简化可以节省未来每次改动的时间。 |
| "代码行数越少越简单" | 一行嵌套三元表达式并不比5行if/else更简单。简单性取决于理解速度,不是代码行数。 |
| "我顺便快速简化下这段无关代码" | 无范围的简化会产生嘈杂的diff,还会给你没打算改动的代码带来回归风险。保持专注。 |
| "类型已经让代码自文档化了" | 类型只能记录结构,不能记录意图。命名良好的函数解释"为什么"的能力远胜解释"是什么"的类型签名。 |
| "这个抽象以后可能有用" | 不要保留推测性的抽象。如果现在没用,它就是没有价值的复杂度。删掉它,等需要的时候再加回来。 |
| "原作者肯定有这么写的理由" | 也许吧。查看git blame——应用切斯特顿围栏原则。但累积的复杂度往往没有理由,只是赶工迭代留下的残渣。 |
| "我加功能的时候顺便重构" | 把重构和功能开发分开。混合改动更难评审、更难回滚、也更难在历史记录中理解。 |
Red Flags
危险信号
- Simplification that requires modifying tests to pass (you likely changed behavior)
- "Simplified" code that is longer and harder to follow than the original
- Renaming things to match your preferences rather than project conventions
- Removing error handling because "it makes the code cleaner"
- Simplifying code you don't fully understand
- Batching many simplifications into one large, hard-to-review commit
- Refactoring code outside the scope of the current task without being asked
- 简化需要修改测试才能通过(你很可能改了代码行为)
- "简化"后的代码比原版更长、更难理解
- 按照个人偏好而非项目规范重命名
- 以"让代码更整洁"为由移除错误处理
- 简化你没有完全理解的代码
- 把多个简化合并成一个难以评审的大提交
- 没有被要求就重构当前任务范围外的代码
Verification
验证项
After completing a simplification pass:
- All existing tests pass without modification
- Build succeeds with no new warnings
- Linter/formatter passes (no style regressions)
- Each simplification is a reviewable, incremental change
- The diff is clean — no unrelated changes mixed in
- Simplified code follows project conventions (checked against CLAUDE.md or equivalent)
- No error handling was removed or weakened
- No dead code was left behind (unused imports, unreachable branches)
- A teammate or review agent would approve the change as a net improvement
完成一次简化流程后:
- 所有现有测试无需修改即可通过
- 构建成功,没有新的警告
- Linter/格式化工具校验通过(没有样式回归)
- 每一处简化都是可评审的增量改动
- Diff干净——没有混入无关改动
- 简化后的代码遵循项目规范(对照CLAUDE.md或等效文档检查)
- 没有移除或削弱错误处理
- 没有遗留死代码(未使用的导入、不可达分支)
- 同事或评审Agent会认可这是一次净收益的改动