山地人

第006期.如何才能写出一手整洁的好代码?(上篇)

山地人
山地人
2021-05-13

Monitor Displaying Computer Application

进化岛的岛民们都有非常高的求知欲望。

自律 、自强 , 自强不息 !:

老师,我发现我在封装请求方面的知识比较缺少,能不能讲一讲这方面的知识。

其实,粗看这个问题,自律同学是想要了解代码封装的一些知识。但仔细想来,其实是希望自己能写出一手好代码。要写出一手好代码,良好的代码封装只是其中的一块内容。

本期,我们就一起来探讨下——如何才能写出一手简洁的好代码?

这里我会分享《代码整洁之道》Clean Code里的精华思想结合我们的前端来和大家一起探讨这个话题。

“Master programmers think of systems as stories to be told rather than programs to be written”

​  — Uncle Bob.

优秀的程序员认为系统是要讲故事的而不只是编写程序。

什么样的代码才算是整洁的好代码

对于简洁的好代码的定义,不同的人有不同的理解。那么我们先开听听我们这一行的业界权威大牛们都是怎么说的。

C++之父Bjarne Stroustrup说过:

“I like my code to be elegant and efficient. The logic should be straightforward to make it hard for bugs to hide, the dependencies minimal to ease maintenance, error handling complete according to an articulated strategy, and performance close to optimal so as not to tempt people to make the code messy with unprincipled optimizations. Clean code does one thing well.”

“我喜欢优雅和高效的代码。代码逻辑应当直截了当,让缺陷难以隐藏;尽量减少依赖关系,使之便于维护;依据某种分层战略完善错误处理代码;西能调至最优,省得引诱别人做没规矩的优化,搞出一堆混乱来。整洁的代码只做好一件事。”

Object Oriented Analysis and Design with Applications,《面向对象分析与设计》的作者Grady Booch认为:

“Clean code is simple and direct. Clean code reads like well-written prose. Clean code never obscures the designer’s intent but rather is full of crisp abstractions and straightforward lines of control.”

整洁的代码简单直接。整洁的代码如同优美的散文。整洁的代码从不隐藏设计者的意图,充满了干净利落的抽象和直截了当的控制语句。

Eclipse战略,OTI公司创始人,Dave Thomas讲过:

“Clean code can be read, and enhanced by a developer other than its original author. It has unit and acceptance tests. It has meaningful names. It provides one way rather than many ways for doing one thing. It has minimal depen- dencies, which are explicitly defined, and pro- vides a clear and minimal API. Code should be literate since depending on the language, not all necessary information can be expressed clearly in code alone.”

整洁的代码应该可由作者之外的开发者阅读和增补。它应有单元测试和验收测试。他使用有意义的命名。它只提供一种而非多种做一件事的途径。它只有尽量少的依赖关系,且要明确地定义和提供清晰、尽量少的API。代码应通过其字面表达含义,因为不同的语言导致并非所有必需信息均可通过代码自身清晰表达。

三位大佬讲了关于整洁代码的各自的观点,其中有很多共性的地方。我们把他们整理总结出来。

整洁的好代码的共性之处:

一、代码优雅,拥有良好的阅读性

好代码应该是阅读起来让人舒服,身心愉悦的。当然代码要写到层次是需要花费很多时间精力来进行训练的。

二、简单

写出来的代码要简单,要符合软件开发的 Do one thing with the Single Responsibility Principle (SRP) 单一职责原则。拿到我们前端来说,写一个function函数,不能里面啥活都干。每个定义的函数应该专注做好一件事。

三、可测试性

要通过所有的测试。如果你稍微关注一下GitHub上的开源代码,很多正规的代码里都能看到各种Test测试。代码的质量怎么得到保证,是需要依赖各种测试的覆盖才能达到的。这个话题,以后我们有时间再来展开专门讨论。

说了这么多,可能对于我们[前端进化岛]的小伙伴来说还是太抽象了。那么,接下来我们来聊聊具体落实到我们的日常项目代码上,有哪些具体的做法。相信这些具体的操作指导是大家现阶段比较关心的问题。

这里我们从几个方面来探讨:

一、从起好名字名字开始

在我们书写代码的时候,起名是程序员要每天都碰到的频率最高的一件事。想一想,你开发一个项目,哪些地方会碰上起名?

