npx skills add https://github.com/ratacat/claude-skills --skill clean-code整洁的代码读起来就像优美的散文。每个名称都揭示意图。每个函数都在讲述一个故事。每个类都有单一的目的。目标不仅仅是让代码运行——而是让其他人能够快速理解、安全修改和自信扩展的代码。
"整洁的代码看起来总是像是由关心代码的人编写的。" — Michael Feathers
"当你发现每个例程都基本符合你的预期时,你就知道自己在编写整洁的代码。" — Ward Cunningham
童子军规则: 让代码比你发现时更整洁。每次提交都应该提高质量,哪怕只是轻微改善。小的改进会累积起来。
本技能提供概览和快速参考。如需带示例的详细指导,请参阅章节文件:
chapters/names.md - 有意义的命名(揭示意图、可搜索、可发音)chapters/functions.md - 函数(小巧、只做一件事、参数少)chapters/comments.md - 注释(为何要避免、什么是可接受的)chapters/objects-and-data.md - 对象与数据结构(德米特法则、DTO)chapters/error-handling.md - 错误处理(异常、空值处理、特例模式)广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
chapters/tests.mdchapters/classes.md - 类(SRP、内聚性、OCP、DIP)smells-and-heuristics.md - 完整的代码异味参考(66种异味及解释)名称应揭示意图且易于搜索。
| 规则 | 差 | 好 |
|---|---|---|
| 揭示意图 | d | elapsedTimeInDays |
| 避免误导 | accountList(不是List类型) | accounts |
| 有区分度 | a1, a2 | source, destination |
| 可发音 | genymdhms | generationTimestamp |
| 可搜索 | 7 | MAX_CLASSES_PER_STUDENT |
| 类名 = 名词 | Process | Customer, Account |
| 方法名 = 动词 | data | postPayment(), save() |
避免: 在类名中使用 Manager、Processor、Data、Info——它们暗示职责不明确。
关键见解: 如果你需要注释来解释变量是什么,那就重命名它。
| 数量 | 指导原则 |
|---|---|
| 0 | 最佳 |
| 1 | 良好 |
| 2 | 可接受 |
| 3+ | 避免——封装到对象中 |
标志参数(布尔值)很丑陋。 它们表明函数做了两件事。拆分它:
# Bad
def render(is_suite: bool): ...
# Good
def render_for_suite(): ...
def render_for_single_test(): ...
checkPassword() 还初始化了会话,那就是在说谎注释充其量是一种必要的恶。注释的正确用途是弥补我们在代码中表达意图的失败。
// 默认构造函数、// 递增 i} // 结束 if 意味着嵌套太深// 需要30分钟)规则: 当你想写注释时,首先尝试重构代码,使注释变得不必要。
错误处理很重要,但如果它掩盖了逻辑,那就是错误的。
| 规则 | 详情 |
|---|---|
| 使用异常而非返回码 | 将算法与错误处理分离 |
| 提供上下文 | 包含失败的操作和失败类型 |
| 包装第三方 API | 最小化依赖,支持模拟 |
| 使用特例模式 | 返回处理特例的对象(空列表、默认值) |
| 不要返回 null | 增加工作量,引发 NullPointerException |
| 不要传递 null | 比返回 null 更糟——默认禁止它 |
# Bad - null checks everywhere
if employees is not None:
for e in employees:
total += e.pay
# Good - return empty collection instead of null
for e in get_employees(): # Returns [] if none
total += e.pay
一个类应该只有一个,且仅有一个变更的理由。
测试:
Manager、Processor、Super)方法应该使用类的实例变量。当方法围绕某些变量聚集而不使用其他变量时,应该拆分这个类。
类应该对扩展开放,对修改关闭。通过子类化添加新行为,而不是修改现有代码。
依赖抽象,而不是具体细节。注入依赖以实现可测试性。
# Bad - can't test without network
class Portfolio:
def __init__(self):
self.exchange = TokyoStockExchange()
# Good - injectable, testable
class Portfolio:
def __init__(self, exchange: StockExchange):
self.exchange = exchange
警告: 测试代码与生产代码同等重要。如果你让测试代码腐坏,你的代码也会腐坏。
| 概念 | 隐藏 | 暴露 | 易于添加... |
|---|---|---|---|
| 对象 | 数据 | 函数 | 新类型 |
| 数据结构 | 无 | 数据 | 新函数 |
一切都是对象的想法是个神话。 有时你只需要简单的数据结构和操作它们的程序。
一个方法应该只调用以下对象的方法:
不要调用允许函数返回的对象的方法(火车残骸):
# Bad
output_dir = ctxt.get_options().get_scratch_dir().get_absolute_path()
# Good - tell the object to do the work
bos = ctxt.create_scratch_file_stream(class_file_name)
来自第17章的完整列表,这些是最重要的:
软件中所有邪恶的根源。 每次重复都是错失抽象机会:
如果你能从函数中提取另一个函数,说明原函数做了不止一件事。
名称占代码可读性的90%。花时间明智选择。
零个最好,然后是一个、两个、三个。更多需要理由。
布尔参数意味着函数做了两件事。拆分它。
未执行的代码。删除它——版本控制会记住。
如果你用一种方式做某事,所有类似的事情都用相同的方式做。
令人厌恶。立即删除它。
"编写整洁的代码需要纪律性地运用无数小技巧,这些技巧通过艰苦获得的'整洁感'来应用。代码感是关键。"
整洁的代码不是机械遵循规则写出来的。它源于驱动纪律的价值观——关心技艺、尊重代码读者,并为专业工作感到自豪。
如何编写整洁的代码? 初稿是笨拙的——长函数、嵌套循环、随意命名、重复。你进行提炼:分解函数、更改名称、消除重复、缩小方法。没有人一开始就能写出整洁的代码。
让软件运行和让它整洁是两种不同的活动。我们大多数人的头脑空间有限,所以我们首先专注于让代码运行。问题是,太多人认为程序一旦运行就完成了。 我们未能切换到组织和整洁的状态。我们转向下一个问题,而不是回去将臃肿的类分解为解耦的单元。
不要这样。回去。清理它。让它比你发现时更好。
每周安装次数
162
代码仓库
GitHub 星标数
25
首次出现
2026年1月22日
安全审计
安装于
gemini-cli156
opencode156
codex155
github-copilot154
amp154
kimi-cli153
Clean code reads like well-written prose. Every name reveals intent. Every function tells a story. Every class has a single purpose. The goal isn't just working code—it's code that others can understand quickly, modify safely, and extend confidently.
"Clean code always looks like it was written by someone who cares." — Michael Feathers
"You know you are working on clean code when each routine turns out to be pretty much what you expected." — Ward Cunningham
The Boy Scout Rule: Leave the code cleaner than you found it. Every commit should improve quality, even if just slightly. Small improvements compound.
This skill provides an overview with quick references. For detailed guidance with examples, see the chapter files:
chapters/names.md - Meaningful Names (intention-revealing, searchable, pronounceable)chapters/functions.md - Functions (small, do one thing, few arguments)chapters/comments.md - Comments (why to avoid, what's acceptable)chapters/objects-and-data.md - Objects and Data Structures (Law of Demeter, DTOs)chapters/error-handling.md - Error Handling (exceptions, null handling, Special Case Pattern)chapters/tests.md - Unit Tests (TDD, F.I.R.S.T., clean tests)chapters/classes.md - Classes (SRP, cohesion, OCP, DIP)smells-and-heuristics.md - Complete code smells reference (66 smells with explanations)Names should reveal intent and be searchable.
| Rule | Bad | Good |
|---|---|---|
| Reveal intent | d | elapsedTimeInDays |
| Avoid disinformation | accountList (not a List) | accounts |
| Make distinctions | a1, a2 | source, destination |
| Pronounceable | genymdhms |
Avoid: Manager, Processor, Data, Info in class names—they hint at unclear responsibilities.
Key insight: If you need a comment to explain what a variable is, rename it instead.
| Count | Guidance |
|---|---|
| 0 | Best |
| 1 | Good |
| 2 | Acceptable |
| 3+ | Avoid—wrap in object |
Flag arguments (booleans) are ugly. They proclaim the function does two things. Split it:
# Bad
def render(is_suite: bool): ...
# Good
def render_for_suite(): ...
def render_for_single_test(): ...
checkPassword() also initializes a session, it liesComments are, at best, a necessary evil. The proper use of comments is to compensate for our failure to express ourselves in code.
// default constructor, // increment i} // end if means too much nesting// takes 30 minutes)The Rule: When you feel the urge to comment, first try to refactor the code so the comment would be unnecessary.
Error handling is important, but if it obscures logic, it's wrong.
| Rule | Details |
|---|---|
| Use exceptions over return codes | Separates algorithm from error handling |
| Provide context | Include operation that failed and type of failure |
| Wrap third-party APIs | Minimizes dependencies, enables mocking |
| Use Special Case Pattern | Return object that handles special case (empty list, default values) |
| Don't return null | Creates work, invites NullPointerException |
| Don't pass null | Worse than returning null—forbid it by default |
# Bad - null checks everywhere
if employees is not None:
for e in employees:
total += e.pay
# Good - return empty collection instead of null
for e in get_employees(): # Returns [] if none
total += e.pay
A class should have one, and only one, reason to change.
Tests:
Manager, Processor, Super)Methods should use the class's instance variables. When methods cluster around certain variables but not others, the class should be split.
Classes should be open for extension but closed for modification. Add new behavior via subclassing, not modifying existing code.
Depend on abstractions, not concrete details. Inject dependencies for testability.
# Bad - can't test without network
class Portfolio:
def __init__(self):
self.exchange = TokyoStockExchange()
# Good - injectable, testable
class Portfolio:
def __init__(self, exchange: StockExchange):
self.exchange = exchange
Warning: Test code is just as important as production code. If you let tests rot, your code will rot too.
| Concept | Hides | Exposes | Easy to add... |
|---|---|---|---|
| Objects | Data | Functions | New types |
| Data Structures | Nothing | Data | New functions |
The idea that everything is an object is a myth. Sometimes you want simple data structures with procedures operating on them.
A method should only call methods of:
Don't call methods on objects returned by allowed functions (train wrecks):
# Bad
output_dir = ctxt.get_options().get_scratch_dir().get_absolute_path()
# Good - tell the object to do the work
bos = ctxt.create_scratch_file_stream(class_file_name)
From Chapter 17's comprehensive list, these are the most important:
The root of all evil in software. Every duplication is a missed abstraction opportunity:
If you can extract another function from it, the original was doing more than one thing.
Names are 90% of what makes code readable. Take time to choose wisely.
Zero is best, then one, two, three. More requires justification.
Boolean parameters mean the function does two things. Split it.
Code that isn't executed. Delete it—version control remembers.
If you do something one way, do all similar things the same way.
An abomination. Delete it immediately.
"Writing clean code requires the disciplined use of a myriad little techniques applied through a painstakingly acquired sense of 'cleanliness.' The code-sense is the key."
Clean code isn't written by following rules mechanically. It comes from values that drive disciplines—caring about craft, respecting readers of your code, and taking pride in professional work.
How do you write clean code? First drafts are clumsy—long functions, nested loops, arbitrary names, duplication. You refine: break out functions, change names, eliminate duplication, shrink methods. Nobody writes clean code from the start.
Getting software to work and making it clean are different activities. Most of us have limited room in our heads, so we focus on getting code to work first. The problem is that too many of us think we are done once the program works. We fail to switch to organization and cleanliness. We move on to the next problem rather than going back and breaking overstuffed classes into decoupled units.
Don't. Go back. Clean it up. Leave it better than you found it.
Weekly Installs
162
Repository
GitHub Stars
25
First Seen
Jan 22, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
gemini-cli156
opencode156
codex155
github-copilot154
amp154
kimi-cli153
Kotlin 开发模式与最佳实践 | 构建健壮高效应用程序的惯用指南
1,200 周安装
generationTimestamp |
| Searchable | 7 | MAX_CLASSES_PER_STUDENT |
| Classes = nouns | Process | Customer, Account |
| Methods = verbs | data | postPayment(), save() |