代码工程实践精华
从写出好代码到成为高效工程师,跨越技术能力与工程素养的核心实践。
一、专业主义:态度决定上限
专业程序员和业余程序员的差距不在技术,在态度。Bob 大叔把专业主义定义为三层金字塔:底层是责任感(对自己的代码负全责),中层是工作纪律(TDD、时间管理、测试策略),顶层是协作与影响力(团队优先、知识分享)。
几个关键行为区分专业和业余:
- 面对 bug:专业的说"我来修",业余的找借口
- 面对工期:专业给出诚实预估、信守承诺;业余随意承诺、经常延期
- 面对质量:专业不交付明知有问题的代码,业余"先上线再说"
- 面对压力:专业坚守底线,业余走捷径
Bob 大叔最狠的一句话:"我会试一试"是最不专业的回答。 它既不是拒绝也不是承诺,而是一种逃避。专业的说法是"不,但是……"——给出替代方案和建设性选择。
勒布朗法则
"稍后等于永不"(Later equals never)。你以为是"以后再优化"的代码,永远不会被优化。看到烂代码当场修掉,哪怕只改一个变量名——这就是童子军规则:让营地比你到达时更干净。
说"不"的勇气
被要求在不可能的工期内完成工作?被要求跳过测试?被要求交付明知有缺陷的代码?专业的做法不是说"好吧我试试",而是给出替代方案:"这个工期不可行,但如果砍掉 X 功能,Y 天可以交付核心。"说"不"之后提供选择,才是真正的专业。
二、代码质量的工程原则
DRY:不要重复自己
系统中每条知识都应有唯一、明确、权威的陈述。这不是简单的"不要复制粘贴代码",而是知识层面的去重——同一个业务规则出现在代码、文档、配置文件三个地方,改了一处忘了另一处就是 bug。程序员的底层思维把这种违反 DRY 的现象称为"基础类型偏执":该抽象成实体类的业务概念,散落在 int/string 变量中。
正交性:消除不相关事物之间的影响
修改 UI 不影响数据库逻辑,改数据库不影响网络层。组件应该自成一体、独立自主、有单一清晰的职责。程序员修炼之道用"直升机"来类比:每个控制杆只负责一个维度的运动,好代码的设计也该如此。
ETC 原则:更容易变更
好设计的终极判据是"更容易变更"(Easier To Change)。如果一个设计让未来的变更变得困难,那它就是坏设计。判断方法很简单:如果改起来很痛苦,说明设计有问题——可能知识重复了(用 DRY),可能组件耦合了(用正交性),可能决策锁死了(用可逆性)。
SLAP 原则:单一抽象层次
每个方法内的代码应在同一级抽象层次。高层逻辑里混入底层实现细节就是典型的违规。抽象思维的四维评判标准:耦合性低、内聚性高、充分性(记录足够特征)、完整性(记录全部有意义的特征)。
契约式设计 + 尽早崩溃
函数有三重契约——前置条件(调用方必须满足什么)、后置条件(函数保证什么)、不变式(始终为真的条件)。如果调用方违反前置条件,函数有权直接崩溃。死掉的程序比有缺陷的程序造成的损害小得多。沉默的错误比明显的崩溃可怕一万倍。
三、重构:对未来的投资
重构不是代码洁癖,是对未来投资——今天多花十分钟改好的代码,会省下明天一小时的理解成本和后天一整天的调试时间。
两顶帽子
Martin Fowler 的经典类比:你要么在"添加功能"(添加新行为),要么在"重构"(不改变行为)。不要同时做两件事,否则出了 bug 不知道是哪个导致的。
代码坏味道 → 重构手法
最常见的坏味道和对应手法:
- 重复代码 → Extract Function / Pull Up Method
- 过长函数 → Extract Function / Replace Temp with Query
- 过大类 → Extract Class
- 过长参数列表 → Introduce Parameter Object
- Switch 惊悚 → Replace Conditional with Polymorphism
- 依恋情结(函数大量使用另一个类的数据)→ Move Function
重构的前提:测试安全网
没有测试的重构就是在赌博。 如果面对完全没有测试的遗留代码,先写特征测试(Characterization Tests)——为现有行为编定基准,再安全地修改。Fowler 说得好:"重构的第一步永远相同:确保即将修改的代码拥有一组可靠的测试。"
小步前进
每次只做一个微小的、可独立验证的改动,然后立刻跑测试。这个循环的关键在于"小步"——如果每一步都足够小,出错范围就足够可控。
四、杠杆率:高效工程师的核心指标
高效工程师不是写代码最多的人,而是产出价值最大的人。衡量标准是杠杆率 = 产出价值 / 投入时间。
提高杠杆率只有三条路径:
- 减少做某件事的时间 → 自动化手动部署流程
- 增加做某件事的产出 → 重构接口让整个团队复用
- 换到更高杠杆率的事 → 停止修无关紧要的 bug,去做影响百万用户的性能优化
时间管理的本质
保护你的制造者时间——程序员需要大段连续时间才能进入心流状态。一次会议就能打断这种状态,恢复需要 15-30 分钟。把会议集中到下午,上午留给深度编码。
优先级管理
大多数人被"紧急但不重要"的事淹没,忽略了"重要但不紧急"的事——学习新技能、构建工具、架构优化。后者才是产生长期价值的地方。用 If-Then 计划对抗拖延:准备一个"20 分钟任务清单",碎片时间直接从清单上挑一个开始。
迭代速度决定学习速度
迭代越快,学得越多。在工具上花的时间看起来是"浪费",但回报是指数级的。缩短调试和验证周期是最直接的杠杆——当你发现自己反复执行同样的操作,停下来自动化它。
五、程序员的底层思维
抽象思维
抽象 = 抽离 + 具象,从具体事物中提取共同特征得到一般化概念。抽象缺失的两种典型表现:基础类型偏执(该抽象成实体类用了 int/string 散落各处)和重复代码。抽象层次越高,扩展性越好但语义越弱;层次越低,语义越强但扩展性越差。
5Why / 5So 思考法
遇到问题连问 5 个为什么,找到根因。反方向追问一个现象会带来什么后果(5So),洞悉未来趋势。这是逻辑思维中最实用的工具。
模型思维
领域模型关注业务语义表达能力,数据模型关注存储和性能,两者经常被混淆但关注点完全不同。建模的关键在于:领域模型能否显性化、清晰地表达业务语义。
量化思维
"No measurement, no improvement." 量化三步:定义指标 → 将指标数字化 → 优化指标。没有量化的目标像断了线的风筝。
六、实用工具箱
| 场景 | 方法 | 核心要点 | |------|------|---------| | 写新功能 | TDD 三定律 | 先写失败测试 → 写最少代码通过 → 重构 | | 修复 bug | 先写测试复现 | 修之前确保能复现,修之后确保不再现 | | 时间预估 | PERT 三点预估 | (乐观+4×标准+悲观)/6 | | 代码审查 | 检查 SLAP + DRY | 抽象层次一致吗?有重复知识吗? | | 技术债偿还 | 按杠杆率排序 | 先还"人流密集"的代码区域 | | 优先级判断 | 四象限 + 杠杆率 | 多做重要不紧急且高杠杆率的事 | | 压力下决策 | 坚守底线 | 压力是检验专业素养的试金石 |
来源书籍:《代码整洁之道》罗伯特·马丁、《重构》Martin Fowler、《程序员修炼之道》David Thomas、《卓有成效的工程师》埃德蒙·刘、《程序员的底层思维》张建飞