在黑盒中心呼唤理智的野兽

/ 0评 / 0

我最讨厌两种人:「要我写代码文档的」和「没给代码写文档的」。

当一名数学家和当一名程序员的差别,我想主要体现在数学家可以在被其他数学家折磨得不爽的时候发明新的数学;而程序员在被其他程序员折磨得不爽的时候只能选择忍气吞声——哪怕二者都能够在方寸之间构造无穷宇宙。

基于逆(xia)向(ji)工(ba)程(cai)的开发模型

除了第一份「工作」,在桂林某棋牌游戏公司实习的一段时间里,我是在做于方寸之间构建宇宙的工作以外,其他时间,我都在和无尽的黑盒搏斗。我所需要接手的项目,因为这样或那样的原因,总是缺少文档、缺少样例。这使得很多时候无论是设计还是调试都会遇到「不知道」的墙壁,项目就难以继续推进。

这个时候,传统的开发经验就帮不上什么忙了。开发者需要有逆向工程的经验来进行猜想、构建实验和执行测试。这个逆向工程的操作甚至需要在目标架构上几乎没有任何调试设施的情况下进行。这种逆向工程的开发模式会随着项目的复杂度增加而成倍地耗费人力,甚至会出现不可控的逆向依赖链增长。

所以有很长一段时间,我需要和这种「不可知」进行对抗。但是有些时候不得不承认这种对抗可能是徒劳的:你无法猜透设计者的全部小心思,从已经被编译器优化过的反汇编中推出他们的构建。在你的所有调试工具就只有一个瘸腿的 printf 的情况下,想要去剖析一个复杂的系统未免显得有些不自量力。

什么是所谓的「好文档」

目前参与过的开发项目里面,能做到「拥有一份好文档」的屈指可数。目前只能说微软、意法半导体和兆易创新的文档还算是详尽,但很多并不能完全说是「好」——一份好的文档不应该直接把读者扔到 API 的汪洋大海里让他们自生自灭。毕竟这种东西 Doxygen 配合合理的代码内联文档能自动生成。

最基础的,一份好的文档应该是能够让二次开发「轻松」一些的。它应该能带领开发者了解他们的工作的大体结构:他们的插件的生命周期如何、系统怎样和这些插件交互。从发现、加载、验证、初始化、注册、唤醒、调用、异常处理、反注册、销毁、卸载,整个流程详略得当地梳理,并附上一些样例代码。即使这套系统并没有使用插件结构,但仍然对二次开发留有接口,那么其实也不过是从动态加载改为了静态调用,其流程的梳理基本如出一辙。

一份好的文档应该明晰数据流的走向:输入从哪里进入,经过哪些模块的处理,最终交付给谁输出。如果必要,它也应该能阐述模块之间的依赖关系。无论你在使用宏服务还是微服务,写着系统软件还是业务逻辑,数据流的表述都是一致且重要的。

一份更好的文档会剖析系统的内部流程,为系统的迭代改进做好准备。对于那些足够好奇的人,你需要给他们讲明白幕布之后发生的事情。但其实也只是表达系统内部组件的生命周期、数据流向和依赖关系。和上文所讲述的基本大差不差,除了潜在的保密问题。

你的代码不是文档

我曾经也相信「好的代码是自解释的」,但是说实话,这个只有在团队中所有人都可以相互理解的情况下才能勉强实现。但是现实生活是并不是所有人都能有和我们一样的水准,比如他们可能比我们要聪明很多,所以对于他们而言很平凡的构建,对于我们而言反而是需要额外解释的内容。在这种「群除我佬」的情况下,很难说出「好的代码是自解释的」这种话,因为我们压根就看不懂这种「自解释」。

文档是隔离这种实现技巧的唯一屏障。文档本身应该比实现还要「无聊」,因为无聊的文档是没有惊喜更没有惊吓的,这可以有效避免猪脑过载。尤其是在水平参差不齐的团队里,拥有一份好的文档是让所有人都能动起来的黄金标准。

在黑盒中心呼唤理智的野兽

不过这样的要求对于大多数人而言都还是太过分了。毕竟,实现程序逻辑就耗费了程序员的绝大多数精力,再想办法写一份没有意外的文档,开发时间翻倍不止。但我也为许多用后即丢的设计感到惋惜。你可以选择很快地写一坨屎然后交付走人,毕竟提桶后管他洪水滔天。我们太多的精力花费在了屎坑蝶泳上,这自然是一种于全部人的浪费。

我们未尝不是在黑盒中心呼唤理智的野兽。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

Your comments will be submitted to a human moderator and will only be shown publicly after approval. The moderator reserves the full right to not approve any comment without reason. Please be civil.