《程序员修炼之道》 —— 从小工到专家

《程序员修炼之道》这个书名实际上不如原版《The Pragmatic Programmer: From Journeyman to Master》来得更清晰明了。此书第一版写于1999年,我看的是11年的版本,但还是透流露着不少世纪初的观念和视野。除开一部分观点认识的过时,书中绝大多数观点都四溢着国外互联网行业的工作风格和流程,和国内凶猛生长、一把梭就是干的风格各有不同,甚至我感觉国内IT,尤其是互联网企业里的工作流更加讲求实效。尽管和读之前的预期不大一样,里面许多经验还是很有借鉴意义,比如正交性、不要依赖巧合等等。

书中内容在项目管理、编程哲学、以及编程过程的各个方面都有涉及,在这些方面上更加深入的探讨,书的最后也推荐了继续阅读的材料。下面就各章节的关键观点加以整理。

关于本书的读法:

  • 能不能让正确原则指导正确的行动本身,其实就是区分是否是高手的一个显著标志
  • 要能内化书中提到的各个小提示,不实践的话,是不会有太大收获的
  • 思考,你的工作,多思考

实效哲学

  • 对你的源码负责
  • 不要容忍破窗,它们会增大你软件的熵(这个也是要结合实际情况看的)
  • 记住大图景,注意方向是否有误,不要光低头做事
  • 知道在何时打住,你不可能做到完美
  • 定期为你的知识资产投资,就像经济投资一样
    • 定期投资
    • 多元化
    • 管理风险,不要把所有技术放在一个篮子里
    • 低买高卖,能看清形势
  • 为此,你需要
    • 每年至少学习一种新语言
    • 每季度阅读一本技术书籍
    • 也要阅读非技术书籍
  • 批判地思考你读到和听到的
  • 如何表达自己很重要,这会增加你的影响力
    • 你想让谁知道
    • 你想让他们知道什么
    • 他们是否感兴趣
    • 他们需要知道细节么
    • 如何促使他们与你交流

实效途径

  • DRY,不要重复自己
    • 强加的重复 => 使用自动生成,减少是信息冗知识
    • 无意的重复 => 优良的设计
    • 无耐心的重复 => 考虑长远
    • 开发者间的重复 => 加强组内交流,制定代码规范,制造更容易复用的环境
  • 减少无关事物的影响,非正交 => 次级效应 => 补偿行为 => 经验依赖
    • 好处:提高生产率(促进复用)、降低风险(风险隔离,易测试)
    • 分层设计、抽象和接口约定
    • 避免使用全局变量
    • 考虑使用库的代码侵入性
    • 文档和认同正交性
  • 不存在最终决策,当需求变动频繁的时候,不仅要思考程序架构如何适应这种变动,也要反思是否是设计者没想清楚到底要做什么
  • 使用曳光弹找到目标,即MVP + 快速迭代 + 即时的反馈
    • 逐步逼近,摸着石头过河
    • 曳光弹模式永远包含着一个可用的软件版本
  • 原型和便笺,使用原型去表达和快速验证项目的可行性
  • 靠近问题领域编程
    • 使用DSL(Domain Specified Language)
  • 估算,以避免意外,主要用来估计工期、分析风险
    • 适当地降低估算速度,慎重思考隐藏的风险

基本工具

工具成为双手和大脑的延伸,优秀的工具可以放大你的才干。

  • 纯文本以其自解释能力几乎可以永久保存,XML、JSON就是利用此成为通用的数据表现形式
  • 利用shell的力量,它是自动化任务避不开的工具
  • 要能烂熟地使用你的编辑器要使用高级的编辑器,由于你的所有开发工作都建立在它上面,做好这两点可以节省你大量时间
    • 反思一下,在用你的编辑器时,你有遇到过到比较繁琐的操作吗?
    • 是因为你不会高级使用方式,还是编辑器本身不支持?
  • 总是使用源码控制(这一点早已成为共识)
  • 调试,debug
    • 通常认为匪夷所思的bug,都来自健忘、自大和愚蠢
    • QA角色的重要性之一:帮助复现、找到规律性
    • 橡皮鸭调试法
    • 二分查找法
    • 如果bug来自某人的错误假设,那么需要清除团队其他人的相同误解
  • 学习一种文本操纵语言或工具,例如awk,sed,处理数据和结果时一定能用上
  • 编写代码生成器
    • 开发者手动触发,如模板代码
    • 程序自动出发,如scheme to idl,idl to code

