本书的论调是 Martin Flower 一派常用的论调,介绍文档和研发实践其实是敏捷编程圈子一直以来形成的实践的一部分。从这个角度看,其实书中实心的部分由于绑定了 BDD / DDD / TDD / XP 等等实践,甚至是 Java 语言的注解一类的细节,其实通用性是不足的。
但是其开篇《重新思考文档》和末篇《在新环境中引入活文档》是通用的。(如果你把《为遗留应用程序编写文档》认为是附录式的最佳实践的内容)
重新思考文档
本文标题『活文档就是反文档』是《重新思考文档》一章里面的主要思想。当然,可以认为文档这个词被重载,被反的是传统文档。但是,实际上作者连活文档也是反对的。
这一章中提出了『文档编写的是知识』和『文档是为了传递知识』的观点,以及最关键的是,『大部分知识是已经存在的』。也就是说,文档并非创造知识,而是记录和传播知识。知识是目的,如果知识的交换和共识形成已经是事实,那么实际情况就是不需要文档。
编写文档起码有以下的问题。
1.独立活动和冗余知识,即编写文档和编码、测试以及需求说明是割裂开来的不同团队和不同阶段的工作。然而,实际上它们依赖的是客观上相同的知识。通过不同的形式和工具来使用,使得文档在流程中相同的知识形成不同的演化和修改版,失去了知识内容的一致性。2.手工转录和大脑转储。从知识到文档或文档到文档是一个转录的过程,这个过程会有随机性和损害性。即使是一流的翻译家都无法将著作原文以另一种文字完全贴切的表达出来,未经训练的成员转录带来的问题就更多了。3.时间陷阱和喧宾夺主。管理层想为用户提供文档,还想用文档来解决团队中人员流动引发的问题。然而,开发人员讨厌编写文档。如果成立技术文档团队来提供文档,他们仍然需要开发人员的协助才能获得编写文档所需的技术知识。通常,这会使得文档挤占处理真正在工作的软件的时间,而协作的方式依然是某种形式的转录。
出于文档的上述问题,本章提出了活文档作为文档 2.0 的特征以及如何解决问题。
1.准确性机制,即需要制定一个准确性机制,以确保知识和项目始终保持同步。通常,这要求知识是单一可信来源( SSOT )的。2.简洁与标准,即文档的内容需要简短可理解,否则成员就不会遵守。简洁来源于标准、共识和隐喻,也就是说,知识形成共识就能减少文档的内容,知识都是共识就不需要文档。3.集体所有权。所有知识都存在源代码控制系统中并不意味着它为开发人员所有。开发人员并非拥有这些文档,知识有责任使用技术手段来处理这些知识。
从文档形式上,本章强调固有文档即存储文档的最佳位置是被记录的事务本身。良好的命名和代码结构好过随意的命名与混乱的代码结构加上解释其实际作用的文档。
最后,本章提出了编写文档时应该提问自己的几个关键问题。
1.首要问题,我们真的需要这个文档吗?我们真的现在就需要这个文档吗?2.其他解决方案,我们可以通过对话或集中办公来分享知识吗?3.知识定位问题,这些知识现在在哪里?4.知识稳定性稳定,这些知识会如何变化?
上面所有这些内容里面,我想针对代码与文档的关系展开讨论一下。
我所见过的最好的技术文档有两类。一类是产品详尽的手册和指引文档,这类文档常见于成熟的软件例如 LLVM 或者英特尔芯片指令集手册等。它们是为依赖该软件工作的人员编写的,例如编译器专家熟悉 LLVM 的具体章节,驱动开发者或操作系统开发者熟悉指令集手册。
另一类是产品功能设计文档,或者被称为 RFC 等。这类文档从背景动机、分层分块和接口实现介绍了产品功能的设计全景图。其中,背景动机是最关键的,这解释了某个产品功能为什么要做,解决了什么问题。如果无法讲清楚这个事情,那么这个功能就是不需要做的。
除此以外,功能型的常青文档仅存在于代码之中,例如 Flink 的 Watermark 类有详细的概念介绍文档,这种基础概念是不会改变的,JDK 标准库有些接口拥有完整的实现文档,来引导开发者扩展其实现。
除此以外,文档所担负的传递知识的职责就应该绝大部分转移到代码本身了,包括变量的命名,真的不要有奇怪的缩写和编号;包括代码的结构和功能流程,真的能够层次递进的了解实现。
我在 PingCAP 和其他同学讨论代码标准流程的时候,发现一个名词对不齐就是流程别人很容易以为是文档或者工作流程,其实我说的是更接近于设计模式的东西。比方说,APP 的扫码流程是前端读取摄像机输入的二维码图片,识别成对应的文本,传输到后端处理中枢,处理中枢根据文本解析的结果分派到对应的业务服务,并返回处理结果,通常是一个结果跳转链接。对于 TiDB 来说,SQL 处理的流程是服务器接收请求提取其中的 SQL 文本并进行语法解析,成为语法树,在经过编译和优化经历逻辑计划和物理计划之后,实例化执行器跑具体的任务。这是一个抽象的说法,并被固化到代码里面,相应地,代码需要以这样的层次组织,而不能在上层内联下层的逻辑,这样才允许阅读者按需缩放知识量,而不是一头撞死在海量细节当中。
在新环境中引入活文档
如何在新环境中引入最佳实践是一个历久弥新的话题。变化对于组织的生存和演进是必不可少的,但是变化又是最为强大的惯性和惰性所阻碍的。我在某公司推行 Git 合并代码以 squash & rebase 而不是 merge with commit 的时候就有过失败的体验。
1.错误估计了成员理解的成本。对于我来说,Flink 社区明确要求合并代码是 rebase 的,ZK 社区有自动化脚本完成 squash & rebase 工作,我也了解 rebase 带来的线性历史的好处。但是对于当时的团队成员来说,他们并不关心 commit 历史是个什么东西,值得关注的是最终代码和上线效果,而现行的 merge with commit 并不阻碍这个事情。我在推行前尝试做过一个演讲来介绍这一变化的内容和意义,但这在本书中是反模式。本书提倡演讲的内容要有用而有趣,演讲的重点不是说明如何做事,而是说明与当前事务状态相比,生活可以如何变得更好。我没有着重讲这方面的内容,或者无法清楚地指出一大堆 fix tests / updated 的 commit 历史是垃圾的问题,使得这次演讲充满了革命和政治意味。2.错误估计了成员执行的惰性。正好今天和当时支持我行动的老板讨论最佳实践的问题,他提到大部分人是这样的状态,『他们肯定不看文档的。他们也不会去想为啥做成这样。他们想的就是怎么快点把工作凑合做完,赶紧下班。所以要让大部分人用的东西,傻瓜一点,在设计规则,框架,产品的时候,这是一个重要的参考。』当时我撰写流程文档的时候第一版甚至详细地有四层缩进总二十条以上的细则,我的同事们真的不会看,正是这位老板提示我精简内容。现在的我是反对复杂性的急先锋,如果一个新流程或规则看起来很复杂,资深员工有抵触,那么它一定是有问题的。3.没有认真调研落地的可行性。由于上面的错误假设,我实际认为我的想法能够为组里的同学所认可,这样他们会跟我一样行动来落实。实际上,这是一个必经流程,而必经流程用 A 方式或 B 方式做开销相近。但是,我忘记了默认的力量。当时公司的业务是由蓬勃发展的微服务来构建的,新的微服务有新的代码仓库,而新的代码仓库的默认合并方式是 merge with commit,要改动这个事情需要全公司改动,这显然不可能。单个仓库改动需要 maintainer 权限,这个权限只有老板有。显然,老板是不会有时间监控并逐个修改权限的,而我也不可能因此申请 maintainer 权限,这在当时只是我们组的内部试点。于是,强大的惯性推动着旧制的复辟,而破窗的后果是大家选择性遗忘曾经的共识。其实,GitLab 没有 squash & rebase 的最佳实践,GitHub 的 squash & merge 就是我需要的功能,如果我们的开发基础设施在 GitHub 上,做这个事情会轻松很多。
本书介绍了在新环境中引入最佳实践的方案,虽然是活文档背景下的,但是换成任何其他最佳实践,这个方案也是可行的。
第一步或者说第零步是秘密实验,也就是自然而然地将最佳实践引入日常工作,成为工作的一部分。最佳实践能够带来工作上的改善,当其他人对这种做法产生兴趣后,你可以将最佳实践作为一个主题进行讨论,并向他们推荐其他阅读和实践材料。
另一种方式是获得正式授权以在整个团队推行,但是本书并不建议这样做,引用缘由如下。
要获得正式授权,一般需要从管理层开始,至少需要管理层发起。对于管理层来说,文档通常是沮丧和焦虑的来源。因此,与开发团队相比,管理层通常会更多地提起文档这个话题。
有发起人是件好事,你会有专门的时间,甚至可能有一个团队来实施这个方法。与之相对的是,作为一个获得正式授权的项目,它会受到高度关注和密切监视,而且会被要求迅速交付看得见的成果。这种压力会迫使项目成功,从而产生危害。但是活文档是一个发现之旅,本身具有实验性的一面,将它引入你的环境里并不能保证一定会成功。你必须做一些尝试,确定哪些操作不适用,然后根据自己的情况做一些调整。这个过程最好不要经受高层人员的过多审查。
因此,我建议先进行秘密实验,当你找到了活文档与你的环境能契合的点后,再要求获得正式授权在整个团队实施这个方法。
因此,总的来说,应该先在团队中引发成员对最佳实践的兴趣,再找机会快速展示这种方法的好处,最后在被认可后开始推广这个方法。
此外,书中还提到了推广开来以后维持或演化最佳实践可能遇到的问题和相应的思考方式。
其他观点摘录
融合乐趣与专业性
只要你在工作时保持专业,那么在工作中获得乐趣并没有什么问题。这意味着,你要尽最大努力解决真正重要的问题、交付价值并降低风险。只要你在工作时能考虑到这一点,就可以自由选择那些使你的生活更有趣的做法和工具。经过 18 年的编程工作,我确信我们可以在玩乐的同时完成工作。有些人认为工作应该是无聊和不愉快的,因为那是工作,或者因为你用得到的报酬来弥补这种不愉快的感觉,这种想法是愚蠢的。你会得到报酬是因为你交付了价值,而这些价值比你的报酬更值钱。所以,交付价值很有趣,而且表现得专业也很开心。对于在愉快的氛围中高效地进行团队合作,乐趣是必不可少的。
推广最佳实践的要点
•从实际问题触发,解决一个实际问题•试点,组织兴趣团队,交流成员的看法•实现人们对美好世界的愿望,承诺会改善现状,附上时间和里程碑