《程序员修炼之道/The Pragmatic Programmer》摘记
背景
提示
提示1 关注你的技艺
思考:
如题,如果不关注技艺,那就没有什么好关注的了。
应用:
提示2 思考!思考你的工作
思考:
为了成为一名务实的程序员,我们要求你在做事的时候,思考一下自己正在做什么。这不是对当前实践做的一次性审计——而是对每天里每一个项目所做的每一个决定进行的批判性评估。不要用自动辅助驾驶系统偷懒,而是要不断地思考,即时地批判自己的工作。
IBM 公司的座右铭“思考!”,实属每个务实程序员的真言。
应用:
提示3 你有权选择
思考:
如题。
应用:
提示4 提供选择,别找借口
思考:
在你的职业发展、学习教育,以及你的项目、每天的工作等各方面对你自己负责,对你的行为负责,承担相应的义务,这是务实哲学的基石之一。
应用:
提示5 不要放任破窗
思考:
不要搁置“破窗”(糟糕的设计、错误的决定、低劣的代码)不去修理。每发现一个就赶紧修一个。如果没有足够的时间完全修好,那么就把它钉起来。一定要告诉自己,“不要打破窗户。”
应用:
提示6 做推动变革的催化剂
思考:
每个人都会守着自己的一亩三分田。你可能处在这样一种状况下——整个系统就在你的眼前,清楚地知道需要做些什么,以及怎样去做。在这种情况下,找出你合理的请求,然后不断完善。
应用:
提示7 牢记全景
思考:
不要学寓言里的青蛙,永远留意着大局,持续不断地审视你身边发生的事情,而不要只专注于你个人在做的事情。
应用:
提示8 将质量要求视为需求问题
思考:
你能训练自己写出够好即可的软件——对用户、未来的维护者来说够好即可,只要好的程度能让你自己内心平静就可以。所有系统必须达到用户的需求才算完成,需要达到基本的性能、隐私和安全标准。不要让过度的修饰和精炼侵蚀掉一个完好的程序,它或许并不完美,不要紧的——它就算永不完美也没关系。
应用:
提示9 对知识组合做定期投资
思考:
学习新事物的能力是你最重要的战略资产。我们可以将程序员所了解的一切有关计算过程的事实、工作的应用领域,以及所有经验,视为他们拥有的知识组合。持续投资非常重要。一旦你进入了对某个新语言或新技术的舒适期,向前走,再学一个。学习的过程将会扩展你的思维,为你打开全新可能性的大门,让你领悟新的做事方式。
想法的交叉传授是很重要的;试着把你领悟到的东西应用到你当前的项目中。即使项目没有用到某项技术,你也可以借鉴一些想法。
管理知识组合和管理金融投资组合非常的类似:
- 正规投资者有定期投资的习惯。
- 多样化是长线成功的关键。
- 聪明的投资者会平衡保守型和高风险高回报型投资的组合。
- 投资者用低买高卖来获得最大的回报。
- 应定期审查和重新平衡投资组合。
建议:
每年学习一门新语言,每月读一本技术书,还要读非技术书,上课,加入本地的用户组和交流群,尝试不同的环境,与时俱进。
应用:
提示10 批判性地分析你读到和听到的东西
思考:
问“五个为什么”,谁从中受益,有什么背景,什么时候在哪里可以工作起来,为什么这是个问题。
应用:
提示11 英语就是另一门编程语言
思考:
把英语(或者你的母语是别的什么语言)看成另一门编程语言。像写代码一样用自然语言写文章:尊重DRY原则、ETC、自动化,等等。
应用:
提示12 说什么和怎么说同样重要
思考:
了解听众,明白自己想说什么,选择时机,挑选风格,让它看起来不错,让听众参与,做倾听者,回应别人。
应用:
提示13 把文档嵌进去,而不要栓在表面
思考:
用源码中的注释生成好看的文档非常容易,建议给模块和导出函数都加上注释,这能在其他开发者使用的时候,给他们很大的助力。
因此,将非API的注释限制在只用来讨论其为何存在及其意图、目标。当代码已经展示了事情怎样完成时,注释是多余的——因为这违反了DRY原则。
注释源码是一个绝佳的机会,可以用来记录那些在其他地方无法记录的项目细节:工程上的权衡,为什么要做决定,放弃了哪些替代方案,等等。
应用:
提示14 优秀的设计比糟糕的设计更容易变更(ETC)
思考:
能适应使用者的就是好的设计。对代码而言,就是要顺应变化。因此要信奉ETC原则(Easier To Change,更容易变更)——就该如此。
据我们所知,无论是什么设计原则,都是ETC的一个特例。
我们的经验是,一开始需要一点有意识的强化。你可能需要花一个星期左右的时间来有意识地问自己:“我刚刚做的事情是让整个系统更容易改变还是更难改变?”当你保存文件时问一遍,当你写测试时问一遍,当你修复Bug时也问一遍。
第一件事,假设不确定什么形式的改变会发生,你也总是可以回到终极的“容易变更”的道路上:试着让你写的东西可替换。做起来并不难,想着一直保持代码的解耦和内聚就够了。
第二件事,把它当作培养直觉的一种方式。在工程日志中记下你面临的处境:你有哪些选择,以及关于改变的一些猜测。
应用:
提示15 DRY——不要重复自己
思考:
在一个系统中,每一处知识都必须单一、明确、权威地表达。
当我们进行维护时,必须找到并变更事物的表达——那些嵌入程序的知识胶囊。问题是,在规范、流程、开发的程序中复制知识太容易了,一旦我们动手这么做,就会招致维护的噩梦——这个噩梦在程序发布前就会开始。
准确的命名即可表述清要做什么。如果有人需要了解更多细节,源码里应有尽有。这就是DRY!
无论什么时候,只要模块暴露出数据结构,就意味着,所有使用这个数据结构的代码和模块的实现产生了耦合。但凡有可能,都应采用一组访问器函数来读写对象的属性。如果未来需要增加功能,这样做能让事情更容易一些。一个模块提供的所有服务都应该通过统一的约定来提供,该约定不应表露出其内部实现是基于储存还是基于运算的。
应用:
提示16 让复用变得更容易
思考:
你要努力的方向,应该是孕育出一个更容易找到和复用已有事物的环境,而不是自己重新编写。
应用:
提示17 消除不相关事物之间的影响
思考:
我们希望设计的组件自成一体:独立自主,有单一的清晰定义的意图。当组件彼此隔离时,你知道可以变更其中一个组件,而不必担心影响到其他组件。只要不去改变组件的对外接口,就可以放心,不会发生波及整个系统的问题。但凡编写正交的系统,就能获得两个主要的收益:提高生产力及降低风险。使用DRY时,你追求最小化系统中的重复。反之,在使用正交时,则要去减少系统组件之间的相互依赖。
- 如一个特别功能背后的需求发生显著改变,有多少模块会受影响?
- 保持代码解耦,避免全局数据,避免相似的函数。
- 养成不断质疑代码的习惯。只要有机会就重新组织、改善其结构和正交性。
- 真正符合正交性的文档,应该能够在不改变内容的情况下显著地改变外观。
应用:
提示18 不设最终决定
思考:
如果某个想法是你唯一的想法,那就没有比它更危险的东西了。每做出一个关键决定,项目团队就会投身于一个更具体的目标——由于选择变少,视野会越来越狭隘。问题在于,关键的决定不易逆转。
错误在于认为任何决定都是板上钉钉的——而没有为可能出现的意外做好准备。与其认为决定是被刻在石头上的,还不如把它们想象成写在海滩的沙子上。一个大浪随时都可能袭来,卷走一切。
应用:
提示19 放弃追逐时尚
思考:
没有人知道未来会怎样,我们也不例外。要让你的代码具备“摇滚”精神:顺境时摇摆滚动,逆境时直面困难。
应用:
提示20 使用曳光弹找到目标
思考:
曳光弹之所以有用,是因为其工作环境和约束与真实子弹的相同。曳光弹能快速抵达目标,所以枪手可以得到即时的反馈。而且,从实用的观点来看,这是一个成本相对低的解决方案。
寻找重要的需求,那些定义了系统的需求。寻找你有疑问的地方,那些你认为有重大风险的地方。然后对开发进行优先级排序,首先从这些地方开始编码。
使用曳光代码有很多优势:用户可以更早地获得能工作的东西,开发者构造了一个可以在其中工作的框架,你有了一个集成平台,你有可以演示的东西,你对进度有更好的感觉。
应用:
提示21 用原型学习
思考:
原型被设计出来,只是为了回答几个问题,因此比要投入生产的应用程序成本更低,开发速度更快。其代码可以忽略一些不重要的细节——那些以后可能对用户非常重要,但目前还不重要的东西。
你会选择用原型来研究什么类型的东西呢?答案是,任何有风险的东西,任何之前没有尝试过或对最终系统来说很关键的东西,任何未经证实、实验性或可疑的东西,以及任何让你不舒服的东西。
原型设计是为了学习经验。它的价值不在于产生的代码,而在于吸取的教训。这正是原型的意义所在。
应用:
提示22 靠近问题域编程
思考:
花费的努力不要比节省下来的还多。编写领域语言会给项目增加一些成本,所以你需要确信省下的花销(在可预计的长期)足以抵消它。
应用:
提示23 通过估算来避免意外
思考:
在某种程度上,所有的答案都是估算,区别仅在于一些比另一些更精确。所以当有人让你估算的时候,你要问自己的第一个问题是,答案会用在什么场合下。对方需要很高的精度,还是只要一个大约的估计?
所有的估算都是基于对问题的建模。但是在我们深入建模技术之前,必须提到一个基本的估算技巧,用它总能给出不错的答案:问问已经做过的人。
所有的评估工作的首要部分都是建立对所问内容的理解。建模是估算中很有趣的部分。当你理解了被问的问题时,就开始为之建立一个粗略的思维模型框架。
应用:
提示24 根据代码不断迭代进度表
思考:
应用:
提示25 将知识用纯文本保存
思考:
为防备老化而加保险,利用杠杆效应让已有工具发挥最大优势,易于测试。事实上,在异构环境中使用纯文本,利远大于弊。当需要确保有一个所有各方都能使用的公共标准,才能实现相互沟通时,纯文本就是这个标准。
应用:
提示26 发挥 Shell 命令的威力
思考:
对于操作文本文件的程序员来说,工作台就是指令Shell。但是,如果使用图形界面去完成所有工作,就会错失环境的全部能力,你将无法把常见的任务自动化,或是无法充分利用工具所能提供的强大功能,并且,你也无法通过组合你的工具来创建定制的宏工具。图形工具的好处在于WYSIWYG ——所见即所得;弱势之处是WYSIAYG——所见即全部。
应用:
提示27 游刃有余地使用编辑器
思考:
编辑时要自省。每次发现自己又在重复做某件事情的时候,要习惯性地想到“或许有更好的方法”,然后找到这个方法。一旦你发掘出一个新的有用的特性,需要尽快把它内化成一种肌肉记忆,这样在使用的时候就能不假思索。据我们所知,能做到这点的唯一方法只有不断重复。
应用:
提示28 永远使用版本控制
思考:
分支的第一个好处是为你提供了隔离。如果你在一个分支中开发了特性 A ,而另一个团队成员在另一个分支上开发了特性 B,你们之间不会相互干扰。
第二个好处是团队项目的工作流核心通常围绕着分支来开展。
自测试验:把一整杯茶倒在笔记本上;然后把机器拿到天才吧,让他们折腾去;再买一台新的带回家。你需要多久,才能把机器恢复到当初的状态?就是举起那只致命的杯子时的状态,包括所有的 SSH 热键、编辑器配置、Shell 设置、安装的软件,等等。
应用:
提示29 去解决问题,而不是责备
思考:
应用:
提示30 不要恐慌
思考:
永远要去发掘问题的根本原因,而不仅仅停留在问题的表面现象。
应用:
提示31 修代码前先让代码在测试中失败
思考:
应用:
提示32 读一下那些该死的出错信息
思考:
应用:
提示33 “select”没出问题
思考:
如果你“只改变了一个东西”,然后系统就不工作了,那么这个东西就最可能直接或间接地负有责任,不管看起来多么牵强。
应用:
提示34 不要假设,要证明
思考:
应用:
提示35 学习一门文本处理语言
思考:
纯文本的文本处理具有广泛的适用性,是一种复利投资。
应用:
- 书籍要点提取及格式化。在做本书摘记时,想要将每条提示摘选出来,作为文章的三级标题,并增加思考和应用环节。具体做法:Python读取本书txt,正则提取提示内容,使用format格式化,内容输出到markdown,效率确实很高;
additional 工程日记
思考:
工程日记比记忆更可靠,它为你提供了一个地方,用来保存与当前任务无关的想法,这样你就可以继续专注于正在做的事情,并知道这个伟大的想法不会被遗忘。也可以记录决策过程,用于后续回顾。
应用:
提示36 你无法写出完美的软件
思考:
在麻烦发生之前就做好准备,预料到意料之外的事情,永远不要把自己置于无法自拔的境地。
应用:
提示37 通过契约进行设计
思考:
前置条件:为调用这个例程,必须为真的是什么?一个例程永远不应该在前置条件被违反的时候被调用。传递良好的数据是调用者的责任。
后置条件:例程保证要做的是什么?例程完成时世界的状态。例程有后置条件这个事实,意味着能得出这样的结论——不允许无限循环。
类的不变式:从调用者的角度来看,类会确保该条件始终为真。在例程的内部处理期间,可以不遵守不变式,但是当例程退出并将控制权返回给调用者时,不变式必须为真。
例程和任何潜在调用者之间的契约因此可以被解读为如果调用者满足了例程的所有前置条件,则例程应保证在完成时所有后置条件和不变式都为真。
一定不要把固定的、不可违背的需求,与那些仅仅可能是随着新管理层上任而改变的策略相混淆。这就是我们使用语义不变式这个术语的原因——它必须是事物意义的核心,而不受策略的影响(策略用于更动态的业务规则)。
应用:
提示38 尽早崩溃
思考:
尽快检测问题的好处之一是,可以更早崩溃,而崩溃通常是你能做的最好的事情。
应用:
提示39 使用断言去预防不可能的事情
思考:
应用:
提示40 有始有终
思考:
应用:
提示41 在局部行动
思考:
不管我们使用什么类型的资源——事务、网络连接、内存、文件、线程、窗口,基本的模式都是适用的:分配资源的人应该负责释放它。
应用:
提示42 小步前进——由始至终
思考:
总是采取经过深思熟虑的小步骤,同时检查反馈,并在推进前不断调整。把反馈的频率当作速度限制,永远不要进行“太大”的步骤或任务。
应用:
提示43 避免占卜
思考:
很多时候,明天看起来会和今天差不多,但不要指望一定会这样。
应用:
提示44 解耦代码让改变更容易
思考:
耦合是修改之敌,因为它将事情连接在一起,要改就得一起改。这使得修改变得更加困难:要么需要花上不少时间,弄清楚所有需要修改的地方到底有哪些,要么又会因为“仅仅只修改一处”而没有跟着改与之相耦合的地方,把时间花在想明白为什么会出问题上。
应用:
提示45 只管命令不要询问
思考:
应用:
提示46 不要链式调用方法
思考:
应用:
提示47 避免全局数据
思考:
应用:
提示48 如果全局唯一非常重要,那么将它包装到API 中
思考:
应用:
additional 事件流
思考:
流让我们把事件当作数据集合来对待。这就好像我们有一个事件列表,当新事件到达时,列表会变长。它的美妙之处在于,我们可以像对待任何其他集合一样对待流:我们可以操作、合并、过滤,以及做我们所熟知的所有其他针对数据所做的事情。我们不再须要将时间视为必须管理的东西。事件流将同步和异步处理统一到一个通用的、方便的 API之后。但是,无论事件源是什么,围绕事件编写的代码都比对应的线性代码更容易响应,解耦效果也更好。
应用:
提示49 编程讲的是代码,而程序谈的是数据
思考:
数据成为与功能对等的东西:管道是一系列的代码→数据→代码→数据……数据不再和特定的函数组一起绑定在类定义中。相反,当应用程序将其输入转换为输出时,可以自由地表达自己的展开过程。这意味着我们可以极大地减少耦合:一个函数可以在任何地方使用(并重用),只要其参数与其他函数的输出相匹配。有许多方法可以做到这一点,但是所有方法都依赖于一个基础约定:永远不在变换之间传递原始值。取而代之的是,将值封装在一个数据结构(或类型)中,该结构可以告知我们所包含的值是否有效。
应用:
提示50 不要囤积状态,传递下去
思考:
应用:
提示51 不要付继承税
思考:
针对传统的类继承的三个替代方案:接口与协议,委托,mixin与特征。
应用:
提示52 尽量用接口来表达多态
思考:
应用:
提示53 用委托提供服务:“有一个”胜过“是一个”
思考:
应用:
提示54 利用 mixin 共享功能
思考:
应用:
提示55 使用外部配置参数化应用程序
思考:
如果代码依赖某些值,而这些值在应用程序发布后还有可能改变,那么就把这些值放在程序外部。基本上,对于任何以后必须要改而又可以表达在代码主体之外的内容,只要事先知道,就要找出来并放入某个配置容器。通过外部配置,提升代码的适应性和灵活性。
应用:
- Python路径外部配置。在不同终端运行Python脚本,需要读取相关文件夹的内容,如果将路径写在程序中,适应性不够。做法:将路径写入到配置文件中,每个终端使用不同的配置,Python脚本代码不变,从配置中读取路径。
提示56 通过分析工作流来提高并发性
思考:
活动图由一组用圆角框表示的活动构成。从一个活动出发的箭头可以指向另一个活动(这个活动能在前一个活动完成后启动),也可以指向被称为同步条的粗实线。一旦指向同步条的所有活动都已完成,就可以处理所有离开同步条的箭头。如果一个活动没有被任何箭头指向,就可以在任意时间启动。
记住两者的区别:并发性是一种软件机制,而并行性则和硬件相关。
最理想的是,将工作分成相对独立的一块一块——每一块工作都能独立进行,而不需要为其他部分做出任何等待。
应用:
提示57 共享状态是不正确的状态
思考:
简单而言,信号量是一个在同一时间只能让一个人持有的东西。你可以创建一个信号量,然后利用它来控制对其他资源的访问。在我们的示例中,可以创建一个信号量来控制对派的陈列柜的访问。采用这样的约定:任何想要更新陈列柜内容的人,只有在持有该信号量的情况下才能行动。
应用:
提示58 随机故障通常是并发问题
思考:
应用:
提示59 用角色实现并发性时不必共享状态
思考:
应用:
提示60 使用黑板来协调工作流
思考:
数据到达的顺序无关紧要:当发布一个事实时,可以触发适当的规则。反馈也很容易处理:任何一组规则的输出都可以发布到黑板上,从而触发更多适用的规则。
应用:
提示61 倾听你内心的蜥蜴
思考:
本能就是我们的无意识大脑对模式的一种直接反应,有些是天生的,有些是通过不断重复学习到的。无论直觉是怎么来的,都有一个共同点:无法用语言表达。直觉让你感觉,而不是思考。
诀窍首先是注意到它正在发生,然后找出原因。你一直在积累经验和智慧。如果能感到一种挥之不去的疑虑,或在面对一项任务时感觉有些不情愿,那可能是那些经验试图和你说些什么——要注意听。你可能无法确切地指出哪里出了问题,但经过一段时间后,疑虑可能会变得实在,变成可以确定的东西。让直觉来提高你的绩效。
首先,停止正在做的事情。给自己一点时间和空间,让大脑自我组织。远离键盘,停止对代码的思考,做一些暂时不需要动脑筋的事情——散步、吃午饭、和别人聊天,或是先睡一觉。让想法自己从大脑的各个层面渗透出来:对此不用很刻意。最终这些想法可能会上升到有意识的水平,这样你就能抓住一个“啊哈!”的时刻。
应用:
提示62 不要依赖巧合编程
思考:
- 时刻注意你在做什么。要按计划推进,不管这个计划是在脑子里,还是在鸡尾酒餐巾纸的背面,或是在白板上。
- 只依赖可靠的东西。不要依赖假设。将假设文档化。
- 为你的精力投放排一个优先级。不要成为历史的奴隶。不要让现有的代码去支配未来的代码。如果不再合适,所有代码都可以替换。
应用:
提示63 评估算法的级别
思考:
应用:
提示64 对估算做测试
思考:
应用:
提示65 尽早重构,经常重构
思考:
随着程序的演化,有必要重新考虑早期的决策,对部分代码进行返工。这个过程理所当然。代码需要演化;它不是一个静态的东西。
重构是重组现有代码实体、改变其内部结构而不改变其外部行为的规范式技术。当你学到一些东西时,当你比去年、昨天甚至十分钟前更了解某事时,你会重构。
重构的核心是重新设计。
- 不要试图让重构和添加功能同时进行。
- 在开始重构之前,确保有良好的测试。尽可能多地运行测试。
- 采取简短而慎重的步骤:将字段从一个类移动到另一个类,拆分方法,重命名变量。
应用:
提示66 测试与找 Bug 无关
思考:
应用:
提示67 测试是代码的第一个用户
思考:
TDD 的基本循环是:
- 决定要添加一小部分功能。
- 编写一个测试。等相应功能实现后,该测试会通过。
- 运行所有测试。验证一下,是否只有刚刚编写的那个测试失败了。
- 尽量少写代码,只需保证测试通过即可。验证一下,测试现在是否可以干净地运行。
- 重构代码:看看是否有办法改进刚刚编写的代码(测试或函数)。确保完成时测试仍然通过。
应用:
提示68 既非自上而下,也不自下而上,基于端对端构建
思考:
我们坚信,构建软件的唯一方法是增量式的。
构建端到端功能的小块,一边工作一边了解问题;应用学到的知识持续充实代码,让客户参与每一个步骤并让他们指导这个过程;不是由测试驱动,而是——从对传统上如何解决这类问题(使用约束传播)的基本理解开始,然后专注于改进算法。
应用:
提示69 为测试做设计
思考:
你编写的所有软件最终都将被测试——如果不是由你和你的团队做测试,那么就将由最终的用户去测试——所以不妨计划好进行彻底的测试。
应用:
提示70 要对软件做测试,否则只能留给用户去做
思考:
应用:
提示71 使用基于特性的测试来校验假设
思考:
单元测试是 API 的第一个客户。
应用:
提示72 保持代码简洁,让攻击面最小
思考:
- 将攻击面的面积最小化
- 最小特权原则
- 安全的默认值
- 敏感数据要加密
- 维护安全更新
应用:
提示73 尽早打上安全补丁
思考:
当涉及加密时,第一条也是最重要的一条规则是,永远不要自己做。
应用:
提示74 好好取名;需要时更名
思考:
名字里有什么?当我们编程时,名字里有“一切”。我们认为,事物应该根据它们在代码中扮演的角色来命名。这意味着,无论何时,只要你有所创造,就需要停下来思考“我这一创造的动机是什么?”
应用:
提示75 无人确切知道自己想要什么
思考:
应用:
提示76 程序员帮助人们理解他们想要什么
思考:
根据我们的经验,最初对需求的声明,往往并非绝对化的要求。客户可能没有意识到这一点,但一定希望你能一起去探索。
应用:
提示77 需求是从反馈循环中学到的
思考:
生成需求文档的另一大危险是过于具体。好的需求是抽象的。就需求而言,最简单最能准确反映业务需求的语句是最好的。需求不是架构;需求无关设计,也非用户界面;需求就是需要的东西。
我们相信,最好的需求文档,或许也是唯一的需求文档,就是可以工作的代码。但这并不意味着,你可以不记录对客户需求的理解就扬长而去。这只是意味着,这些文档不必交付:它们不是需要交给客户签字的东西;相反,只是帮助指导实现过程的路标。我们喜欢可以写在真实(或虚拟)索引卡上的东西。这些简短的描述通常被称为用户故事。它们从使用某功能的用户角度,描述了应用程序的一小部分应该做什么。
应用:
提示78 和用户一起工作以便从用户角度思考
思考:
应用:
提示79 策略即元数据
思考:
应用:
提示80 使用项目术语表
思考:
应用:
提示81 不要跳出框框思考——找到框框
思考:
解谜的奥妙在于确定真正的(而不是想象的)约束条件,在这个约束条件下找到解开的方法。有些约束条件是绝对的,有些其实是一些先入为主的观念。应该尊重那些绝对的约束条件,无论这些约束条件看起来多么令人反感或愚蠢。解决谜题的关键是,认识到你所受到的约束和你所拥有的自由度,因为认识到这些就会找到答案。
在日常工作中,将什么行得通什么行不通反馈给大脑,是供养大脑的最好方法。我们描述过一个好方法,就是记录工程日记。
应用:
提示82 不要一个人埋头钻进代码中
思考:
我们可以不断地提问、澄清、决策和演示。用户是你团队的一部分。这就是我们所说的“一起工作”的真正含义:不仅仅是提问、讨论、做笔记,还要在真正编码的同一时刻提问和讨论。
- 打造代码,而非打造自我。这与谁最聪明无关;我们都有许多闪光的瞬间,也有糟糕的时刻。
- 从小规模做起。只需要 4-5 人的群体,或者开始时只组成几对,做一些短期活动。
- 批评要针对代码,而不针对人。“让我们看看这一块”听起来比“你搞错了”好得多。
- 倾听他人的观点并试着理解。观点不同不是错误。
- 频繁进行回顾,为下一次做好准备。
应用:
提示83 敏捷不是一个名词;敏捷有关你如何做事
思考:
我们一直在实践中探寻更好的软件开发方法,身体力行的同时也帮助他人。由此我们建立了如下价值观:
- 个体和互动高于流程和工具
- 工作的软件高于详尽的文档
- 客户合作高于合同谈判
- 响应变化高于遵循计划
也就是说,尽管右项有其价值,我们更重视左项的价值。
以敏捷方式工作的秘诀:- 弄清楚你在哪里。
- 朝想去的方向迈出有意义的最小一步。
- 评估在哪里终结,把弄坏的东西修好。
应用:
提示84 维持小而稳定的团队
思考:
务实的团队很小,充其量也就10-12 人左右。成员很少进出。每个人都很了解彼此,相互信任,互相依赖。
鼓励每个人积极监控环境的变化。保持清醒,对项目范围扩大、时间缩短、额外特性、新的环境——任何在最初的理解中没有的东西,都要留心。对新的需求要保持度量,团队不必对变化导致的失控心存抗拒——只需要知道变化正在发生就可以。否则,置身沸水的人就会是你。
团队想要成功,也需要考虑对他们的知识和技能投资。如果团队对改进和创新是认真的,那么就需要将其排入日程表。“只要有空闲时间”就去做,意味着这件事永远不会发生。
应用:
提示85 排上日程以待其成
思考:
团队整体的对外交流,不要重复自己,团队的曳光弹。
无摩擦力意味着,提出问题,分享进展、问题、见解和学到的东西,以及时刻关注队友正在做什么——都很容易,不需要什么仪式。
保持清醒,留意DRY。
应用:
提示86 组织全功能的团队
思考:
应用:
提示87 做能起作用的事,别赶时髦
思考:
他们模仿的是形式,不是内容。人类学家称之为货物崇拜。在很多时候,我们就是这些岛民。
别上当。特定的神器,以及浮于表面的结构、策略、流程和方法是不够的。怎样才能知道“什么能起作用”?试一试。
应用:
提示88 在用户需要时交付
思考:
我们的目标是交付可以工作的软件,让用户马上能获得新的功能。如果交付周期是几年,试着把周期缩短到几个月。如果是几个月,就减少到几周。如果是一个四周的冲刺,那么试一下两周。如果是两周的冲刺,试试一周。然后到每天。最后是即期交付。
请注意,能够即期交付并不意味着你必须每天每分钟都交付。只有当这样做在业务上有意义时,才有必要在用户需要时即期交付。你会在版本控制系统的主干上进行开发,而不是在分支上进行,并且使用诸如特性切换之类的技术来选择性地向用户推出测试特性。
应用:
提示89 使用版本控制来驱动构建、测试和发布
思考:
构建、测试和部署通过提交或推送给版本控制来触发,并在云容器中完成创建。发布到交付阶段,还是生产阶段,可以通过在版本控制系统中打标记来指定。这样,发布就不再有那么强的仪式感,变成了日常生活中的一部分——这是真正的持续交付,没有绑定到任何一台构建机器或开发人员的机器上。
应用:
提示90 尽早测试,经常测试,自动测试
思考:
事实上,好项目的测试代码可能会比产品代码更多。生成这些测试代码所花费的时间是值得的。从长远来看,最终的成本会低得多,而且你实际上有机会生产出几乎没有缺陷的产品。
应用:
提示91 直到所有的测试都已运行,编码才算完成
思考:
自动构建过程要运行所有可用的测试。以“测试实际环境”为目标很重要,换句话说,测试环境应该与生产环境紧密匹配。任何缝隙都是 Bug 滋生的地方。单元测试,集成测试,确认和验证,性能测试,对测试做检测。
应用:
提示92 使用破坏者检测你的测试
思考:
一旦你确信测试是正确的,并且正在进行寻找 Bug 的工作,那么如何知道是否已经对代码库进行了足够彻底的测试?
简单的回答是“无法知道”,永远也不会知道。
应用:
提示93 测试状态覆盖率,而非代码覆盖率
思考:
使用基于特性的测试技术,根据被测代码的契约和不变式生成测试数据。
应用:
提示94 每个 Bug 只找一次
思考:
一个 Bug一旦被人类测试员发现,这就应该是它被该人类测试员发现的最后一次。要立即修改自动化测试,以便这个特定的 Bug,从此往后每次都被检查到——不能有任何例外。
应用:
提示95 不要使用手动程序
思考:
一切都要依赖于自动化。除非构建完全自动化,否则无法在匿名云服务器上构建项目。如果涉及手动步骤,则无法自动部署。一旦你引入了手动步骤(“就只有这一部分……”),就打破了一扇非常大的窗户。
有了这三件套:版本控制、无情的测试和完全自动化,项目就有了你所需要的坚实基础,这样就可以将精力集中在困难的部分:取悦用户。
应用:
提示96 取悦用户,而不要只是交付代码
思考:
用户真正要的不是代码,他们只是遇到某个业务问题,需要在目标和预算范围内解决。他们的信念是,通过与你的团队合作,能够做到这一点。这个项目在完成一个月(或是一年,不管多久)之后,你根据什么来判断自己已经取得成功?
如果你想取悦客户,就和他们建立起某种关系,这样即可积极地帮助他们解决问题。或许你的头衔只是“软件开发者”或“软件工程师”的某种变体,而事实上这个头衔应该是“解决问题的人”。这就是我们所做的,也是一个务实的程序员的本质。
应用:
提示97 在作品上签名
思考:
务实的程序员不会逃避责任。相反,我们乐于接受挑战,并让自己的专长广为人知。你不应该百般猜忌地捍卫自己的代码不被他人干涉;同理,你应该尊重别人的代码。恪守恕道(“己所不欲,勿施于人”),以及在开发者之间建立相互尊重的基础,是实现这一条的关键。
应用:
提示98 先勿伤害
思考:
对于我们交付的每一段代码,我们有义务问自己两个问题:
- 我已经保护好用户了吗?
- 我自己会用它吗?
应用:
提示99 不要助纣为虐
思考:
正是你的想象力、你的希望、你的关注,为未来20年甚至更长时间的构建,提供了纯净的思想基础。
你正在为自己和子孙后代建设未来——这是你的职责所在,去创造一个让所有人心向往之的宜居未来。当你做的事情违背了这个理想时,要敢于承认,并有勇气说“不!”对可以拥有的未来充满憧憬,才有动力去创造它。即使是空中楼阁,也要每天为它添砖加瓦。
应用:
提示100 你要为自己的人生做主。精心营造,与人分享,为之喝彩。好好享受吧!
思考:
应用:
应用
参考
- Thomas, David, and Andrew Hunt. The Pragmatic Programmer : Your Journey to Mastery. Addison-Wesley, 2020.
附件
版本记录
2024-09-04,初稿;