写了这么多年代码,从懵懵懂懂到随心所欲,从弱水三千到只取一瓢,从小作坊写到大公司,经历与感慨颇多。要问什么代码是好的代码,一千个人眼里就有一千个哈姆雷特。
比如对老板而言,能有效、快速支撑业务发展的就是好代码;对于网红来说,能装逼、构思巧妙震惊众人的就是好代码。所以我们这里大体可以限定下,只讨论团队协作时的开发以及独立开发时的维护场景吧。
什么代码不好?
要是问到如何写好代码可能有点千头万绪,但要是吐槽下什么代码不好,相信大家都有不少的经验。
- 没有文档、没有注释;或者即便有了,文档注释不更新、不同步;或者太多太冗长;
- 没有类型约束,也没有单元测试,不知道边界条件下代码健壮性如何;
- 滥用设计模式,刻意使用不常见语法、奇技淫巧;
- ……
这样的负面清单,我们可以拉得很长。在实际开发中,我们可以尽量去规避这些不好的情况,但是这些太细节琐碎了,很难记住并执行好。有必要有一个总体的、甚至是感性的认知,并抓住最重要的几个点。
好的代码就如一篇好文档
我一直有一个断言:代码写不好的人大概率文档也写得不怎么样。反过来也差不多。
为什么?因为它们都是给别人看的,而且大部分时候是读多写少。也就是说写可能就一次,但在它的整个生命周期里,它会被读无数次,会被无数人读。所以一篇好的文档,肯定是更多地照顾读者,而不是作者的激情输出、孤芳自赏。在文档的立意、结构、行文等方面,要尽量照顾读者——读者有不同层次,有不同背景。
代码也是如此。我们大部分时候是处于一个团队中,我们的代码需要被同事评审,乃至维护。哪怕是一个独立开发者,我们也会面临要维护一些时隔半年甚至更长时间的代码。这个时候,能够让同事、过去的你快速理解、准确理解的代码,才称得上是好的代码,才会有更强的生命力。
这就是可交流性,或者专业点说就是可维护性。我把这个作为好代码的最重要的一条评判标准,如果不是唯一的话。要写出一份可交流性高的代码,以下几点尤为重要。
技术设计、文档先行
俗话说,三思而后行。技术设计就是“思”的过程。不经历一个思考的过程,想到哪写到哪,这样的代码往往会走向无序混乱,不安全也不可靠。
设计就是一个思考的过程。我们可以通过编写设计文档,理清背景、目标及其衡量指标、竞品、各种可能的实现途径及其影响范围、测试范围、维护方式等。通过自然语言、数据、作图等更亲和、更具表现力的手段将代码的逻辑展现出来。
有了设计文档,我们可以提前邀请同事评审。如果设计不可行,那就修改设计。这样就我们就可以将不好的代码在萌芽阶段就给消灭,降低整体推倒重来的概率与成本。
核心逻辑要有单元测试覆盖
很多开发人员不愿意写测试代码,觉得冗余、没用,甚至还有鄙视链在里面——测试不如开发,为什么要去做比较低级的事情?但我敢说,代码写不好的,测试也做不好。因为代码本来就写得不怎么样,再弄一个不怎么样的单测,也覆盖不了什么,徒增工作量。
测试不是与开发割裂的,而是用来补充开发的。通常写代码时,我主要关心主线逻辑;而在写测试代码时,则要想还有哪些边界场景。两者的角度是不一样的,前者是站在生产者的角度,后者则是消费者——用户的角度。
也不是所有的代码都要写单测来覆盖,把那些核心的、复杂的逻辑部分覆盖完整了,整个功能就错不了。这样也能更好地取得效率与质量上的平衡。
代码可搜索
什么是代码可搜索性?它表示代码里的函数、变量等能被精确地定位,不管是通过类型索引还是全局文件搜索。
当我们维护别人的代码时,将会发现一个具备良好可搜索性的代码是多么的亲切。
- 排查一个 HTTP API 的问题,拿着 URL Path 一搜就能快速找到关键实现位置;
- 拿到一个日志的非变量部分,能快速定位到输出位置。
它要求我们减少不必要的封装,尽可能地把常量完整的暴露出来。对于那些很可能影响代码可搜索性的设计模式,要谨慎使用——比如依赖注入、装饰器。
结语
在不同的人心中、同一个人不同的阶段,对好代码都可能有不同的理解。无论如何,记住我们的代码是需要被拿来交流的。