Community编程与开发github.com

m2vic/simple-code

编写最简单、最具可读性的代码,满足需求即可,去除不必要的复杂逻辑、抽象和多余内容。在编写、扩展或重构任何语言的代码时均可使用。

simple-code 是什么?

Simple Code 是一个AI代码辅助技能,指导AI助手编写对人类最易读、最简洁的代码。它强调每段代码中每一个类、辅助函数、参数和层都必须“证明自己存在的价值”,即它们必须直接贡献于程序的行为变化,而非为可能的未来扩展做准备。该技能支持在任何编程语言中使用,适用于编写新代码、重构现有代码或扩展功能。其核心工作流程包括:明确任务清单、先写出最朴素的版本、执行“删除测试”(检查移除某元素后是否仍满足所有需求)、编写测试用例并保持简洁,最后以清晰的方式报告交付物。该技能尤其适合当用户要求代码“简单、易读、干净、可维护、不过度设计”时,或抱怨AI生成的代码过于复杂时使用。它提倡使用最直接的语言构造(如值、字面量、if语句、循环、函数),避免过早抽象、过度分层、框架依赖或不必要的设计模式,同时强调正确处理错误和边界情况,并保持测试作为文档和安全网的一部分。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/m2vic/claude-skills/tree/HEAD/plugins/simple-code/skills/simple-code

Installed? Explore more 编程与开发 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

简单代码

两个输出相同的程序并不相等:人们能理解得更快的那个更好。每个类、辅助函数、参数和层都是下一个读者需要学习的东西,因此它们都必须通过改变程序的行为来证明自己的存在价值。

目标是让新队友能够从上到下阅读一次代码,就能解释清楚并安全地进行修改。

如何工作

  1. 明确任务。 什么输入,什么输出,要求了哪些规则和边界情况,以及用户提到的任何质量目标或设计。所有这些都是需求。从这份清单出发,而不是从代码未来可能会需要什么出发。
  2. 先写出最朴素的版本。 使用普通函数、if 语句、循环和字面量数据,按照人们描述步骤的顺序来写。这就是你要保留的设计,除非它未能满足某个明确的需求。
  3. 执行删除测试。 对于每个类、辅助函数、参数、常量、导入、分支和 try:在脑中将其移除。如果所有明确的需求(包括质量目标)仍然满足,那么就真的将其删除。
  4. 测试并保留测试。 用一个小而简洁的测试文件覆盖每个明确规定的规则和边界情况,放在代码旁边,遵循项目的约定,除非用户明确说不需要。测试能让下一个读者知道规则是什么,并使修改变得安全,因此它们是任务的一部分,而非额外的负担。
  5. 清晰地报告。 说明你构建了什么。如果你有意省略了某些内容,用一句话说明(例如"没有 CLI 或日志,因为两者都没有被要求"),这样用户可以根据需要提出添加。

什么是简单

为今天的需求而构建。 一个“以后可能会添加更多”的假设并非一个现在就要构建的功能。简单的代码是最容易扩展的,因为没有什么需要绕开。添加一个优惠券功能应该意味着添加一行代码,而不是首先学习一个框架。

以最简单的方式满足明确的质量目标。 当需求提到“生产就绪”、“健壮”、“可扩展”或“企业级”时,问问这个代码在实际使用中真正可能出什么问题,然后直接处理这些问题:拒绝不良输入,让失败可见,不让数据静默丢失,金额算对到分。这些词要求的是这种审慎,而不是层次、插件系统或框架。

交付用户要求的设计。 当有人要求一个架构或特定结构时,以最小的可用形式交付,而不要回复说应该等待。例如,如果以后还有更多表单,设计可以是共享的检查函数供下一个表单复用,并加上一行注释说明如何添加。应止步于一个仅为想象场景所需而构建的引擎之前。

使用能工作的最直接构造,大致按以下顺序:

  • 在配置系统之前使用值或字面量字典
  • 在注册表、策略模式、工厂模式或插件系统之前使用 if/elif 或查找字典
  • 在类或包含方法的结构体之前使用函数;只有当它需要持有多个操作共享的状态时才添加类或结构体
  • 在接口或泛型之前使用具体类型;只有当今天确实需要两个具体的实现或类型时才引入它们
  • 在协程和通道之前使用顺序代码,除非并发是需求
  • 在新依赖之前在已有项目中寻找标准库和辅助函数

保持流程直白。 尽早返回而不是嵌套;超过大约三层深度通常意味着流程可以展平。每行只做一件事。优先使用可读的循环,而不是嵌套推导式、链式三目运算符、reduce 或技巧性正則表达式。避免元编程、反射和自定义装饰器,除非任务本身就是关于这些的。

