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