七个小时的火车,闲来无事,总结一下对代码可读,可维护的一些个人实践,与诸位道友交流探讨
基本格式化
首先是对基本格式化的处理:
缩进,空格间隔,单双引号,提交信息格式等这些基本的格式化,在项目中统一交给:eslint,prettier,stylelint,commitlint
等工具进行管理,可以减少了很大的心智负担,不仅如此eslint
可以对代码进行校验,一定程度上提升了代码质量
命名or注释
命名的好坏相当重要,代码整洁之道的作者Bob大叔说过:好的命名可以使代码不需要注释
,日常开发中个人常常遵守以下规则:
-
必须全英文: 即使读你代码的同学不认识某个单词,全英文的命名也为其留下了最后一条生路
-
不同类型命名使用不同结构:
- 常量:
全大写
- 类:
首字母大写
- 函数:
动词+名词
等等就不一一列举了
- 常量:
-
格式统一: 变量,文件夹,文件,
css
类等这些命名的格式有很多:大驼峰,小驼峰,BEM等等,选择什么格式不重要,格式保持统一很关键 -
注释,命名,命名长度的优先级:
准确释义 > 命名长度 > 注释
-
文档注释: 函数的文档注释相当有必要,很多时候我们无法只从函数名判断这个函数的用法: 接收什么参数,返回什么值,这时候一句简单的注释便能解决问题,当然
准确的命名
+TS
之后,文档注释也不需要了
解释变量
这是个人最常用的一个小技巧了,可以使判断条件一目了然
解释变量是一个专门为了解释某一个行为而存在的变量,虽然多声明一个变量会增加代码量,但对代码可读性的提高是这点额外代码量无法比拟的,最常见的场景便是判断语句中:
举个列子:
scss
if (age >= 18 && age <= 60) {
buyAlcohol();
}
能猜测到这个判断条件想表示的什么意思嘛?
下面使用解释变量来修改一下:
const canBuyBeer = (age >= 18 && age <= 60);
if (canBuyBeer) {
buyAlcohol();
}
现在读起来语义就清晰多辽
也许上面的例子太小了,无法体会解释变量的强大之处,那么当看到下面的代码会做什么感想呢?
vbnet
if ((order.totalAmount >= freeShippingThreshold &&
order.containsHeavyItems == false ||
(order.isPremiumCustomer && order.totalAmount >= premiumFreeShippingThreshold)) &&
order.deliveryAddress.country.inEurope()) {
applyFreeShipping(order);
}
哈哈哈,脑袋一下子就炸了,光看判断条件怎么也想不到这是判断用户的订单是否符合免费配送的条件吧!
层次结构
由单一职责原则到业务的抽象层级再到划分代码层次结构
函数要符合单一职责原则,一个函数只做一件事
.我刚开始听这个概念的时候感觉满脑子问号:只做一件事?什么是只做一件事?怎么才叫只做了一件事?后来在代码整洁之道
看到一句话:一个函数一个抽象层级
....一瞬间,,我顿悟了.
抽象是对业务的抽象,代码是对业务的实现,从业务可以抽象出代码的层次结构: 每个函数只做一件事情,每一个层级便是一件事情,根据抽象层级编写代码,于是就实现出有层次结构结构的代码.
之前写过一个简单的vscode插件Fast-ConsoleLog,可以在选中变量的上/下一行插入打印该变量的语句,以这个业务为例,聊聊如何根据单一职责原则来划分代码层次结构:
-
整体业务逻辑: 首先我们需要获取到插入的位置,然后获取到插入内容,同时为了保证插入代码和源代码的缩进相同,还要获取到当前的缩进,然后就是插入代码了,插入代码后还需要移动光标的位置到括号内,方便用户直接更改
-
对业务进行抽象,起始是一个层级,该层级内部又可以分为四个层级,依次类推,每个函数只干一个层级的事情
-
根据抽象层级写出的代码如下所示,这是第一个层级对应的函数,可以看到只用读名字就能知道该层级干了什么事情,无论是深入某个层级去了解具体细节,还是在当前层级了解整体业务,完全由读者掌控.
typescript/** * @message: 插入console字符串 * @param {'log'|'dir'} type console类型 * @param {*} line 插入位置偏移量 * @since: 2023-08-01 18:29:32 */ async function addConsole(type = "log", line) { const nextPos = getInsterPos(line); const snippet = await getText(type); await insertText(snippet, nextPos); cursorMove("left", 3); }
划分好层次结构,写出的代码将会是这样的:由上至下
可以快速
概览整体业务逻辑,由浅入深
可以详细
了解每一步的细节.这也是我的梦中情码
应该具备的素质之一.
就近定义
能将变量/函数
在第一次使用的地方就近定义的情况下就近定义.
有时读一个段代码需要在整个文件各个地方进行""跳跃"",甚至多个文件间"跳跃",思绪很容易被打断.虽然编辑器中点击变量即可自动跳跃到定义位置,但能在一个屏幕中显示的话还是推荐就近定义
空行的妙用
也算是控制代码层次的一种方式
使用空行将不同的逻辑代码分隔开,相近的逻辑代码保持紧凑,这样做的好处就是: 整体代码被分隔成一块一块的,一眼望去便知道这块代码大概分为几个部分,方便后期的查找.
事务隔离
适用于一个页面中多个组件的情况,如有三个Modal
弹窗组件,分别对应增删改的功能,那么将需要三个变量控制弹窗的打开和关闭,三个发送请求的方法,三个onOk
的回调.三个onClose
回调,如果还有其他逻辑就更复杂了,如果这些代码全都放在一起,很容易就搞混乱了.这时候可以通过事务隔离来进行逻辑的封装:
css
定义三个对象:可以是createOption,modifyOption,delOption,然后将对应的逻辑封装在对象中,就像这样:
const createOption = {
open: () => {},
close: () => {},
fetch: () => {},
commit: () => {}
}
当别人读代码的时候会知道这里有三个业务逻辑,每个对象对应一个
同时如果后期更改需求,可以快速找到对应的逻辑模块,进行修改.
以上为例,许多场景都可以使用事务隔离进行处理,即可提高可读性,同时提高后期的可维护性
写在最后
常用的技巧差不多就这些了,之后想起其他的再回来补充.也欢迎各位大佬进行指点斧正.祝大家都能写出自己的梦中情码
.