# 编程十四年感悟:复杂度管理与工程实践

Posted on 2025-10-16 02:30  吾以观复  阅读(5)  评论(0)    收藏  举报

关联知识库:# 编程十四年感悟:复杂度管理与工程实践

编程十四年感悟:复杂度管理与工程实践

原文链接https://mp.weixin.qq.com/s/DYs0VIk-rduCPHHIGMUVWw
原文标题:入行 14 年,我还是觉得编程很难:给大项目写代码没意思还危险
作者:朱雷(@piglei)
来源:InfoQ 技术公众号
发布时间:2023 年
核心主题:编程经验、工程实践、复杂度管理、代码质量


核心观点

"十年很短,编程很难。软件开发的核心问题是管理复杂度,失控的复杂度就是程序员最大的敌人。"

作者在入行 14 年后的深刻感悟:

  • 随着经验增长,编程并不会变得像吃饭一样简单
  • 给许多"大项目"写代码不光没意思,还很危险
  • 只从技术角度思考问题,成不了好程序员
  • 人、流程、工程方法论远比单纯的技术更重要

目录

  1. 写代码很简单,但写好代码很难
  2. 编程的精髓是"创造"
  3. 打造高效试错的环境至关重要
  4. 避开代码完美主义陷阱
  5. 技术很重要,但"人"也许更重要
  6. 求知若渴是好事,但也要注意方法
  7. 越早开始写单元测试越好
  8. 程序员最大的敌人是什么?

1. 写代码很简单,但写好代码很难

核心论述

编程正在变得越来越容易学习:

  • 学习途径多样化:教学视频、交互式课程、游戏化学习(CodeCombat)
  • 编程语言更友好:动态类型语言大受欢迎,开发工具越来越完善
  • 门槛大幅降低:从专业技能变成人人可学的普通手艺

但低门槛 ≠ 高质量代码

现实困境:好代码仍然很少

作者在多家公司的真实经历:

  • 大型互联网公司的"大项目",代码质量远不如预期
  • 数百行的函数、神秘的数字字面量比比皆是
  • 不论公司多大、项目多牛,好代码仍是小概率事件

好代码的评价维度

Martin Fowler 的经典定义:

"任何傻瓜都能写出计算机能理解的代码。优秀程序员写人类能理解的代码。"

多维度评价标准

  • 可读性:易于理解,把人类读者放在第一位
  • 贴合语言特性:使用推荐写法和恰当的语法糖
  • 易于修改:考虑未来需求变更
  • API 设计合理:简单场景易用,高级场景可扩展
  • 性能够用:满足业务需求,保留提升空间
  • 避免过度设计:不过早优化

写好代码的捷径:阅读 <-> 编程 循环

编程和写作的相似性

  • 没有作家从不读书,只读自己的作品
  • 职业作家每天在"阅读 <-> 写作"循环中提升

程序员应该

  1. 阅读经典项目代码:学习 API 设计、模块架构、编码技巧
  2. 定期读技术书籍:保持阅读习惯
  3. 循环往复:在"阅读 <-> 编程"中快速成长

推荐资源

  • Jeff Atwood《Programmers Don't Read Books -- But You Should》(2008,15年后仍不过时)

2. 编程的精髓是"创造"

核心论述

"创造"的定义不限于发布新软件

  • 写一个可复用的工具函数 ✅
  • 设计一套清晰的数据模型 ✅
  • 优化一个算法提升性能 ✅

创造的价值

保持对"创造"的热情带来的益处:

  1. 更高效的学习

    • 学习新技术的最佳方式:用它开发真实项目
    • 在创造过程中学习,效果最好
  2. 邂逅了不起的东西

    • Linux - Linus Torvalds 出于兴趣创造
    • Python - Guido van Rossum 在 1989 年圣诞假期开始创造

创造者思维 vs 搬砖工思维

经典的"砌砖工"故事对比:

  • 搬砖工:"我只是在砌砖"
  • 创造者:"我在建造一座大教堂"

