如何提升可读性
在show观点的时候,已经提到了可读性体现优势的三个方面:更贴近人的语言(通俗表达)、方法的意图(明确意图)、层次(层次结构);
1. 通俗表达
我认为最通俗的表达,其实就是以前我们会有个习惯,在写代码之前会写伪代码,伪代码就是一种非常对co-worker友好的代码形式的表达,来看看下面这段例子(从现有工程代码里面找的)。

从这个例子看到,最通俗的表达是哪个?应该是1-9这几个comments,次之是各个备注下面的方法的命名(因为可能中翻英不是那么地道);我们代码中对自己人最友好的就是备注,(但是有时候也会有意外,如果这个备注是过期的话),备注下方对应的方法名,可能不一定对人那么友好,一个原因是我们对于中文翻译到英文,如何翻译得准确和地道,其实拿捏不好,因为有时候我们翻译能力受限的时候是拼音+英文混搭的;另外一个原因是我们在定义方法名称的时候,没有描述到位这个方法所做的事情,要么就是描述一半,要么描述很抽象,似乎get到了点什么,似乎好像看了又等于没看;通俗的表达的前提是有层次、有抽象、有封装,这块具体下面来讲,可以体感下这个例子:

这段代码算通俗吗?也许可能每一行都能读懂什么意思,但是整体在一起,这个if到底判断了啥,是不知道的(当然,我很取巧的把注释给你们拿了哈,这里其实这个注释的英文命名就是这个if语句条件抽象成的方法的最好定义)这里对于通俗的表达的定义涵盖两个方面:1. 足够友好的能让后面读你代码的人能够读懂,并且是直观的通顺的理解;2. 足够准确的去描述这个方法所做的事情;再者,像遵循约定、变量/方法/类的合理命名、定义完整的文件名、规范的格式和空格空行的运用、备注等,都能帮助后续别人在读你的代码的时候,可以轻松并且明确的驾驭你的意图的;
2. 明确意图
明确的意图本质上是现实和预期的匹配:1. 现实:代码作者在写这个方法的具体实现;2.预期:读代码的人在看到这个方法的时候心里预期的实现;两者如何是匹配的,那我们定义为这段代码是有明确意图,并且没有side effect的;side effect就是副作用,也可以理解为是否在明确定义的方法之下有夹带行为,这类事情其实代码中犯的很多,而且属于大家觉得不应该犯,但是多多少少个人在写的时候,都是潜意识的没注意到,看下这个例子,非常典型:

因为我们用cache、tair用的就比较多,对于tair的常规更新策略都是读未命中之后溯源查询之后回写,然后名称可以保证90%以上的都是getXXXFromCache,但是里面做着更新的事情,但是这个事情又说回来,如果整体团队都形成共识,这样的共识如果变成一种约定,可能倒也不算在side effect的范畴,但是这里我只是举了个例子;上面说的这类是属于方法的名称没有明确的去表达方法内部的实现的范畴,还有一类,其实属于Functional Programming的范畴(FP本身是另外一个领域,这里不细说),在FP中有一个严格的要求和规范,就是不能变更入参,要保证多次执行之后的结果是一致的(框架实现中的基于context传递的面向过程的编程方式不在此列),看下下面这个例子:

代码比较长,我把其他代码删除了,这个对于入参的修改还是比较隐形的,但是本质上是违背了FP的原则,同时后续迭代的人是不知道这个逻辑的,非常容易踩坑,因为在这里被变更掉的request的成员,可能会在之后的流程中成为重要的处理对象,但是如果后面迭代同学的预期是这个成员变量要和接口入参一致的时候,他会一脸懵逼的发现情况有点超乎自己的想象,这时候要么arthas,要么就是debug了;side effect最大的问题大于惯性犯错,因为我们都是秉持相信上一代作者的设计、意图和结构,去做后面的需求迭代的,这时候意图的错误传达,会导致异常乃至故障的发生,同时这样的问题还非常不好排查,因为这个漏洞属于存在于惯性思维的掩护之下的;
3. 层次结构
这里说的层次结构是复杂方法内的代码层次结构,不是以前我们说的比较多的应用分层的层次结构,从一个例子入手:

这个方法freeTieClip内部实现,调用了两个封装的方法,分别是make_item和add_item,在这个方法之前,是一段购物车商品的遍历,array_index和for loop其实和后面两个的方法调用,应该不属于一个层次的抽象,因为前两者是直接的pass through的调用(可以理解为通过 . 来执行调用的),后者属于function call,因此正确的层次描述如下:

那针对这个freeTieClip方法的层次结构优化手段也很简单,就是给前面两个的pass through调用封装一个方法:

接着,如果我们要增加一个从购物车中按照name来删除一个商品的方法remove_item_by_name,大致的逻辑如下:

那这个方法应该是处于哪一个层次结构呢?可能的结果有如下几种:

从方法的命名的业务语义上来说,上面两层new layer above和top layer都不太合适,那从直观来说,应该是bottom layer比较符合,因为再往下down的一层new layer below是属于base的实现了;最终的层次如下所示:

例子中所描述的分层的方法,具体在实践中可以参考,倒是不用这么严格地去做,但是这个思路还是非常有借鉴意义的,至少是赋予了一个模糊的、不好定义的可读性设计和实现提供了一种方法论;