Loading...
Loading...
Compare original and translation side by side
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的模型无关、流程驱动的技能。
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?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?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 depth1. 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// 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';
}// 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);
}// 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';
}// 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);
}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?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?| 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 |
| 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 |
| 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行以上代码 | 提取为公共函数 |
| 死代码 | 不可达分支、未使用变量、被注释的代码块 | 确认确实无用后删除 |
| 不必要的抽象 | 没有提供任何价值的包装层 | 内联包装层,直接调用底层函数 |
| 过度设计的模式 | 为工厂再建工厂、只有一个实现的策略模式 | 替换为简单直接的实现方式 |
| 冗余类型断言 | 转换为已经被推断出的类型 | 移除类型断言 |
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 reconsiderFOR 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 reconsiderCOMPARE 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?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?// 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;
}// 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;
}undefinedundefinedundefinedundefined// 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.// 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.| 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——应用切斯特顿围栏原则。但累积的复杂度往往没有理由,只是赶工迭代留下的残渣。 |
| "我加功能的时候顺便重构" | 把重构和功能开发分开。混合改动更难评审、更难回滚、也更难在历史记录中理解。 |