我们如何写有价值的必要文档
背景
我入职亚信cboss部门已1年有余,最大的感受就是每个开发环节都非常注重文档,软件或者需求开发的每一步从形式到内容都要求文档化。这种高度文档化的模式需要设计者话费大量的精力在文档的撰写和维护上、需要投入大量的成本,虽然这种成本在相对固定,变化较少的问题域可以从软件后期的维护收益上得到补偿,实践中也得到了较好的效果,但是在变化多的问题域,如互联网、创业企业等,高度文档化会造成整个软件生产过程的反应迟滞,进而造成企业竞争力的下降。于是这些要求快速反应,快速更迭的行业逐步放弃了高度文档化的要求,开始追求原型设计、分步迭代以及代码文档。
但是,通过与在互联网行业工作的朋友交谈之后发现,实践过程中所谓的“敏捷”项目却从“高度文档化”走向了“无文档”:需求也只有几句定性的描述,一个或几个开发者自己就鼓捣着把功能完成了,最终交付的也只有一个SVN地址,没有任何有价值的文档可言。从结果看,个人认为这样的项目是失败的,无论是技术上还是业务上。个别项目业务需求很大,技术后期满足不了,只能进行痛苦的重新设计和重写,这个过程往往耗时甚多,并对业务有或多或少的影响,也就背离了“敏捷”保障业务快速发展的初衷。
作为开发者,我们的目标是正确认识文档的作用,制定或运用合适的规范,撰写必要而足够的文档。提升文档的编写和阅读能力,同时使文档为我们服务,为开发和维护过程创造价值。
文档的作用
既然文档如此重要,那文档有具体的哪些作用呢?
帮助设计者克服恐惧
面对新的业务需求,尤其是不熟悉的业务,设计者内心多少会有些忐忑,或者说恐惧。例如前段时间,要我做一个4G转售优化业务的后台进程,我从未接触过这方面的知识,内心难免会有些忐忑,唯恐做出的东西漏洞太多。在新的业务需求全新的设计,需要通盘考虑各种情况如何处理,这个过程中往往还存在很多有抵触的点,需要设计者取舍。如果不写文档,设计者在脑海中构建一个初步的想法之后就会动手编码。这个初步的想法一般来说都是不全面的,但恐惧往往会驱使程序猿尽快开始行动,试图看出一些产出,同时也能尽快给管理或者说上层一些相应。可是未经全面考虑的产出往往有着较大的设计漏洞。幸运的情况下这种产出会被后续更改或者覆盖,如果不幸,这些缺陷的产出会直接把后续的开发带错路。
帮助设计者抵御立即动手编码的冲动
因为文档比代码的抽象程度更高,写文档促使设计者从更加抽象的角度思考问题,借助文档的抽象,设计者能从概念而非实现的角度看待整个需求或者系统。脱离了实现细节,设计者更容易发现哪些概念是错误的抽象(错误抽象是某个概念和其他概念存在不合理的依赖或者交叉)以及整个设计拼图中有哪些确实。通过撰写文档,设计者为自己提供了一幅图,从而有勇气去作全局的设计。
增加沟通和交流
作为一个团队成员,我们仅仅交付功能是不够的,我们交付的是可理解、可维护的功能。为了这个目标,我们需要和各方进行交流和沟通,把我们的设计思路向他们讲清楚。设计评审者通常对项目细节不会非常熟悉,他们关注的是整个项目的核心诉求,技术难点和实现方案是否自洽。他们比设计者(文档撰写者)考虑的更加抽象,看的往往是几张图或者表格,但这几张图和表格并不会凭空出现,一定是从设计文档中抽象出来的最核心的设计要素。对于服务使用者来说,按照“对接口编程”思想,接口上的文档通常有两类,一类是独立的接口描述文档和示意图,这用于团队内部;另一类是程序内文档javadoc,作为接口说明供接口使用者参考。由于javadoc支持html,设计时可以先写interface,用详细的javadoc接口描述信息,在用工具抽取成独立的接口描述文档。这样既可以避免两份文档之间不一致,也更加容易发现文档和代码之间不一致。对服务维护者而言,需要通过详尽的文档,才能了解最初设计者的意图,并在后续设计中保持这个意图。
表明想法和目标
很多时候缺乏文档是很难了解作者是怎么想的。如果维护者不知道设计者的思路,再好的设计也无法得到贯彻。如果你是文档撰写者,请务必在文档中说清楚你的想法和目标。
必要的文档
我们需要文档,但是不需要冗余的文档浪费程序猿的时间和精力。我们希望程序猿写的每一份文档都是有价值的,有信息量的。目前来说,对新功能需要提供以下设计文档。
实体关系图
包括新功能的用例图、要引入的实体以及实体之间的关系。实体关系图的重点是看实体抽象是否正确,新的抽象是否正确实现所有用例。
接口文档
接口文档是接口两端程序猿的约定,任何需要多人合作的边界上都需要提供接口文档。接口文档包括:前后端文档和后端接口文档
采用前后端分离的开发模式,前后端接口文档需要详细说明列表,每个前后端接口的格式和说明,这个文档一般由前端提供,后端是吸纳。例如:
后端接口文档,为了便于同步代码和文档,后端接口文档以javadoc为主,评审者抽取javadoc即可。Javadoc可以用IDE书写,更加方便,评审以interface Javadoc为主。
单元测试,为每一个新增功能都做好充分的单元测试。单元测试能够真实的反映出用户需求和系统API,并能够帮助程序猿写出高质量的代码
系统交互