# 软件工程的朴素真理 > 软件工程不是把代码写出来,而是在变化中持续交付可靠价值。 软件工程的核心,不是写代码,而是管理复杂性。 代码只是结果。真正困难的是:需求会变化,人会误解,系统会膨胀,历史包袱会累积,边界会模糊,成本会被低估。 软件工程不是把复杂问题变成复杂代码,而是尽量把复杂问题变成可理解、可维护、可演进的系统。 ### 一、关于代码 #### 1. 代码是写给人读的,顺便让机器执行 机器不在乎变量名叫 a1 还是 user_discount_rate,但人会在未来反复阅读、修改、排查这段代码。 代码首先是一种沟通媒介,其次才是机器指令。 可读性比聪明感重要。没人会长期欣赏只有你自己能看懂的代码。 #### 2. 清晰比聪明重要 聪明的代码可能让人佩服一分钟,清晰的代码能让团队少痛苦几年。 调试通常比写代码更难。如果代码本身已经写得过于“聪明”,未来排查问题的人会付出更高代价。 #### 3. 命名是编程中最难的事之一 一个好名字抵得上一段注释,一个坏名字会制造无数误解。 命名困难,往往说明概念还没有想清楚。 #### 4. 最好的代码,是不存在的代码 能不写的代码,永远是最好的代码。 代码越多,维护成本越高,出错面越大。删除代码常常才是真正的进步。 少即是多,不是偷懒,而是克制。 #### 5. 重复代码不一定坏,错误抽象更坏 抽象是有代价的。 好的抽象减少复杂性,坏的抽象制造复杂性。没有被真实使用验证过的抽象,往往只是提前制造复杂度。 过早抽象,很多时候比适度重复更糟。 ### 二、关于复杂度 #### 6. 软件工程的核心是管理复杂性 软件开发本质上,是把业务世界里的混乱逻辑,转化为可运行、可理解、可维护的数字逻辑。 业务本身有多复杂,系统最终就会有多复杂。 工程能力不是消灭所有复杂度,而是让复杂度有边界、有位置、有解释。 #### 7. 复杂度不会消失,只会转移、隐藏或命名 你可以通过架构、抽象、封装、平台化来移动复杂度,但很难真正消灭复杂度。 如果一个系统看起来简单得不可思议,复杂度很可能被推给了用户、运维、调用方,或者藏在某个尚未暴露的角落里。 #### 8. 简单不是简陋,而是克制 简单不是少写几行代码,而是少让人记住东西。 好的设计不是堆更多功能,而是减少不必要的概念、状态、分支和例外。 真正的简单,是让正确的事情容易发生,让错误的事情难以发生。 ### 三、关于需求 #### 9. 需求永远不会完整 用户往往知道自己不满意什么,却未必能准确描述自己真正需要什么。 很多失败项目,不是因为程序员不会写代码,而是因为一开始就没有搞清楚要解决什么问题。 #### 10. 需求不清,技术越强,偏得越快 需求不清时,技术能力越强,越可能把错误的方向实现得又快又复杂。 最贵的 bug,通常不是写错了代码,而是理解错了问题。 #### 11. 变化是常态 软件不是在稳定世界里运行的静态产物。 市场会变,用户会变,组织会变,依赖会变,监管会变,基础设施也会变。 所以软件设计不能只追求“第一次做对”,还要考虑未来如何修改、扩展、替换和回滚。 ### 四、关于维护 #### 12. 上线不是结束,而是开始 软件不是一次性交付物,而是一项长期债务。 上线只是软件开始接受现实检验的第一天。维护、扩展、排障、迁移、兼容,才是成本的大头。 #### 13. 不动的代码也会腐烂 即使一行代码都不改,系统也可能逐渐失效。 依赖会过时,环境会升级,接口会废弃,业务规则会变化,安全风险会积累。 不维护的系统,迟早会出问题。 #### 14. 技术债不是罪,假装没有技术债才是罪 为了赶进度牺牲质量,有时是现实选择。 但技术债必须被看见、被记录、被评估。债可以借,但要知道借了多少,利息是什么,什么时候还。 “以后再重构”通常意味着“以后也不会重构”。 ### 五、关于质量 #### 15. 测试不是为了证明代码正确 测试不能证明系统没有 bug,但能阻止很多旧 bug 复活。 它最大的价值,是让修改不那么可怕。 没有测试的系统,越成功越难改;越难改,越容易变成负担。 #### 16. 性能问题要靠测量,不要靠感觉 过早优化是万恶之源。 先让它跑起来,再让它正确,最后才是让它快。 大多数性能问题不是靠猜出来的,而是靠监控、profiling、压测和真实数据定位出来的。 #### 17. 安全不是一个功能,而是一种默认假设 系统最脆弱的地方,通常不在算法,而在边界。 输入、权限、网络、并发、时间、状态、依赖、异常路径,才是事故高发区。 安全的基本假设应该是:任何输入都可能有问题,任何边界都可能被突破。 #### 18. 稳定不是没有故障,而是故障可控 稳定系统靠的不是永远不出问题,而是出问题时能够被发现、被定位、被隔离、被恢复。 日志、监控、告警、追踪、降级、限流、回滚,都是系统稳定性的一部分。 日志不是给程序看的,是给凌晨三点处理事故的人看的。 ### 六、关于架构与权衡 #### 19. 没有银弹 没有任何语言、框架、架构、平台或工具能解决所有问题。 换语言不一定能解决性能问题,引入新框架不一定能解决组织问题,使用 AI 写代码也不等于解决了需求定义和工程责任。 技术只是手段,不是答案本身。 #### 20. 软件工程本质上是权衡 软件世界里很少有绝对最优,更多是当前条件下的相对合适。 速度、质量、成本、灵活性、稳定性、安全性、复杂度,往往互相牵制。 架构设计不是寻找完美方案,而是在多个不完美选项中,选择团队当前最能承担的代价。 ### 七、关于团队 #### 21. 软件工程是团队运动 再厉害的独行侠,也比不上一个沟通顺畅的团队。 代码是媒介,协作才是核心。 团队里的隐性知识越多,系统风险越大。没有被写下来、讲清楚、传递出去的知识,都会在未来变成成本。 #### 22. 系统的形状,往往反映组织的形状 沟通混乱的团队,很难产出边界清晰的软件。 职责不清、目标不一、协作低效,最终都会反映到系统里,变成混乱的模块、模糊的接口和难以维护的依赖关系。 #### 23. 文档不是装饰品 文档不是为了证明你写过什么,而是为了让别人少猜。 尤其是记录“为什么这么做”的文档,通常比解释“代码做了什么”更有价值。 代码能说明系统当前怎么运行,但文档能解释当时为什么做出这个选择。 ### 八、最终总结 软件工程的朴素真理是: 技术只是手段,解决问题才是目的。 优秀的工程师,不是写出多复杂的代码,而是能用尽可能简单、清晰、可靠的方式解决复杂问题。 每一行代码,都是未来要承担的责任。 每一个抽象,都是未来要维护的承诺。 每一个系统,都会在变化中接受检验。 所以,软件工程的本质不是“把代码写出来”,而是: 在变化中持续交付可靠价值。