跳转到内容
新建笔记

KISS:保持设计简单,保留必要的能力

KISS 常展开为 “Keep It Simple, Stupid”,在设计语境中可理解为保持简单,避免不必要的复杂性。这里的重点是要求设计者克制复杂化倾向,不能机械翻译为“保持简单,愚蠢”。

在软件工程中,简单意味着:读者能理解系统为什么这样工作,使用者能完成任务,维护者能定位问题并做出局部修改。它不等于代码行数最少、功能最少或界面按钮最少。输入校验、错误处理、权限控制和数据恢复可能增加实现量,却是实际需求的一部分。

从需求中区分两类复杂性

跳转到“从需求中区分两类复杂性”

问题本身的复杂性来自业务规则或运行条件。例如,采集系统必须处理断线、丢包和不同采样率;不能为了让程序短一点就忽略这些情况。

实现额外引入的复杂性来自不必要的中间层、隐含状态、重复配置或过早泛化。例如,一个只需要读取本地配置文件的工具,暂时未必需要插件注册中心、远程配置服务和十级继承。

做设计时先列出必须支持的行为,再检查每一层抽象解决了什么具体问题。对尚无需求、也没有现实扩展证据的机制,可以先不引入;一旦出现第二种真实实现,再根据变化位置提取共同接口。这里强调的是判断依据,不是禁止抽象或要求永远等到重复代码出现。

例子:配置读取应当明确

跳转到“例子:配置读取应当明确”

假设采集程序要求用户指定 1~100000 Hz 的整数采样率,错误配置必须在启动前报告。容易理解的实现应该让默认值、格式规则和取值范围都能直接看到:

def parse_sample_rate(text: str | None) -> int:
if text is None:
return 1000
value_text = text.strip()
if not value_text or not value_text.isascii() or not value_text.isdecimal():
raise ValueError("采样率必须是十进制正整数")
value = int(value_text)
if not 1 <= value <= 100_000:
raise ValueError("采样率必须在 1~100000 Hz 之间")
return value

该例的输入契约是字符串或 None;空字符串不等于“没有配置”。字符串允许首尾空白,但不接受负号、小数、科学计数法或非 ASCII 数字。范围上限只是这个示例的需求,不代表任何采集硬件都支持 100 kHz。

将所有异常一概吞掉并返回 1000,看上去可以缩短代码,却会把拼写错误隐藏成有效配置;反过来,为这一个参数创建整套插件框架也会增加理解成本。合适的简单方案应同时满足规则、可读性和明确的失败行为。

Python 的 PEP 20同样强调可读、明确和认真处理错误。这里把它作为编程取舍的参考,不把它当作 KISS 的历史起源证明。

如何用于代码、界面和协作

跳转到“如何用于代码、界面和协作”
场景可执行的做法容易走偏的做法
代码让函数完成清楚的工作,明确输入、输出和错误;按真实变化提取公共部分为缩短行数堆叠表达式,或者为假想扩展创建大量层级
界面把最常见任务放到明显位置,合理给出默认值,在需要时展示专业选项隐藏必要状态,让用户猜测是否保存、是否出错
产品先确定主要使用场景,再取舍功能和操作步骤只凭外观简洁就认定产品容易使用
项目流程每个审批和交接步骤都对应明确责任与输出去掉必要复核,或者保留无人使用的重复报表
团队沟通写清决定、理由、负责人和验收标准以“简洁”为由省略上下文,导致反复询问

原笔记提到易用性、可靠性、效率和成本,这些都可以作为评估方向,但不是“KISS 一用就改善”的保证。更少的操作可能提高效率,也可能把复杂工作转移给用户;更少的模块可能降低导航成本,也可能让一个模块承担过多职责。

KISS 用来检查复杂性是否值得;SOLID帮助检查职责、替换和依赖关系。两者没有必须二选一的关系:一个稳定的小接口可能减少调用方理解成本;几十个没有独立职责的接口则可能增加成本。

评价方案时可以依次问:

  1. 读者能否根据命名和数据流解释主要行为?
  2. 失败条件是否可见,能否定位到具体输入或步骤?
  3. 常见任务需要多少操作,哪些操作只是系统组织方式造成的负担?
  4. 某项需求变化时,需要修改哪些位置,是否存在不必要的连带修改?
  5. 去掉一个层级或步骤后,是否会损失已经确认的能力、保障或责任?

这些问题把“看起来简单”的主观评价转化为可讨论的具体证据。对于复杂但必要的功能,优先清楚地组织它,而不是假装它不存在。

本页重写自 KISS 原则原始笔记,保留软件、产品、流程和团队应用,以及过度简化的边界;删除没有证据支持的品牌效果举例,纠正机械直译,并补充具体配置读取案例。