为什么过度工程实际上是需求问题
为什么过度工程实际上是需求问题
过度工程是一种症状,而非美德
要点: 过度工程发生在团队解决了错误的问题,通常是因为需求不清晰或不对齐,而不是因为他们对完美过于执着。
原作者 var0xyz 的文章驳斥了常见的口号“不要追求完美”。它表明真正的敌人不是完美本身,而是模糊或不完整的需求。当每一个约束都被明确列出时,解空间往往会收敛为在该情境下唯一的完美答案。
完美的解决方案源自严格的约束
要点: 当所有相关约束都被枚举时,通常只有一种设计能够满足它们,这种设计就是完美的契合。
- 示例:为一个新的无服务器 Python Web 应用选择技术栈。如果团队知道必须使用 Python、部署到 AWS Lambda,并且需要快速迭代,那么“完美”方案就是满足这些约束的组合。若约束改为低延迟的 C++ 服务,则会指向另一套同样完美的方案。
文章强调,完美并不意味着在所有情况下都是最优的;它指的是针对给定、明确定义的问题的最优。
系统是产品,而非纯技术制品
要点: 将库、API 或内部工具视为产品会迫使工程师揭示真实的用户需求,从而澄清需求并防止不必要的复杂性。
当系统被当作独立的技术练习来看待时,团队常会添加层层(微服务、自定义协议),这些看似优雅却并未满足任何具体的用户需求。通过询问谁会使用系统以及他们真正需要什么,设计空间会大幅收窄。
识别过度工程的代码
要点: 过度工程的标志是设计决策的理由与它实际解决的问题之间不匹配。
文章提供了一个具体场景:三名工程师维护五个微服务,这些服务通过松散的字符串 ID 而非外键共享数据。其代价——数据不一致、运维开销——远大于独立部署带来的边际收益,而团队根本不需要这种独立部署。深入追问为何选择这种架构,往往得到不满意的答案,暴露出需求的错位。
根本原因:需求收集错误
要点: 过度工程本质上是未能收集到正确需求;一旦需求精准,完美的解决方案便显而易见。
作者将问题重新表述为产品工程:在写代码之前先收集所有约束(性能、团队专长、截止日期、运营成本等)。当约束明确时,唯一满足全部约束的设计就是唯一可行的方案,从而消除添加不必要层的冲动。
社区观点
同意过度工程解决了错误的问题
"我不会说‘过度工程意味着解决了错误的问题’。想法本身可能是对的,只是人们在为不存在的约束进行优化…" – qsort
此评论对原始论断作了细化,指出团队有时会追逐不存在的约束,导致即使核心问题本身是合理的,也会产生过度工程的解决方案。
产品思维的争论
"产品思维是有毒的…所有最好的软件更偏向‘工具’类别,而不是‘产品’类别。" – MatrixMan
持反对意见的人认为,将软件视为产品可能引入以利润为导向的动机,进而与以用户为中心的目标冲突。这种张力凸显了需要进行诚实的需求收集,真正反映用户需求,而非仅仅业务指标。
定义过度工程 vs. 过度复杂
"过度复杂是添加了太多功能;过度工程是在不产生价值的情况下超出需求。" – titzer
此区分说明,一个解决方案可以在技术上很复杂,却仍然满足其需求;而过度工程则是投入了额外的工作却没有相应的价值回报。
“完美” vs. “足够好” 的权衡
"Worse is better… 动力往往比 100 % 完美更重要。" – shevy-java
一些评论者认为,追求 100 % 完美会拖慢交付速度,主张务实的“足够好”。原文通过强调明确的约束来呼应这一点;如果约束是快速上线,那么完美的方案就是满足该截止日期的最简实现。
防止过度工程的实用清单
要点: 使用以下具体步骤确保需求驱动设计,而不是相反。
- 列出所有约束 – 性能目标、团队专长、部署模型、截止日期、预算、合规等。
- 与利益相关者验证约束 – 确认每一项都对应真实的用户或业务需求。
- 对每个架构决策问“为什么?” – 如果答案无法回溯到已列出的约束,则重新考虑。
- 尽早原型 – 构建满足约束的最小系统;仅在约束变化时再迭代。
- 衡量权衡 – 量化额外复杂度的成本(运维开销、延迟、维护等)与其带来的收益。
结论
要点: 完美不是好软件的敌人;模糊或错误的需求才是。通过将约束显式化并把每个系统当作拥有真实用户的产品来对待,工程师可以在当前问题上收敛到完美的解决方案,避免过度工程带来的隐藏成本。
作者还提供了该论点的视频版本: Perfection is not over‑engineering。