随便打开一个js代码文件。里面的各类var ,let,const后面跟的变量名、function 函数名、class 类名、如果你搞一些其他语言还可能碰到模块名,包名。当然还有js文件名,目录名。是不是导出都是起名,哦忘了,对于前端来说还有各类资源切图文件的名字。导出都充斥着各种名字。

有人开玩笑说,计算机科学最难的有两件事,一个是缓存失效,另外一个就是命名。如果你已经结婚有孩子,想想当年你给还是起名是不是最最让你头疼的一件事。

起名这么头疼,但是它也是让你的代码变得优雅的非常重要的一个方面。想想,如果你的代码里导出都是 a1,b1,a2,c2这种毫无意义的变量,如果公司的其他同事要阅读维护你的代码是不是非常头疼。这也是为什么我们很多开发宁可自己重新写也不愿意看别人写的代码的原因。大家写的代码都很烂,自然也就不想去阅读了。

但是回过头来想一想,写代码除了让代码能够正常实现功能,还有没有别的重要的功能?当然了,那就是社交。社交?没错。你的代码写出来之后,其实就已经开始讲述你的故事了。在团队合作开发时,你的代码时和其他开发者见面沟通的大使。这样来想,你是否应该给你的沟通大使打扮的好一点。这样当下次其他开发者打开你的代码,阅读起来非常舒服,你将会收获他人对你的钦佩和尊重。

那么具体怎么做才能起出好名字呢?下面我们针对不同的场景,分别探讨一下。

名字要见名知意

每个名字都在讲述他们自己的故事,告诉你或者你团队的其他开发者,它为什么存在,它是干啥的,以及他是如何被使用的。其实做好这事,无论是你将来再次回来阅读或者其他小伙伴接受维护你的项目,都会有非常多的好处。所以为了将来维护代码更加容易,你从现在起,就要开始学习起名的技巧。让你的名字见名知意。

//糟糕的名字
let a = Date.today;
//好的名字
let today = Date.today;

使用组合方式来起名

人在理解一个意思的时候,往往有几个词连在一块的短语会比单个词更加好理解。所以起名的时候可以借助这个技巧。

var elapsedTimeInDays;
var daysSinceCreation;
var dasySinceModification;
var fileAgeInDays;

看到上面这些组合名称,你大体上已经知道这个变量是干啥用的了。这就是组合名字的威力。

起一个好类名

现在ES6引入的class,让前端也能写很多类了。那一个好理解的类名也就变得必要了。比如,对于我们的前端项目,不管是基于Vue的还是基于React开发的。我们的每一个页面的名字可能就是一个独立的类组件。你可以使用下面的一些起名字的方式。

/**独立的页面**/
class PageHome;
class PageAbout;
class PageShop;
class PageCategory;
/**组件的名字**/
class CompButton;
class CompNavBar;
class CompPhoneNumber;
class CompDashBoard;

上面只是一些抛砖引玉的思路,如果用上面的这种方式来起名,你在看到类名的时候,就已经知道了这个组件的一些信息了。比如PageHome,你会很自然的联想到这是一个独立的Page页面,而且是关于Home主页的。对于CompNavBar,你就知道是一个NavBar导航栏组件。而且这种起名的方式还有另外一个好处,如果你使用IDEA这样的带智能提示的编辑器时,你输入Page之后,所有Page相关的类名,都会自动显示在提示面板上。写代码的时候,也非常舒服。好的名字规则让你阅读和开发期间都变得舒服。那为何不花一点点时间好好想想起名的问题呢。

怎样给函数(方法)起个好名字

函数通常表示的是干一件什么事,所以这里你可以使用一个动词加一个名字的方式来定义一个函数名,比如像下面这样:

function createUser(){}
function deletePhoto(){}
//事件处理函数
function handleLogin(){}
function handleChangePassword(){}

动词+名词的方式来命名函数,当然这个规则结合下面要讲的规则来一起使用,会更加有效。

保持命名的一致性

对同样的概念在系统中保持使用同一个词,比如对于从服务器上请求数据我们可以使用很多方式来命名这个概念,比如fetch,get,pull,retrive。但是如果你在一个项目里使用不同的命名会增加日后的阅读成本。

function fetchUserInfo(){}
function fetchProductInfo(){}
function fetchActiveInfo(){}

在你的项目中,使用一致的命名规则,可以帮助开发者更加容易阅读代码,从而提升开发效率。

这一篇,先写到这里。我们下一期,会接着这个《如何才能写出一手整洁的好代码?》的话题继续来聊。