思维转变带来的影响

场景举例:给 API 增加报错提示文字

  • 搬砖工思维:快速完成需求就好
  • 创造者思维
    • 我想为用户创造什么样的产品体验?
    • 怎样的报错文字更能帮助用户?
    • 这个设计能达成我的目标吗?

实践建议

立即行动:问自己一个问题

"我的下一份创造会是什么?"


3. 打造高效试错的环境至关重要

反面案例:糟糕的工程环境

作者参与过的一个"成功"产品:

  • ✅ 市场表现:设计精美、功能丰富、用户量大
  • ❌ 工程质量:
    • 零单元测试
    • 零自动化测试流程
    • 业务逻辑复杂
    • 意外耦合多如牛毛
    • 每次发布氛围紧张,紧急回滚常见

结果:乐趣荡然无存,只剩下心理素质的锻炼

理想编程体验 ≈ LeetCode 刷题

LeetCode 做题的三大特征

特征 具体表现
关注点分离 每道题独立,可以完全沉浸其中
快速精准反馈 每次调整代码后,自动化测试快速反馈
零成本试错 语法错误、逻辑问题无不良后果,心理负担小

改善编程环境的工具和理念

可用的改进手段

1. 设计层面

  • 模块化思想:降低耦合,提升正交性
  • 设计原则:应用 SOLID 等经典原则

2. 质量保障

  • 自动化测试:单元测试 + Mock 技术
  • 覆盖关键路径:用测试覆盖业务核心

3. 反馈优化

  • 缩短反馈回路
    • 切换更快的编译工具
    • 优化单测性能
    • 竭尽全力缩短"改代码 → 获得反馈"的时间

4. 架构层面

  • 微服务架构:必要时拆分大单体,分散复杂度

核心目标

创造允许高效试错的"代码乐园"

  • 让工作像刷题一样轻松愉快
  • 这是经验丰富的程序员能为团队做出的最好贡献之一

4. 避开代码完美主义陷阱

核心观点

精益求精 ≠ 追求极致

  • ✅ 在代码质量上精益求精是好事
  • ❌ 但要避免掉进完美主义陷阱

编程 ≠ 艺术创作

关键区别

  • 作家:可以花数年打磨一本传世之作
  • 程序员:在代码上无限钻牛角尖很有问题

务实的代码标准

足够好的代码

  • 满足当前需求
  • 为未来扩展留了一些空间
  • 就够了

警惕"代码强迫症"标签

作者的招聘观察:

  • 有候选人给自己打"代码强迫症"标签
  • 虽然能感受到对代码质量的重视
  • 但更期望已经远离完美主义陷阱

5. 技术很重要,但"人"也许更重要

单一职责原则(SRP)背后的"人"

SRP 原则定义

"每个软件模块应该只有一个被修改的理由"

关键洞察:程序不会自己改变,修改的理由都来自"人"

案例对比分析

案例 1:字典数据类

  • 支持:存数据、取数据
  • 判断:✅ 没问题

案例 2:员工资料类

  • 支持:更新个人信息、渲染用户资料卡片图
  • 判断:❌ 违反 SRP

为什么?两个不同的修改理由(人)

  1. 管理员:需要校验"个人电话"字段
  2. 某员工:希望资料卡片上的"名字"字体加大

理解 SRP 的关键

"是人在要求软件变更。你绝不想把那些不同人出于不同原因所关心的代码混在一起,这样只会把他们和你自己搞糊涂。"

核心要素

  • 理解人在软件开发中的角色
  • 关注不同利益相关者的诉求
  • 根据"人"来划分模块边界

微服务架构与组织规模

常见误区:只关注微服务的技术优势

真正的关键:微服务与"人"的关系

  • 数百人维护一个大单体 → 效率低下
  • 许多小组织各自维护独立微服务 → 高效

本末倒置的做法

  • ❌ 缺少特定组织规模(人)作为前提
  • ❌ 空谈微服务的各种技术优势

