程序员修炼之道:通向务实的最高境界(第2版)
- 1. 本书赞誉
- 2. 提示1 关注你的技艺
- 3. 提示2 思考!思考你的工作
- 4. 提示3 你有权选择
- 5. 提示4 提供选择,别找借口
- 6. 提示5 不要放任破窗
- 7. 提示6 做推动变革的催化剂
- 8. 提示7 牢记全景
- 9. 提示8 将质量要求视为需求问题
- 10. 提示9 对知识组合做定期投资
- 11. 提示10 批判性地分析你读到和听到的东西
- 12. 提示11 英语就是另一门编程语言
- 13. 提示12 说什么和怎么说同样重要
- 14. 提示13 把文档嵌进去,而不要栓在表面
- 15. 提示14 优秀的设计比糟糕的设计更容易变更
- 16. 提示15 DRY—不要重复自己
- 17. 提示16 让复用变得更容易
- 18. 提示17 消除不相关事物之间的影响
- 19. 提示18 不设最终决定
- 20. 提示19 放弃追逐时尚
- 21. 12 曳光弹
- 22. 提示20 使用曳光弹找到目标
- 23. 提示21 用原型学习
- 24. 提示22 靠近问题域编程
- 25. 提示23 通过估算来避免意外
- 26. 提示24 根据代码不断迭代进度表
- 27. 提示25 将知识用纯文本保存
- 28. 提示26 发挥Shell命令的威力
- 29. 提示27 游刃有余地使用编辑器
- 30. 提示28 永远使用版本控制
- 31. 提示29 去解决问题,而不是责备
- 32. 提示30 不要恐慌
- 33. 提示31 修代码前先让代码在测试中失败
- 34. 提示32 读一下那些该死的出错信息
- 35. 提示33 “select”没出问题
- 36. 提示34 不要假设,要证明
- 37. 提示35 学习一门文本处理语言
- 38. 提示36 你无法写出完美的软件
- 39. 提示37 通过契约进行设计
- 40. 提示38 尽早崩溃
- 41. 提示39 使用断言去预防不可能的事情
- 42. 提示40 有始有终
- 43. 提示41 在局部行动
- 44. 提示42 小步前进——由始至终
- 45. 提示43 避免占卜
- 46. 提示44 解耦代码让改变更容易
- 47. 提示45 只管命令不要询问
- 48. 提示46 不要链式调用方法
- 49. 提示47 避免全局数据
- 50. 提示48 如果全局唯一非常重要,那么将它包装到API中
- 51. 提示49 编程讲的是代码,而程序谈的是数据
- 52. 提示50 不要囤积状态,传递下去
- 53. 提示51 不要付继承税
- 54. 提示52 尽量用接口来表达多态
- 55. 提示53 用委托提供服务:“有一个”胜过“是一个”
- 56. 提示54 利用mixin共享功能
- 57. 提示55 使用外部配置参数化应用程序
- 58. 提示56 通过分析工作流来提高并发性
- 59. 提示57 共享状态是不正确的状态
- 60. 提示58 随机故障通常是并发问题
- 61. 提示59 用角色实现并发性时不必共享状态
- 62. 提示60 使用黑板来协调工作流
- 63. 提示61 倾听你内心的蜥蜴
- 64. 提示62 不要依赖巧合编程
- 65. 提示63 评估算法的级别
- 66. 提示64 对估算做测试
- 67. 提示65 尽早重构,经常重构
- 68. 提示66 测试与找Bug无关
- 69. 提示67 测试是代码的第一个用户
- 70. 提示68 既非自上而下,也不自下而上,基于端对端构建
- 71. 提示69 为测试做设计
- 72. 提示70 要对软件做测试,否则只能留给用户去做
- 73. 提示71 使用基于特性的测试来校验假设
- 74. 提示72 保持代码简洁,让攻击面最小
- 75. 提示73 尽早打上安全补丁
- 76. 提示74 好好取名;需要时更名
- 77. 提示75 无人确切知道自己想要什么
- 78. 提示76 程序员帮助人们理解他们想要什么
- 79. 提示77 需求是从反馈循环中学到的
- 80. 提示78 和用户一起工作以便从用户角度思考
- 81. 提示79 策略即元数
- 82. 针对更普遍的情况做实现,至于系统需要支持的那种特定类型的东西,只是通用实现在加入策略信息后的示例。
- 83. 提示80 使用项目术语表
- 84. 提示81 不要跳出框框思考——找到框框
- 85. 提示82 不要一个人埋头钻进代码中
- 86. 提示83 敏捷不是一个名词;敏捷有关你如何做事
- 87. 提示84 维持小而稳定的团队
- 88. 提示85 排上日程以待其成
- 89. 提示86 组织全功能的团队
- 90. 提示87 做能起作用的事,别赶时髦
- 91. 提示88 在用户需要时交付
- 92. 提示89 使用版本控制来驱动构建、测试和发布
- 93. 提示90 尽早测试,经常测试,自动测试
- 94. 提示91 直到所有的测试都已运行,编码才算完成
- 95. 提示92 使用破坏者检测你的测试
- 96. 提示93 测试状态覆盖率,而非代码覆盖率
- 97. 提示94 每个Bug只找一次
- 98. 提示95 不要使用手动程序
- 99. 提示96 取悦用户,而不要只是交付代码
- 100. 提示97 在作品上签名
- 101. 提示98 先勿伤害
- 102. 提示99 不要助纣为虐
本书赞誉
正是这本书,开阔了我的视野,让我意识到自己不仅仅是庞大机器上的一枚齿轮,有朝一日也能藉由修炼成为匠师。它是我生命中最重要的一本书。
哪有什么简单的答案。没有最好的解决方案,无论是工具、语言还是操作系统;只在特定的环境下才有所谓更合适的系统。
作为务实的程序员,你们会共有许多如下特征:
- 早期的采纳者/快速的适配者。
- 你热衷于收集各种细微的事实,坚信它们会影响自己多年后的决策。
提示1 关注你的技艺
提示2 思考!思考你的工作
你能更积极地投入喜欢的工作,对越来越多的学科有掌控感,对不断进步产生愉悦感。从长期来看,时间投资将得到回报,因为你和你的团队将变得更高效,能编写出更容易维护的代码,并且在会议上花的时间更少。
伟大的草坪需要每天的点滴护理,伟大的程序员也是如此。
我活着不是为了满足你的期望,正如你也不是因为我的期望而活着。
——李小龙
提示3 你有权选择
如果你的技术过时了,安排时间(你自己的时间)学习一些看起来有趣的新东西。这是一种自我投资,只有为此而加班才是合理的。
在你的职业发展、学习教育,以及你的项目、每天的工作等各方面对你自己负责,对你的行为负责,这是务实哲学的基石之一。
提示4 提供选择,别找借口
给出选择,而不是找借口。不要说搞不定;解释一下要做些什么才能挽回这个局面。
当你意识到自己在说“我不知道”时,一定要接着说“——但是我会去搞清楚”。用这样的方式来表达你不知道是非常好的,因为接着你就可以像一个专家一样承担起责任。
提示5 不要放任破窗
不要搁置“破窗”(糟糕的设计、错误的决定、低劣的代码)不去修理。每发现一个就赶紧修一个。如果没有足够的时间完全修好,那么就把它钉起来。也许你可以注释掉那些糟糕的代码,显示一行“尚未实现”的信息,或用假数据先替代一下。采取行动,预防进一步的损害发生,表明一切尽在你的掌握中。
提示6 做推动变革的催化剂
大多数软件灾难都始于微不足道的小事,项目的拖延也是一天天累积而成的。系统一个特性接一个特性地偏离规范,一个接一个的补丁加到代码上,最终原始代码无影无踪。往往就是一件件小事的累积破坏了团队和士气。
提示7 牢记全景
永远留意着大局,持续不断地审视你身边发生的事情,而不要只专注于你个人在做的事情。
提示8 将质量要求视为需求问题
投资知识,收益最佳。
——本杰明·富兰克林
管理知识组合和管理金融投资组合非常的类似:
正规投资者有定期投资的习惯。
多样化是长线成功的关键。
聪明的投资者会平衡保守型和高风险高回报型投资的组合。
投资者用低买高卖来获得最大的回报。
应定期审查和重新平衡投资组合。
提示9 对知识组合做定期投资
每年学习一门新语言
每月读一本技术书
还要读非技术书
上课
加入本地的用户组和交流群
尝试不同的环境
与时俱进
学习的机会
批判性思维
提示10 批判性地分析你读到和听到的东西
提示11 英语就是另一门编程语言
了解听众。
明白自己想说什么。
选择时机。
挑选风格。
让它看起来不错。
让听众参与。
做倾听者。
回应别人。
提示12 说什么和怎么说同样重要
越是有效的交流,影响力就越大。
提示13 把文档嵌进去,而不要栓在表面
注释源码是一个绝佳的机会,可以用来记录那些在其他地方无法记录的项目细节:工程上的权衡,为什么要做决定,放弃了哪些替代方案,等等。
接下来的两部分:DRY—邪恶的重复和正交性,有紧密关联。前一个提醒你不要在系统中复制知识,后一个阐述了不要把同一块知识切分到多个系统组件中。
提示14 优秀的设计比糟糕的设计更容易变更
为什么解耦很好?因为通过隔离关注焦点,可让每一部分都容易变更—此谓ETC。
ETC是一种价值观念,不是一条规则。
ETC里有一个隐含的前提。
第一件事,假设不确定什么形式的改变会发生,你也总是可以回到终极的“容易变更”的道路上:试着让你写的东西可替换。
第二件事,把它当作培养直觉的一种方式。在工程日志中记下你面临的处境:你有哪些选择,以及关于改变的一些猜测。
提示15 DRY—不要重复自己
唯一的方法是遵循下面这条被称为DRY的原则:在一个系统中,每一处知识都必须单一、明确、权威地表达。
DRY 针对的是你对知识和意图的复制。它强调的是,在两个地方表达的东西其实是相同的,只是表达方式有可能完全不同。
提示16 让复用变得更容易
你要努力的方向,应该是孕育出一个更容易找到和复用已有事物的环境,而不是自己重新编写。
提示17 消除不相关事物之间的影响
但凡编写正交的系统,就能获得两个主要的收益:提高生产力及降低风险。
有几种技术可以用来保持正交性:
保持代码解耦
避免全局数据
避免相似的函数
养成不断质疑代码的习惯
测试
由于系统组件之间的交互是形式化的,且交互有限,因此可以在单个模块级别上执行更多的系统测试。
编写单元测试本身就是一个有趣的正交性测试
修Bug也是评估整个系统的正交性的好时机
提示18 不设最终决定
提示19 放弃追逐时尚
要让你的代码具备“摇滚”精神:顺境时摇摆滚动,逆境时直面困难。
12 曳光弹
曳光弹之所以有用,是因为其工作环境和约束与真实子弹的相同。曳光弹能快速抵达目标,所以枪手可以得到即时的反馈。
提示20 使用曳光弹找到目标
曳光弹式开发和项目不会结束这种理念是一致的:总有东西需要改,总有新功能需要加。这是一个逐步递增的方法。
提示21 用原型学习
由于原型需要跳过细节,专注于它所考虑的系统的特定方面,所以你可能想用高阶脚本语言来实现原型。
脚本语言也可以很好地充当“粘合剂”,将低阶代码块组合成新的搭配。
提示22 靠近问题域编程
领域语言语言之界限,即是一个人世界之界限。
提示23 通过估算来避免意外
吃掉大象:
检查需求分析风险
设计、实现、集成
和用户一起验证
一次次地迭代下去,提炼出的东西会变得更好,对进度的信心也会随之增长。这种评估工作通常在每个迭代周期的末尾团队进行回顾时完成。
提示24 根据代码不断迭代进度表
把提炼进度表作为每次迭代的一部分,你就可以估算出能力范围内最精确的进度安排。
提示25 将知识用纯文本保存
我们把需求以知识的形式收集起来,然后在设计、实现、测试和文档中表达这些知识。
纯文本赋予了我们操作知识的能力
为防备老化而加保险
利用杠杆效应让已有工具发挥最大优势
易于测试
提示26 发挥Shell命令的威力
在Shell中,你可以调用所有能用的工具,或通过管道用各种方式把工具组合起来—恐怕开发者自己做梦都不会想到,自己当初开发的工具会被这么使用。
提示27 游刃有余地使用编辑器
怎么才算游刃有余。这里有一个挑战列表:
当编辑文本时,以字符、单词、行、段落为单位移动光标及进行选择。
当编辑代码时,在各种语法单元(配对的分隔符、函数、模块……)之间移动。
做完修改后,重新缩进代码。
用单个指令完成代码块的注释或取消注释。
Undo并Redo变更。
把编辑窗口切割成多个面板,然后在它们之间跳转。
跳转到特定的行号。
对选出的多行进行排序。
搜索普通字符串,或用正则表达式搜索,然后重复上一次的搜索。
基于框选或某个模式匹配的结果,临时创建多个光标,并行地在多个光标处编辑文本。
显示当前项目的编译错误。
跑一下当前项目的测试。能不能不用鼠标/触控板完成上面所有的任务?
首先,编辑时要自省。每次发现自己又在重复做某件事情的时候,要习惯性地想到“或许有更好的方法”,然后找到这个方法。
藏起鼠标/触摸板,一整个星期只用键盘。如果发现有大量的事情,离开点击你就干不了了,那么正好学习一下该怎么干。
提示28 永远使用版本控制
把版本控制视为项目中枢。
提示29 去解决问题,而不是责备
Bug是你的错还是别人的错并不重要。无论是谁的错,问题仍然要你来面对。
调试心态。
最容易欺骗的人就是自己。
提示30 不要恐慌
人们很容易陷入恐慌,尤其是当最后期限逼近,或是在老板或客户站在背后紧张凝视之下,拼命找出问题原因的时候。
如果你在看到Bug或Bug报告时的第一反应是“这不可能”,那你就大错特错了。不要在“但那不可能发生”的思路上浪费哪怕一个神经元,因为很明显它会发生,而且已经发生了。
永远要去发掘问题的根本原因,而不仅仅停留在问题的表面现象。
从哪里开始。
请确保正在处理的代码可以干净构建——没有警告。
当错误报告来自第三方时,Bug报告的准确性会进一步降低——实际上,你可能需要观察提交错误报告的用户,通过其操作来获得足够详细的信息。
调试策略。
复制Bug。
提示31 修代码前先让代码在测试中失败
提示32 读一下那些该死的出错信息
通常有一种比逐个检查每个栈帧更快的方法来发现问题:使用二分法。但是在讨论二分法之前,让我们先看看另外两个常见的Bug场景。
输入值的敏感度。
获取数据集的副本,并用数据测试本地运行的应用程序副本,确保其在本地也能崩溃。
版本间回退。
二分法。
不断分割数据,直到得到能显露问题的最小集。
输出日志及(或)跟踪信息。
通过使用文本处理工具或Shell命令来处理日志文件,就可以很容易地识别出,有问题的打开操作发生在哪里。
排除法。
提示33 “select”没出问题
有时改变的东西超出了你的控制范围:更新操作系统、编译器、数据库或其他第三方软件的版本,可能会破坏以前正确的代码,因而出现新的Bug。
不要因为“觉得”一个程序或一段代码没问题,就在它牵涉一个Bug时,对它视而不见。你需要证明它没问题,用出Bug时的上下文、同样的数据、当时的边界条件来证明它没问题。
提示34 不要假设,要证明
如果Bug是损坏的数据造成的结果,而数据引爆程序前经过几层逐级传播,可以试试给函数加上更完备的参数检查,以便更早地将问题剥离出来。
如果修复这个Bug花了很长时间,问问自己为什么。你能做些什么来让下次修复这个Bug更容易呢?也许可以构建更好的测试钩子,或是编写一个日志文件分析器。
如果Bug是因为某人的错误假设造成的,那么就与整个团队讨论这个问题:如果一个人误解了,那么很可能很多人都误解了。
调试工作的清单。
提示35 学习一门文本处理语言
提示36 你无法写出完美的软件
我们需要防御性驾驶。在麻烦发生之前就做好准备,预料到意料之外的事情,永远不要把自己置于无法自拔的境地。
我们被教导要防御式编程——有任何疑问,都要去验证我们得到的一切信息;使用断言来检测错误数据,不信任任何可能来自潜在攻击者或有恶意者的数据;做一致性检查,对数据库的列设置约束——做完这些,我们通常就会自我感觉良好。
务实的程序员则更进一步,他们连自己也不相信。既然没人能写出完美的代码,那么也包括自己在内。
务实的程序员会为自己的错误建立防御机制。
最重要的一点是,只要我们总是坚持走小步,按照不要冲出前灯范围中描述的那样,就不会从悬崖边掉下去。
“当所有人都真的在给你找麻烦的时候,偏执就是一个好主意。”
提示37 通过契约进行设计
请记住,如果你订的契约是可以接受任何东西,并且承诺要回报整个世界,那么你就有很多代码要写!
类的不变式与函数式语言。
DBC与测试驱动开发。
实现DBC。
在编写代码之前,简单地列出输入域的范围、边界条件是什么、例程承诺要交付什么——或者更重要的是,没有承诺要交付什么——这些对编写更好的软件来说,是一个巨大的飞跃。
断言。
因为契约最大的用途,就体现在你的代码和它所使用的库之间的边界处,这里通常会检测到最多的问题。
DBC与尽早崩溃。
谁的责任。
语义不变式。
出错时要偏向消费者。
提示38 尽早崩溃
崩溃,不要制造垃圾。
一旦代码发现本来不可能发生的事情已发生,程序就不再可靠。
一个死掉的程序,通常比一个瘫痪的程序,造成的损害要小得多。
提示39 使用断言去预防不可能的事情
论何时,你发现自己在想“当然这是不可能发生的”时,添加代码来检查这一点。最简单的方法是使用断言。
提示40 有始有终
无论在什么时候,我们写代码都要管理资源:内存、事务、线程、网络连接、文件、计时器——所有可用的数量有限的东西。大多数情况下,资源使用遵循一个可预测的模式:分配资源,使用它,然后释放它。
当有疑问时,缩小范围总是有好处的。
提示41 在局部行动
嵌套的分配。
释放资源的顺序与分配资源的顺序相反。
在代码的不同位置,如果都会分配同一组资源,就始终以相同的顺序分配它们。
长期的平衡。
对象与异常。
保持平衡与异常。
当你无法保持资源的平衡时。
检查平衡。
因为务实的程序员不相信任何人,包括自己。
提示42 小步前进——由始至终
总是采取经过深思熟虑的小步骤,同时检查反馈,并在推进前不断调整。把反馈的频率当作速度限制,永远不要进行“太大”的步骤或任务。
越是必须预测未来会怎样,就越有可能犯错。与其浪费精力为不确定的未来做设计,还不如将代码设计成可替换的。
提示43 避免占卜
很多时候,明天看起来会和今天差不多,但不要指望一定会这样。
当我们试着单独挑出一个事物的时候,总会发现它与宇宙中其他一切都有关联。
提示44 解耦代码让改变更容易
提示45 只管命令不要询问
这个原则说的是,不应该根据对象的内部状态做出决策,然后更新该对象。这样做完全破坏了封装的优势,并且在这样做时,也会把实现相关的知识扩散到整个代码中。
提示46 不要链式调用方法
提示47 避免全局数据
全局数据包括单件。
全局数据包括外部资源。
提示48 如果全局唯一非常重要,那么将它包装到API中
继承增加了耦合。
一切都是为了变更。
让代码害羞一点:让它只处理直接知道的事情,这将有助于保持应用程序解耦,使其更易于变更。
如果你不能将正在做的事情描述为一个流程,那表示你不知道自己正在做什么。
提示49 编程讲的是代码,而程序谈的是数据
提示50 不要囤积状态,传递下去
提示51 不要付继承税
提示52 尽量用接口来表达多态
提示53 用委托提供服务:“有一个”胜过“是一个”
提示54 利用mixin共享功能
物归其所,事定期限。
提示55 使用外部配置参数化应用程序
提示56 通过分析工作流来提高并发性
共享状态是不正确的状态
提示57 共享状态是不正确的状态
提示58 随机故障通常是并发问题
角色是一个独立的虚拟处理单元,具有自己的本地(且私有的)状态。
进程通常代表一种更通用的虚拟处理机,它一般由操作系统实现,可以让并发处理更容易。进程也能(根据约定)被约束为以角色的形式运转,我们在这里说的就是这类进程。
提示59 用角色实现并发性时不必共享状态
提示60 使用黑板来协调工作流
提示61 倾听你内心的蜥蜴
首先,停止正在做的事情。给自己一点时间和空间,让大脑自我组织。
让想法自己从大脑的各个层面渗透出来:对此不用很刻意。最终这些想法可能会上升到有意识的水平,这样你就能抓住一个“啊哈!”的时刻。
学会在编码时听从直觉是一项需要培养的重要技能。
不要假设,要证明。
找到恰好能用的答案和找到正确的答案不是一回事。
提示62 不要依赖巧合编程
如果希望花费更少的时间来编写代码,就要在开发周期中尽可能早地捕获并修复错误,这样可以一开始就少犯错。
不要成为历史的奴隶。不要让现有的代码去支配未来的代码。如果不再合适,所有代码都可以替换。即使一个程序正在进展中,也不要让已经做完的事情限制下一步要做的事情——准备好重构。
所以下次碰到有什么事情看起来可行,但你不知道为什么,确保它不是一个巧合。
提示63 评估算法的级别
提示64 对估算做测试
最好的不会永远最好。
在投入宝贵的时间尝试改进算法之前,确保算法确实是瓶颈,总是最为可取。
提示65 尽早重构,经常重构
重构的核心是重新设计。
不要试图让重构和添加功能同时进行。
在开始重构之前,确保有良好的测试。
采取简短而慎重的步骤
提示66 测试与找Bug无关
测试获得的主要好处发生在你考虑测试及编写测试的时候,而不是在运行测试的时候。
提示67 测试是代码的第一个用户
测试驱动开发。
TDD的基本循环是:
决定要添加一小部分功能。
编写一个测试。
运行所有测试。
尽量少写代码,只需保证测试通过即可。
重构代码:看看是否有办法改进刚刚编写的代码(测试或函数)。
务必实践一下TDD。但真这样做时,不要忘记时不时停下来看看大局。
提示68 既非自上而下,也不自下而上,基于端对端构建
我们坚信,构建软件的唯一方法是增量式的。构建端到端功能的小块,一边工作一边了解问题。应用学到的知识持续充实代码,让客户参与每一个步骤并让他们指导这个过程。
测试对开发的驱动绝对能有帮助。但是,就像每次驱动汽车一样,除非心里有一个目的地,否则就可能会兜圈子。
提示69 为测试做设计
如果代码出过一次问题,就有再出问题的可能性。不要将创建出来的测试扔掉,把它添加到现有的单元测试库中。
我的个性坚持认为,当开始觉得舒适的时候,就应该去尝试别的东西。
我相信这个原因就是,(对我来说)测试的好处更主要来自于思考测试,以及思考测试会对代码造成怎样的影响。在长时间坚持这样做之后,我写不写测试都会这样思考。代码仍然是可测试的,只是无须真的写出测试而已。
提示70 要对软件做测试,否则只能留给用户去做
提示71 使用基于特性的测试来校验假设
当基于特性的测试失败时,找出传递给测试函数的参数,然后使用这些值创建一个单独的、常规的单元测试。
基于特性的测试让你从不变式和契约的角度来考虑代码;你会思考什么不能改变,什么必须是真实的。这种额外的洞察力会对代码产生神奇的影响,可以消除边界情况,并突显使数据处于不一致状态的函数。
安全性的基本原则
将攻击面的面积最小化
最小特权原则
安全的默认值
敏感数据要加密
维护安全更新
提示72 保持代码简洁,让攻击面最小
提示73 尽早打上安全补丁
不要禁用浏览器中的粘贴功能。破坏浏览器和密码管理器的功能,并不能使系统更安全。实际上,它会促使用户创建更简单、更短、更容易破解的密码。
当涉及加密时,第一条也是最重要的一条规则是,永远不要自己做。
名不正,则言不顺;言不顺,则事不成。
提示74 好好取名;需要时更名
所谓完美境界,亦非加无可加,而是减无可减……
提示75 无人确切知道自己想要什么
提示76 程序员帮助人们理解他们想要什么
提示77 需求是从反馈循环中学到的
每次迭代都以客户的直接反馈结束。这样可使我们走上正轨,并确保如果走错了方向,损失的时间是最少的。
提示78 和用户一起工作以便从用户角度思考
提示79 策略即元数
针对更普遍的情况做实现,至于系统需要支持的那种特定类型的东西,只是通用实现在加入策略信息后的示例。
提示80 使用项目术语表
提示81 不要跳出框框思考——找到框框
简单地说,注意力分散的人在解决复杂问题时比有意识的人做得更好。
打造代码,而非打造自我。这与谁最聪明无关;我们都有许多闪光的瞬间,也有糟糕的时刻。
批评要针对代码,而不针对人。“让我们看看这一块”听起来比“你搞错了”好得多。
倾听他人的观点并试着理解。观点不同不是错误。
频繁进行回顾,为下一次做好准备。
提示82 不要一个人埋头钻进代码中
提示83 敏捷不是一个名词;敏捷有关你如何做事
所以下面是我们以敏捷方式工作的秘诀:
弄清楚你在哪里。
朝想去的方向迈出有意义的最小一步。
评估在哪里终结,把弄坏的东西修好。
由“魔法三连”:版本控制、测试和自动化组成的务实的入门套件。
提示84 维持小而稳定的团队
质量是一个团队问题。即使是最勤奋的开发者,只要身处一个什么都不在乎的团队中,也会发现自己很难保持修复琐碎问题所需的热情。如果团队不鼓励开发者在这些修复工作上花费时间,那么问题就会进一步恶化。
对项目范围扩大、时间缩短、额外特性、新的环境——任何在最初的理解中没有的东西,都要留心。
“只要有空闲时间”就去做,意味着这件事永远不会发生。
提示85 排上日程以待其成
良好的沟通是避免这些问题的关键。这里所说的“良好”,指的是即时、无摩擦力。
保持清醒,留意DRY 。
提示86 组织全功能的团队
记住团队是由个人组成的。赋予每个成员能力,让他们以自己的方式发光发热。要提供完善的架构来支持他们,并确保项目交付的价值。
提示87 做能起作用的事,别赶时髦
怎样才能知道“什么能起作用”?有一个最基本的实用技巧可以依靠,那就是:
试一试。
请注意,能够即期交付并不意味着你必须每天每分钟都交付。只有当这样做在业务上有意义时,才有必要在用户需要时即期交付。
提示88 在用户需要时交付
过度投资于任何一种特定的方法,会让你对其他方法视而不见。当你习惯于一种方法时,很快就看不到其他的出路了。你已经僵化,变得不再能快速适应。
提示89 使用版本控制来驱动构建、测试和发布
提示90 尽早测试,经常测试,自动测试
提示91 直到所有的测试都已运行,编码才算完成
构建可能包括几种主要的软件测试类型:单元测试、集成测试、确认和验证,以及性能测试。
提示92 使用破坏者检测你的测试
提示93 测试状态覆盖率,而非代码覆盖率
提示94 每个Bug只找一次
提示95 不要使用手动程序
一切都要依赖于自动化。
用户真正要的不是代码,他们只是遇到某个业务问题,需要在目标和预算范围内解决。他们的信念是,通过与你的团队合作,能够做到这一点。
“需求”实际上只是对用技术可以完成哪些工作的猜测——它实际上是一个业余的实现计划,只是伪装成需求文档。如果你能证明有方法会使项目更接近目标,那么就不要害怕,大胆提出改变需求的建议。
提示96 取悦用户,而不要只是交付代码
或许你的头衔只是“软件开发者”或“软件工程师”的某种变体,而事实上这个头衔应该是“解决问题的人”。这就是我们所做的,也是一个务实的程序员的本质。
提示97 在作品上签名
过去的工匠很自豪地为他们的作品签名。你也应该这样。
保持匿名会滋生粗心、错误、懒惰和糟糕的代码,特别是在大型项目中——很容易把自己看成只是大齿轮上的一个小齿,在无休止的工作汇报中制造蹩脚的借口,而不是写出好的代码。
我们这些开发者,拥有令人难以置信的特权——我们真正在建设未来,这是一股巨大的力量。伴随着这种力量而来的,是一种非同寻常的责任。
提示98 先勿伤害
有一些创造性的想法,开始打道德行为界限的擦边球,如果你参与了这类项目,就和出资者一样负有责任。
提示99 不要助纣为虐
Title: 程序员修炼之道:通向务实的最高境界(第2版)
Author: Amber
Date: 2025-06-20
Last Update: 2025-06-19
Blog Link: https://wyiyi.github.io/amber/2025/06/20/the-pragmatic-programmer/
Copyright Declaration: Copyright © 2022 Amber.