从源代码到领域知识

在软件开发过程中,编译器起到了一个很关键的作用,

它将一堆人类能读懂的符号进行转换,其结果让计算机可以执行。


正因为如此,我想也不会有人认为编译产物是公司的一种财富,

丢失了源代码,我们几乎一无所有。


有了源代码,我们就可以对它进行重新编译

得到计算机可以执行的编译结果。

除此之外,我们还可以在现有源代码的基础上继续开发。


然而,我认为这可能是技术人员的一厢情愿罢了。

且不论在不理解现有代码的情况下进行开发,可能引发的质量问题,

就只谈论新加入的功能,能否与现有系统良好的并存,也可能会成为问题。


所以,源代码也只是一种中间语言


1. 自然语言

为什么编译器不直接对人类的自然语言进行转换呢?

我想可能是自然语言的歧义性,和计算资源的取舍问题,

我们将花费更多计算资源,来理解更有歧义的自然语言。


而程序设计语言在识别歧义性方面,投入产出比则更高。

况且,即使是用自然语言,也没办法完整传达我们要表达的含义

为了表达清楚,就必须不断的沟通和交流。


从这种意义上来讲,是我们事先在头脑中有了一个想法,

然后进行了一些简化

再将简化后的想法,用自然语言(或程序语言)表述出来。


因此,是产生想法的那个,拥有要被表达的想法,

而不是语言本身。


2. 领域知识

进行软件开发工作的朋友们,可能会对“业务逻辑”这个术语比较熟悉,

所谓业务逻辑,指的是现实世界业务规则的程序编码。


In computer software, business logic or domain logic is the part of the program that encodes the real-world business rules that determine how data can be created, stored, and changed.

—— Business logic


业务逻辑又称为领域逻辑(domain logic),

它反映了现实世界业务领域中约定俗成的一些规则和知识


因此,只看源代码却不顾领域知识

就相当于,保存着编译产物,却不关心源代码。


失去了领域知识,源代码就失去了思想


3. 信息不完整

3.1 接口文档

当我们阅读自己代码的时候,会觉得很多代码逻辑的显而易见的,

但是实际上,代码并没有留下足够多的信息


例如,JavaScript中数组的sort函数,

1
2
> [1, 2, 3, 11, 12, 13].sort();
[1, 11, 12, 13, 2, 3]

得到这个结果,多多少少会让不了解内情的人感到意外,因为,事实上,

The default sort order is according to string Unicode code points.


默认排序是按字符串的unicode码位排序的,

这些数字首先会被转换为字符串,再按unicode码位排序。


这只是一个接口相关的例子而已。

我们通过把接口文档补充完整,就能大幅度的改善这个问题。


然而,还有一些关于灵活实现的问题,却没有这样简洁的办法避免它。


3.2 未定义的实现方式

例如大部分表单页面,都会实现一个避免重复提交的功能。

这个功能的实现方式非常灵活


我们可以点击按钮之后,在页面中弹出一个遮罩层,避免用户再次点击。

也可以把按钮置灰,让用户无法点击。


现在就有一个问题,如果服务器端异常了,

这时候页面会如何展示,

不刷新页面我就不能提交了吗?


显然这件事除了看代码,或者去问代码的编写者之外,

没有更好的办法去确定它。


4. 代码即文档?

像上文提到的那样,代码只是实现了开发者头脑中的一部分想法

另外一部分想法,如果开发者不写在别的地方,我们永远都不知道。


因此我们应该鼓励对这些专有知识进行广播,继而沉淀下来。

通过代码来反推业务逻辑,

则无异于对编译产物进行逆向工程得到源代码。


一个代码库,如果只有通过阅读代码这一种手段来理解它,

那么它关于领域知识的留存度,将是十分缺失的。


所以,代码即文档,强调的应当是努力提高代码的可读性

而不是说出了代码之外,就不应该有文档了。


结语

对软件行业不理解的人们,可能会觉得,

工程师们聚在一起,一定是在互相切磋编码技能,

其实不是如此。


他们在尝试理解对方,也尝试让对方理解自己。

尝试把专有知识公有化

也尝试把更多无损的想法放入代码和文档中。


源代码也只是一种中间语言,写代码的那个人,才是关键。


Reuse is about people and education, not just architect.

—— 《软件架构师应该知道的97件事