实践建议

转换视角

  • 技术视角 → 人的视角
  • 关注组织结构、团队协作、沟通成本
  • 必要时的视角转换对你大有裨益

6. 求知若渴是好事,但也要注意方法

程序员的学习挑战

技术迭代极快的现实

  • 三年前流行的框架,一个月前可能已过时
  • "每分钟都有一个新的 JS 框架被发明"(玩笑)

后端工程师需要掌握的知识清单(示例):

  • 编程语言 / MySQL / Redis / 设计模式 / 用户体验 / 软件工程 / 编译原理 / 操作系统 / 网络基础 / 分布式系统 / …

关注学习性价比

学习成效与投入的关系曲线

成效 ↑
│     ┌─────(指数级投入)
│    ╱
│   ╱ (快速增长期)
│  ╱
│ ╱
└────────────→ 投入

关键洞察

  • 初级阶段:投入少,成效增长快
  • 超过阈值后:继续提升需要指数级投入

学习策略

关键问题:在开始学习前先问自己

"我应该在上图中的哪个位置停下来?"

分类处理

  • 需要持续精进:核心专业技能(成年累月学习)
  • 蜻蜓点水即可:周边辅助技能(皮毛绰绰有余)

准确判断并分配有限的学习精力,甚至比努力学习本身更重要

挑选合适的学习资料

作者的失败经历

目标:提升产品交互设计能力
做法:购买《About Face 4: 交互设计精髓》(经典权威)
结果:❌ 连第一章都读不完(隔行如隔山)

经验教训

不要"眼睛大,嘴巴小"

  • ❌ 只奔着最经典、最权威的资料
  • ✅ 挑选更易读、更适合"门外汉"的资料

推荐高性价比入门书

领域 推荐书籍 特点
设计 《写给大家看的设计书》 门外汉友好
Web 体验 《点石成金》 简单易懂
Linux 《鸟哥的 Linux 私房菜》 系统全面

核心原则

接受现实

  • 时间和精力总是有限
  • 不能也不需要在所有领域都成为专家
  • 在有限资源下做出明智选择

7. 越早开始写单元测试越好

作者的强烈推荐

个人声明

"我非常非常喜欢单元测试,我认为写单测这件事,对我的编程生涯影响极大。"

生涯分界线

  • 以"开始写单元测试"作为分界线
  • 后面那段远比前面那段精彩得多

单元测试的核心价值

多重好处

  1. 驱动代码设计改善:倒逼你写出可测试的代码
  2. 充当代码文档:测试即文档,展示如何使用
  3. 构建高效试错环境:完善的单测是第 3 点的关键基础

相关深入资源

作者的系列文章:

  • 《有关单元测试的 5 个建议》
  • 《游戏"蔚蓝山"教我的编程道理》

行动建议

立即开始

"如果到目前为止,你从未试过写单元测试,或从没重视过测试,我建议你从明天就开始写起来。"

不要犯的错误

  • ❌ "我不测试我的代码"
  • ❌ "假如测的话,我在生产环境测"(讽刺梗)

8. 程序员最大的敌人是什么?

常见误解:产品经理是敌人?

段子文化

  • 产品经理总是改需求
  • 一天一个新想法
  • 程序员苦不堪言

真相澄清

产品经理不是敌人

为什么需求总在变化?

软件的本质特性

  • 软件生来就是准备被修改的
  • 不然为什么叫"软"件?

关键对比

  • 建房子:没人会推倒重建,用更少的钢筋和水泥建一样的楼
  • 写软件:需求变更是常态,修改和优化是日常

结论

  • ❌ 产品经理和不稳定需求不是敌人
  • ✅ 能否写出易于修改、适配变化的代码,是区分普通程序员和优秀程序员的重要标准

真正的敌人:失控的复杂度

核心论断(引自《代码大全 2》):

软件开发的核心问题是管理复杂度

失控的复杂度就是程序员最大的敌人

