软件是一种固化的思维→理解已经固化的思维的唯一途径是阅读代码→第一个要接触的是名字→如果名字和它所要表达的概念和逻辑是吻合的,那么程序将变得简单→否则要加入一个从其他代码推导名字含义的过程,使代码变得不再简单。
老子在《道德经》里说:无名天地之始;有名万物之母。程序也是这样,当我们看到一份设计图或一份代码时,大多数人会“望文生义”。但使人“望文生义”却正是语言文字的根本使命。因此,如果一个函数被命名为Add(),但内部实际做的是减法,那么这份设计或者这份代码,一定是很难理解的。
于是一个非常现实的问题就摆在了我们的面前:我们究竟应该如何为类,为方法等命名?在命名时,有两类较大的错误:一个是名实不符;另一个是词义混淆。名实不符的常见情形又有两类。
1)以偏概全。假设说一个方法被命名为OutputLineNumber(),但实际上这个方法会在分析源文件后,同时输出LineNumber和指定行号下的内容。
2)大而无当。假使说一个类被命名为XMLHandler,那么看的人基本不能从这个名字上获得有效信息。这主要是由于Handler这个词的含义过于宽泛。
上文所说的命名为Add()但实际做减法操作是名实不符的极端情形,达到了名实相反的地步。
词义混淆则源自语言文字自身的限制。常表现为一词多义或多词一义。
语言文字可以被看成是一种表意的符号系统,这个符号系统的典型特征是其模糊性。同一个意思可以有许多种表达方法。比如说,index和number是两个不同的词,但很多时候其意义互相重叠。而假如说一个变量名为fileNumber,那么这个变量既可以代表文件的总数,也可以代表某个具体文件的编号。
上述问题会因为英语不是我们的母语而变得更为麻烦。
名实不符与词义混淆这类陷阱的一个主要触发条件是软件自身的不停衍化。
前文曾经提到过,对于概念和逻辑的认知是一个逐层递进的过程。在这一过程中,包、类、方法等的内涵必然会发生变更。变更无疑会使名实不符这类问题加剧。比如,一个类原本负责输出测试结果,这时候OutputTestResult这样的命名可能是合适的。可随着软件功能的增强,最终可能不只要输出结果,还要对结果进行一定分析和统计。这样原来的命名就显得有些不合适了。
在对命名这一问题的根源进行分析之后,我们来看看可能的应对方法。命名问题事实上并不能只在命名这一环节进行解决,首先要有容易命名的对象,接下来才有容易命名的事实。
比如说,是先有猫和狗这类外在特征不同的动物,接下来我们才用猫和狗这样不同的名字来称呼它们,而非相反。
如果概念之间是正交的,概念的边界也是清晰的,那么命名会容易很多。好的设计是改善命名的基础。也就是说,很多时候我们感到命名困难,真正的原因可能并非是命名的技能不够,而是设计还不够优化。
在努力改善设计之后,才需要面对纯粹的命名问题。从本质上来看,命名问题并不是一个编程的问题,而是一个表达的问题。命名最终对读程序的人负责。
有些表达上的基本原则对于解决命名问题会有些帮助如:
(1)尊重既成事实
每个人都是有创造性的,但在命名的时候发挥创造性则更可能是有害的。比如说,在XML中一般使用sibling这个词来表示兄弟节点,这时候就不需要创造性地使用brother node这样的自制词汇了。
(2)用完整词汇(www.xing528.com)
对一般人而言要求事先记忆几十个缩写词,而后来读程序是不太可能的事情。所以如果一个程序中充满_Tx和CSCP这样的特制符号,那这样的程序是不容易懂的。
一个典型的反例是P·J Plauger版的C++标准模板库。也许是出于隐藏实现细节的目的,这份标准模板库的实现里面几乎完全不用完整词汇。如果想体验一下不用完整词汇的后果,那么可以读一下这里面的代码。
(3)要具体
具体是一个方向。比如说,可以用OutputLinenumber()的时候,就不要用Output()。而可以用OutputCppLinenumber()的时候就不要用OutputLinenumber()。
(4)多人协作的时候,使用统一规范
这条规则最终会导致常说的Coding Rule。对具体如何定义Coding Rule,《代码大全》一书中给出了详细的指导,这里就不再说明了。
有一点需要补充的是,和说话的时候记不住语法一样,设计或做编码的人往往也记不住编码规则。所以规则也不宜过多。如果必须详细,那么至少要主次分明。比如说,统一使用主宾结构还是使用动宾结构这样的选择会影响程序的大部分内容,那么就应该优先统一。
现代的IDE中大多提供了对重命名的支持,因此,一旦对如何命名有把握,修改已有的不恰当的命名反倒不是困难的事情。
Code Review的价值
Code Review在很多项目中是“鸡肋”环节—扔了可惜,做了难受。但事实上Code Review也是最容易被误用的环节,就好像锤子可以用来打钉,但不能用来拧螺丝一样,使用Code Review前也要先考察,它所适用的场景究竟什么。
这里做一点简单的总结,以供参考。Code Review对达成下面这些目标帮助较大:
●检查代码非功能性质量(如命名是否符合规范,分解是否正交等)。
●检查并行相关的错误。(如多线程下,有的问题是有时候有,有时候没有的,这时候如果没有在Code Review中做一定检查,很可能在黑盒测试中无法发现。)。
●提高团队成员的编程能力。
以下目标就不适合用Code Review来达成:
●检查软件的功能是否正确。
●检查需求是否都已经被实现。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。