偏执编程

  • 通过合约设计,约定好接口,合作方基于接口开发
    • 强类型语言更容易实现这一点
  • 早崩溃,这在需要编译的软件开发上比较科学,对于web应用来说却不是这样
  • 使用断言确保某事不会发生,减少预设条件代理的隐藏bug
    • 不要滥用断言
  • 只在异常处用异常
  • 一定记住释放请求的资源,如内存、句柄等,可以通过封装统一的资源类实现自动的资源释放

时间的魔力

  • 德墨忒尔法则,使模块间的依赖减少到最小
    • 物理解耦
  • 要配置不要hardcode,使用元数据动态描述你的程序
    • 抽象放进代码,细节放进元数据
  • 时间耦合:考虑并发和事件的发生顺序
    • 在异步代码中,总考虑并发
  • 一些GUI的设计模式
    • 发布订阅
    • MVC
  • 基于规则/规则集的黑板系统
    • 黑板给出统一接口
    • 耦合方通过调用黑板接口避免耦合
    • 黑板通过规则给出输出

编码时

  • 不要靠巧合编程
    • 改动要有文档沉淀
    • 只依靠文档中记录的行为
    • 把你的假设记入文档
  • 在大数据量时,考虑算法数量级
    • 兼顾效率和可读性
  • 早重构,常重构,代码是业务设计的近似同构体,常重构才能保证代码完美贴合需求设计
    • 重构和功能开发分开进行
    • 重构一定要有测试
  • 优秀的代码不是看新增了多少行,而是看删除了多少行
  • 编写易于测试的代码
    • 测试你的软件,否则你的用户会代你做测试

项目开始前

完美,不是在没有什么需要增加,而是在没有什么需要去掉的时候达到的。

  • 去挖掘需求,思考用户做特定事情的原因,和如何去做的方式,让需求成为一种一般性的陈述
    • 制作需求文档时的一大危险是太过具体,好的需求文档会保持抽象
    • 经常性复盘
    • 鼓励文档分享和交流
  • 巧妙解决看似不能解决的难题,关键要找到真正的约束,去思考
    • 有更容易的方法么
    • 你是在解决真正的问题,还是被外围的技术问题转移了注意力
    • 这件事为什么是一个问题
    • 是什么让它难以解决
    • 它必须这么做么
    • 它必须完成么
  • 准备好再开始,但不要让它成为你懈怠的借口
  • 不要成为方法学的奴隶

实效项目

  • 团队建设
    • 不留破窗户(考验leader的管理能力)
    • 经常性的复盘和例会
    • 减少团队成员分工的冗余
    • 自动化项目流程 => 效率工程团队开发内部工具
    • 制造context,给成员足够空间
  • 不要使用手动流程,它不可控且难以复制
    • shell、crontab
    • CI和自动化持续集成
    • 代码生成
    • 自动化测试
    • 代码review和源码版本控制流程
  • 常测试,早测试,自动化测试
    • 单元测试/集成测试/压力测试/回归测试
    • 测试状态覆盖,而不是代码覆盖,代码覆盖率提供的意义有限
  • 关于如何生产文本
    • 所有文档都是代码的反映
    • 源码注释应该去把项目里那些难以描述、容易忘记、不能记录在其他地方的东西记载下来
    • 比无意义的名称更糟糕的是有误导性的名称
    • 除非有程序或人工维护,否则任何形式的文档都只是快照
  • 温和地超出用户期望,如
    • 友好的新手指引
    • 快捷键
    • 自动化安装
  • 自豪地为你的作品签名

更多资源

  • 《人月神话》
  • 《Unix编程艺术》
  • 《Effective C++》
  • 《集市与大教堂》

–END–