导致复杂度增长的要素

来源 具体表现
功能增加 更多功能 = 更多代码 = 更高复杂度
高可用需求 引入消息队列等额外组件和代码
高性能需求 引入缓存、拆分模块、部分重写
推迟的重构 项目排期紧张,技术债越积越多
忽视测试 没人写单测,没人关心质量

复杂度失控的后果

最终结果

"咚!一个大家不愿改、不敢改的'大坑'凭空出现在了所有人的 IDE 中。"

反思问题

"究竟是谁挖下了这个坑?"

减缓复杂度增长的实践

核心要求:每个人都做到以下事项

1. 编码层面

  • ✅ 精通编程语言与工具
  • ✅ 写整洁的代码
  • ✅ 使用合适的设计模式

2. 代码质量

  • ✅ 对重复代码零容忍
  • ✅ 抽象库和框架
  • ✅ 编写详尽的文档和注释

3. 测试保障

  • ✅ 编写规范有效的单元测试

4. 架构设计

  • ✅ 适当运用整洁架构、领域驱动设计
  • ✅ 分离变动的与不变的

总结

所有实践的核心

写更好的代码

关键认知

  • 复杂度增长不可避免
  • 但可以通过工程实践减缓
  • 长期控制在合理范围内是可行的

核心启示

1. 编程是一门需要终身精进的手艺

  • 14 年工作经验不代表编程变简单
  • 好代码需要在多个维度上反复权衡、精心设计、持续打磨

2. 工程方法论比技术更重要

  • 单元测试、模块化、设计原则不是可选项
  • 打造高效试错环境是资深工程师的核心贡献

3. 关注"人"而非只关注技术

  • 理解 SRP 的关键在于理解"人"
  • 微服务的价值在于组织效率,不只是技术花活
  • 转换视角看问题,大有裨益

4. 复杂度是最大的敌人

  • 产品经理不是敌人,失控的复杂度才是
  • 管理复杂度是软件开发的核心问题
  • 写更好的代码 = 减缓复杂度增长

5. 保持创造者思维

  • 不要只见砖块,不见教堂
  • 问自己:"我的下一份创造会是什么?"

6. 学习要讲究性价比

  • 准确判断学习投入的停止点
  • 挑选适合门外汉的学习资料
  • 不在所有领域都成为专家

7. 务实胜于完美

  • 避开完美主义陷阱
  • 足够好的代码:满足需求 + 保留扩展空间

8. 越早开始单元测试越好

  • 单测是职业生涯的分界线
  • 从明天就开始写

相关资源

作者其他作品

  • 《Python 工匠:案例、技巧与工程实践》
  • 《有关单元测试的 5 个建议》
  • 《游戏"蔚蓝山"教我的编程道理》

推荐阅读

  • Martin Fowler - 代码可读性相关著作
  • Jeff Atwood - 《Programmers Don't Read Books -- But You Should》(2008)
  • 《代码大全 2》- 复杂度管理
  • 《写给大家看的设计书》- 设计入门
  • 《点石成金》- Web 用户体验
  • 《鸟哥的 Linux 私房菜》- Linux 入门

延伸思考

问题 1:你当前的编程环境

  • 能否像 LeetCode 刷题一样快速试错?
  • 反馈回路有多长?如何缩短?
  • 单元测试覆盖率如何?

问题 2:你的学习策略

  • 哪些技能需要持续精进,哪些点到为止?
  • 最近的学习资料选对了吗?
  • 是否陷入了"只买经典书但读不下去"的陷阱?

问题 3:代码质量现状

  • 你的项目代码质量如何?
  • 好代码多还是烂代码多?
  • 复杂度是否在可控范围内?

问题 4:思维方式

  • 你是"砌砖工"还是"建教堂者"?
  • 最近一次的"创造"是什么?
  • 下一份创造会是什么?

"十年很短,编程很难。复杂度是最大的敌人,而好代码是最好的武器。"