如何“偷懒”:从提升代码质量开始

分享:  

如果一件事情只需要做一次,我们可能怎么方便怎么来,但是如果一件事情要重复千百遍,怎么方便怎么来就会变成灾难。对身体,对时间,对团队。停下来想想过去做的一些事情,都是为了做好事情的同时,能让自己更好地慢下来,让身体可以偷懒。本文先从提升代码质量开始谈起。

Linus Torvards在一次采访中,主持人贴了两个链表操作的实现,让其评价哪一种更好一点,Torvards说更喜欢消除了特殊逻辑的那种,并将这种偏好称为“taste”。每个人的taste不同,也不方便评价好与坏,但是“脑筋急转弯似”的做法一点都不“聪明”。好的思路很多都是相同的,不好的东西千差万别的厉害。

站在巨人肩膀上

从什么时候开始,我开始思考如何在有限的时间里涉猎更多的东西,awesome、101、patterns、slideshare、best practices…似乎有限的时间被延长了,我们没必要一个个坑的踩过来摸索中前进,别把别人头破血流总结出的经验教训不当回事。以前我奉行“纸上得来终觉浅、绝知此事要躬行”,很好,但是生命是有限的。

想要更大的世界,必须懂得借力,吸收经验教训,好的坏的全部统统吸纳滋养自己。

对异常关注不足,未养成安全编程习惯

经常看到 if ok {...} else {...} 这样的代码,没有养成优先处理异常的习惯。导致出现多余的if-else分支是小事,怕的是,这么习惯了容易产生下面的问题:if中先处理正常逻辑,else中再事后补异常处理逻辑,而对异常情景的细分,也可能会因为“功能已完成、异常哪有那么巧出现”的侥幸心理而有所倦怠,如rpc错误是网络错误、超时还是逻辑逻辑,每种该作何处理,可能会草草了事。不能说这种担心是多余的,人都是属驴的,自己也会有这种惰性。

对输入不做校验,“不大可能”,这不能算是一个合理的理由,“调用方判断”,这更不合理。这就好比我想吃饭了,从商家买到过保质期的食物,那我作为活动的发起方(调用方)我肯定会检查下食物保质期,但是商家也不能不管保质期就卖给我吧。那这么看,是调用方检查,还是提供方检查,还是没必要。自己的函数坑自己的服务,也是坑。

每每提及“高可用”、5个9,大家就竖起耳朵听,可是连基本的进程级的健壮性都不下功夫,又怎么去奢求诗和远方。

写的虽然是代码,但其实是逻辑的表达

发明高级语言的目的,就是为了更好的表达,但是我们学会了编程语言,却忘了怎么表达。

我想了想那些好的文章是怎么写的,我们需要一个吸睛的标题来惹人关注,需要时刻不忘中心思想避免论述过于涣散,还需要凤头猪肚豹尾来层层论述,每个段落也要有提纲挈领的中心句。如果说是一本书,也还是类似的,但是又有了其他的要求,章节并不是硬性的切割,有时候我们前言里会看到,您可以根据情况自主选择感兴趣的章节阅读,那是因为各个章节相对独立,结合起来又形成一个更完备的论述。

那,代码该怎么写呢?

一个服务的所有逻辑,平铺在一个工程下的源文件中,没有任何模块化的组织,比如go项目没有任何package,那我们的逻辑是变复杂了还是变简单了? 函数、方法调用体现的是一种通信,当我们去和别人沟通时,我们一定是清晰地知道别人能提供我们需要的服务,才会去选择与其沟通,而且为了有效率的沟通,还要言简意赅。那一个package、receiver下的函数、方法不区分导出、非导出,那该选择哪个发起通信呢?而且内部的一些实现细节也不关心,我只关心能不能买到服务。 完成一项任务,总可以拆分成几个步骤,所以我们可以先写伪代码列出todolist,基本上每一项todo都是一个相对独立的逻辑,还可以为每个相对独立的逻辑加一行简单的注释,末尾加空行隔开,以体现出逻辑区块。难道从头撸到尾能将逻辑表达的更清晰?想象一篇没有标点的作文该怎样阅读? …… 有时候,我们说编码好坏是习惯问题,是taste,但我觉得是思维习惯的问题。这样的习惯日积月累,负面影响可能会更大。

简单点再简单点,简单可依赖

什么是简单?是方便,是省心?我觉得是诚实不隐瞒,是就是,不是就不是。最恨的就是那些表面光正背后搞小动作的代码。

有些代码表里不一,表面是一套,背后是一套。命名说是做这个,结果背后不干这个,或者除了干这个还干别的。为什么我们使用一些标准库的api的时候就愿意选择相信它,但是看我们自己代码的时候就不得不频繁地跳来跳去呢?

不相信写的代码,原因跟下面经常遇到的问题相关,经过了现实的捶打只能先“另眼相看”; 导出类型、方法、函数、变量、常量缺乏必要的注释,不得已只能跳过去看代码; 函数签名多返回值没有必要说明,如返回值变量名,除了最后一个是error不知其他干嘛的,只能跳过去看return,问题是还有多个return出口; 函数签名参数列表,shorter & simpler,如果有近10个、20来个参数,怎么记得住形参?传实参的时候会不会对应错误?哪些参数是必填、选填?命名是否能准确清晰地覆盖这些参数? hack逻辑,如硬编码,这些损失的不只是灵活性,也植入了一些暗黑操作。一个好的软件架构师应该做到“make the invisible visible”,invisible的一个直观的害处就是,越俎代庖的事情会变得普遍,本来可以由调用方支配的一些控制参数,被独断专行了,本来应该上升到系统层面的问题,被一个模块偷偷代表了; …… 我的逻辑是,只要阅读代码的时候有非常频繁的跳转、推导、假设、验证的过程,那这个代码的可读性就真的不怎么样。

公司代码规范

只要是规范,就有局限性、滞后性。我理解,规范不是让我们追求完美主义,而是追求better code,better practices。如果一个开发者有好的taste,他写出来的代码可能已经接近或达到规范的要求了。但是并不是每个开发者都有这样的taste,所以我们才需要规范来约束我们做一件共同的事情。

遵守代码规范的一个明显的好处是,可读性会有比较明显的提升,这是很有意义的。可读性提升,意味着维护成本降低,意味着省下时间,意味着可以在正常工作时间做更多事情,可以早下班休息、充电。这可能不是对每个人都是个好事情,但是是对团队有意义的事情,对多数人有意义的事情,就应该坚持!

最后

多年前翻阅Linux文档,Torvards解释为什么一个Tab非要8个空格而非通用的4个,他说,我就是要让那些爱写嵌套多层代码的人“难受”……

省下大把自己、大家的时间,这难道不是一种很聪明的“偷懒”行为?