让小重复存在。 三行相似的代码通常比一个带有标志位(flag)的辅助函数更清晰。只有当函数能给一个真正的想法起个好名字,或者逻辑必须保持同步时,才提取函数,而不仅仅是因为两行看起来相似。不要添加只有一个调用者使用或没人要求的参数。

为人命名。 使用完整、普通的词语(shipping_fee,而不是 sf 或 FeeCalculationContext)。一个好的名字消除了写注释的需要。

仅为“为什么”写注释。 记录一个令人惊讶的规则或约束。跳过那些重复代码的注释、章节标题,以及冗长的、重复函数签名的文档字符串。

处理可能发生的失败,并且失败时要明确。 对需求或真实边界(用户输入、网络、文件)所要求的内容进行校验,对不正确的输入返回清晰的错误,而不是产生一个似乎合理但错误的答案。如果代码跳过了或丢弃了数据,要让运行它的人看到,例如通过日志行中的计数。不要捕捉异常只是为了重新抛出它,也不要防范代码无法达到的状态。

在对外部数据进行算术运算之前先检查它们。 来自请求的数量、金额或计数可能非常大,加法或乘法可能溢出为一个小值或负值,从而通过后续的所有检查。在将其加进任何东西之前,将输入值与它的限制(库存、最大值)进行比较,并添加一个测试,发送该类型能容纳的最大值。这只是一个 if,不是额外的代码。

决定重启在多步骤变更中间会做什么。 当代码更改了已保存的状态,调用某些缓慢或外部的东西(如支付服务商),然后再更改状态时,问问如果进程在这些步骤之间停止了会发生什么。在调用之前保存一个明确的中间状态(例如 pending)。重启时,不要猜测:不要撤销一个可能已成功的步骤(例如针对一笔可能已成功扣款的交易返回库存),也不要重新打开工作以便重试可能导致重复扣款。将记录保留在中间状态,使其保持阻塞,并使其可见,例如通过在启动时记录有多少处于 pending 状态,以便人工解决。在设计中使用一两行代码写下这条规则,并通过重启一条 pending 记录来测试它。

不要添加额外功能。 除非它们被要求,或者不添加就无法完成工作或达到既定目标,否则不要添加 CLI、日志、配置、重试、缓存、指标或类型层次结构。例如,无人值守运行的代码需要某种方式来报告问题。

修改现有代码时

遵循项目的约定,并进行最小的修改来完成工作。不要重构邻近的代码或顺便引入新的模式。保留正在工作的复杂代码,除非简化它就是任务,或者你的修改需要它;如果它看起来可以移除,提出来即可。

简单并不意味着什么

永远不要为了节省行数而牺牲以下任何一点:

  • 正确的行为,包括每个明确规定的规则和边界情况
  • 安全性:信任边界处的输入验证、安全的查询、代码中无秘密
  • 重要的精度:金额必须算对到分,包括半分的情况,并且测试应该证明这一点。使用能做到这一点的最直接方法。当价格只有几位小数,且浮点数无论如何都会跨越函数边界时,使用带有小型舍入辅助函数来消除二进制噪声的浮点数是可以的。只有当明确规则要求,或者测试显示更简单的方法会得到错误结果时,才转向整数分或精确分数(如 big.Rat)
  • 任务实际要求或测量结果已证明重要的性能
  • 用户明确要求的抽象;以最简单的形式构建它

行数更少也不是目标。代码高尔夫和过度设计一样难以阅读,所以当更长的版本更清晰时,优先选择它。一个全做了一切的冗长函数并不简单:当一个函数混合了不同的步骤(如读取、解析和汇总)时,要为每个步骤提供一个命名良好的函数。当问题本身具有真正的复杂性时,保留它,将其隔离在一个命名良好的地方,并用简短的注释解释原因。

示例

任务:应用会员折扣,并对 50 以下的订单收取 5 元运费。

避免这样写。它给出相同的输出,但要读的东西却多得多:

type DiscountStrategy interface {
	Apply(amount float64) float64
}

type MemberDiscount struct{}

func (MemberDiscount) Apply(amount float64) float64 {
	return amount * 0.95
}

type PriceCalculator struct {
	Strategy          DiscountStrategy
	ShippingThreshold float64
	ShippingFee       float64
}

func (c PriceCalculator) Calculate(amount float64) float64 {
	discounted := c.Strategy.Apply(amount)
	if discounted < c.ShippingThreshold {
		return discounted + c.ShippingFee
	}
	return discounted
}

写成这样:

func FinalPrice(amount float64, isMember bool) float64 {
	if isMember {
		amount = amount * 0.95
	}
	if amount < 50 {
		amount = amount + 5
	}
	return amount
}

以后添加 VIP 折扣只需要多一个 if,而且没人需要学习一个接口和三个类型才能做到。

相关技能