clean-code
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseClean Code
Clean Code(整洁代码)
This skill covers writing code that is easy to read and change, and — just as important — avoiding the over-engineering that makes code harder to read and change in the name of "best practices." Both halves matter together: clean code is simple code, not merely well-decorated code.
本 skill 涵盖如何编写易于阅读和修改的代码,以及同样重要的——避免以“最佳实践”之名进行过度工程,使代码变得更难阅读和修改。两者必须结合:整洁代码就是简单代码,而不只是装饰良好的代码。
Workflow for Writing or Reviewing Code
编写或审查代码的工作流程
- Scope the change — Identify exactly what was asked for. Note what's out of scope before writing anything.
- Reach for the simplest solution first — Prefer the direct, obvious implementation over a general or configurable one, unless a concrete current need justifies more.
- Name things for their purpose — Choose names that reveal intent before writing the body of a function or the shape of a type.
- Keep functions single-purpose — If a function needs a comment to explain what it does, split it.
- Remove duplication deliberately — Extract shared logic only once it's actually duplicated (see Rule of Three below), not preemptively.
- Write or update tests — Cover the new behavior and the edge cases it introduces.
- Verify scope before delivery — Confirm only the requested code changed, check for a simpler approach you might have missed, and confirm no unrequested files were touched.
- 界定变更范围——准确识别所提出的要求。开始编写任何内容之前,先记录不属于范围的事项。
- 优先采用最简单的解决方案——除非存在明确的当前需求作为理由,否则应优先选择直接、显而易见的实现,而不是通用或可配置的实现。
- 按用途命名——在编写函数体或定义类型结构之前,选择能够清晰表达意图的名称。
- 让函数保持单一用途——如果需要通过注释才能解释函数的作用,就应将其拆分。
- 有意识地消除重复——只有在共享逻辑确实出现重复后才提取(参见下方的“三次法则”),不要提前抽象。
- 编写或更新测试——覆盖新行为及其引入的边界情况。
- 交付前验证范围——确认仅修改了所请求的代码,检查是否遗漏了更简单的方案,并确认没有改动未请求的文件。
Meaningful Names
有意义的命名
- Variables, functions, and classes should reveal their purpose from the name alone.
- Names should explain why something exists and how it's used, not just its type or contents (, not
activeUserIds).list1 - Avoid abbreviations unless they're universally understood in the domain (,
id— fine;url— not fine).usrCfgTmp
- 变量、函数和类应当仅凭名称就能揭示其用途。
- 名称应说明事物为何存在以及如何使用,而不只是描述其类型或内容(使用 ,而不是
activeUserIds)。list1 - 除非缩写在所属领域中已被普遍理解,否则应避免使用缩写(、
id没问题;url则不合适)。usrCfgTmp
Constants Over Magic Numbers
常量优于魔法数字
- Replace hard-coded values with named constants (, not a bare
MAX_RETRY_COUNT = 3three call sites later).3 - Use descriptive constant names that explain the value's purpose, not just its value.
- Keep constants at the top of the file or in a dedicated constants module when shared across files.
- 将硬编码值替换为具名常量(使用 ,而不是在三处调用点中使用裸
MAX_RETRY_COUNT = 3)。3 - 使用能够说明值之用途的描述性常量名称,而不只是描述其数值。
- 对于跨文件共享的常量,将其放在文件顶部或专用的 constants 模块中。
Smart Comments
智能注释
- Don't comment on what the code does — make the code self-documenting through naming and structure instead.
- Use comments to explain why something is done a certain way, especially when the reason isn't visible in the code (a workaround for a library bug, a non-obvious ordering requirement).
- Document public APIs, genuinely complex algorithms, and non-obvious side effects.
- 不要注释代码做了什么——应通过命名和结构让代码具备自我说明能力。
- 使用注释解释为什么以某种方式完成某项操作,尤其是在代码中无法直接看出原因时(例如规避 library bug,或满足不明显的使用顺序要求)。
- 为公共 API、真正复杂的算法和不明显的副作用编写文档。
Single Responsibility
单一职责
- Each function should do exactly one thing.
- Functions should be small and focused enough to be understood without scrolling.
- If a function needs a comment to explain what it does, that's a signal to split it into named sub-functions instead.
- 每个函数应当只做一件事。
- 函数应保持小巧且聚焦,无需滚动页面即可理解。
- 如果需要通过注释才能解释函数的作用,就应将其拆分为具名的子函数。
DRY — Don't Repeat Yourself
DRY——不要重复自己(Don't Repeat Yourself)
- Extract repeated code into reusable functions once the repetition is real, not anticipated.
- Share common logic through a proper abstraction — a shared function or module, not copy-paste with tweaks.
- Maintain a single source of truth for any given piece of business logic or configuration value.
- 只有在重复真实发生之后,而不是提前预判其可能发生时,才将重复代码提取为可复用函数。
- 通过恰当的抽象共享公共逻辑——使用共享函数或 module,而不是稍作修改后复制粘贴。
- 对于任何给定的业务逻辑或配置值,应维护单一事实来源。
Encapsulation
封装
- Hide implementation details behind a clear interface; callers shouldn't need to know how a thing works to use it.
- Move nested conditionals into well-named functions or guard clauses instead of deep /
iftrees.else
js
// Before
function canCheckout(cart) {
if (cart.items.length > 0) {
if (cart.user.isVerified) {
if (cart.total <= cart.user.creditLimit) {
return true;
}
}
}
return false;
}
// After
function canCheckout(cart) {
const hasItems = cart.items.length > 0;
const isWithinCreditLimit = cart.total <= cart.user.creditLimit;
return hasItems && cart.user.isVerified && isWithinCreditLimit;
}- 将实现细节隐藏在清晰的 interface 之后;调用者不应需要了解其内部工作方式才能使用。
- 将嵌套条件逻辑移入命名清晰的函数或 guard clause,而不是形成深层的 /
if树。else
js
// Before
function canCheckout(cart) {
if (cart.items.length > 0) {
if (cart.user.isVerified) {
if (cart.total <= cart.user.creditLimit) {
return true;
}
}
}
return false;
}
// After
function canCheckout(cart) {
const hasItems = cart.items.length > 0;
const isWithinCreditLimit = cart.total <= cart.user.creditLimit;
return hasItems && cart.user.isVerified && isWithinCreditLimit;
}Clean Structure
整洁的结构
- Keep related code together (a feature's components, hooks, and styles in one directory, not scattered by file type).
- Organize code in a logical hierarchy that mirrors how the domain is understood.
- Use consistent file and folder naming conventions across the codebase.
- 将相关代码放在一起(某个功能的组件、hooks 和样式放在同一目录中,而不是按文件类型分散放置)。
- 按照与领域理解方式相呼应的逻辑层级组织代码。
- 在整个 codebase 中使用一致的文件和文件夹命名约定。
Avoiding Over-Engineering
避免过度工程
- Only change what was asked. The simplest solution that satisfies the request comes first.
- When the right level of abstraction is unclear, ask rather than guessing toward the more elaborate option.
- Do not modify unrequested code, even if it looks improvable — a drive-by refactor in an unrelated function expands the review surface and the risk of the change.
- Do not add abstractions (interfaces, factories, plugin systems, config layers) without a concrete, current need. A single implementation doesn't need an interface "in case" a second one shows up later — that's speculative generality (YAGNI: "You Aren't Gonna Need It").
- Do not import a new dependency to solve a problem a few lines of existing code already solve.
- Do not rewrite entire files for small changes — a targeted diff is easier to review and safer to ship than a full-file rewrite.
- Do not add error handling for scenarios that cannot occur given the surrounding code's guarantees — defensive code for impossible states adds reading cost without adding safety.
- 只修改所请求的内容。能够满足需求的简单方案始终优先。
- 当无法确定恰当的抽象层级时,应主动询问,而不是猜测并选择更复杂的方案。
- 不要修改未请求的代码,即使它看起来可以改进——在无关函数中进行顺手重构会扩大审查范围并增加变更风险。
- 不要在没有明确的当前需求时添加抽象(interface、factory、plugin system、配置层)。单一实现不需要为了“万一以后出现第二种实现”而预先创建 interface;这属于推测性通用设计(YAGNI:“你不会需要它”)。
- 不要为了解决几行现有代码即可处理的问题而引入新 dependency。
- 不要为小改动重写整个文件——有针对性的 diff 比完整重写文件更容易审查,也更安全地交付。
- 不要为周围代码所保证不会发生的场景添加错误处理——针对不可能状态的防御性代码只会增加阅读成本,无法提升安全性。
Rule of Three
三次法则(Rule of Three)
- Tolerate duplication the first two times a pattern appears.
- Extract an abstraction on the third occurrence, once the actual shape of the shared logic is clear — extracting after one or two instances often guesses wrong about what's actually shared.
- 某种模式在前两次出现时,可以容忍重复。
- 在第三次出现时提取抽象,此时共享逻辑的实际结构已经清晰——在一两个实例之后就提取,往往会错误判断究竟哪些内容是共享的。
Signs of Over-Engineering
过度工程的迹象
- A configuration option that has only ever been set to one value.
- An interface with exactly one implementation and no test double that needs a second.
- A generic object accreting fields for hypothetical future callers.
options - A plugin/strategy pattern introduced before there are two strategies to switch between.
- 某个配置选项始终只会被设置为同一个值。
- 某个 interface 恰好只有一个实现,并且没有需要第二种实现的 test double。
- 通用 对象不断为假设中的未来调用者添加字段。
options - 在尚不存在两种可切换策略之前,就引入 plugin/strategy 模式。
Code Quality Maintenance
代码质量维护
- Refactor continuously in small steps rather than deferring cleanup to a dedicated "refactor sprint."
- Fix technical debt early, while the context for why the code looks the way it does is still fresh.
- Leave code cleaner than you found it, scoped to the area you're already touching — not as license to refactor unrelated files.
- 持续以小步骤重构,而不是将清理工作推迟到专门的“重构冲刺”。
- 及早修复技术债务,趁代码为何呈现当前状态仍然清晰时进行处理。
- 让代码比发现时更加整洁,但范围仅限于正在修改的区域——这并不意味着可以重构无关文件。
Testing
测试
- Write a failing test before fixing a bug, so the fix is verified and the bug can't silently regress.
- Keep tests readable and maintainable — a test that's harder to understand than the code it tests has failed at its job.
- Test edge cases and error conditions explicitly, not just the happy path.
- 修复 bug 前先编写失败的测试,以验证修复并防止 bug 悄然回归。
- 保持测试可读且易于维护——如果测试比它所测试的代码更难理解,就说明测试没有发挥应有作用。
- 明确测试边界情况和错误条件,而不只是测试正常执行路径。
Version Control
版本控制
- Write clear, specific commit messages that explain why a change was made.
- Make small, focused commits — one logical change per commit.
- Use meaningful branch names that describe the work, not the author or the date.
- 编写清晰、具体的 commit message,说明进行变更的原因。
- 使用小巧、聚焦的 commit——每个 commit 包含一项逻辑变更。
- 使用能够描述工作的有意义分支名称,而不是作者姓名或日期。
Before Delivery Checklist
交付前检查清单
- Only the requested code changed — no unrelated files touched.
- No abstraction was added without a concrete need that exists today.
- No dependency was added that duplicates something already available.
- A simpler approach was considered and ruled out, not just skipped.
- New behavior has test coverage, including at least one edge case.
- 仅修改了所请求的代码——没有改动无关文件。
- 没有在缺乏今天确实存在的具体需求时添加抽象。
- 没有添加与现有能力重复的 dependency。
- 已考虑更简单的方案并说明将其排除的原因,而不是直接跳过。
- 新行为已有测试覆盖,包括至少一个边界情况。