几个可以提高代码可读,可维护性的实践

七个小时的火车,闲来无事,总结一下对代码可读,可维护的一些个人实践,与诸位道友交流探讨

基本格式化

首先是对基本格式化的处理:

缩进,空格间隔,单双引号,提交信息格式等这些基本的格式化,在项目中统一交给:eslint,prettier,stylelint,commitlint等工具进行管理,可以减少了很大的心智负担,不仅如此eslint可以对代码进行校验,一定程度上提升了代码质量

命名or注释

命名的好坏相当重要,代码整洁之道的作者Bob大叔说过:好的命名可以使代码不需要注释,日常开发中个人常常遵守以下规则:

  1. 必须全英文: 即使读你代码的同学不认识某个单词,全英文的命名也为其留下了最后一条生路

  2. 不同类型命名使用不同结构:

    • 常量: 全大写
    • 类:首字母大写
    • 函数: 动词+名词

    等等就不一一列举了

  3. 格式统一: 变量,文件夹,文件,css类等这些命名的格式有很多:大驼峰,小驼峰,BEM等等,选择什么格式不重要,格式保持统一很关键

  4. 注释,命名,命名长度的优先级:准确释义 > 命名长度 > 注释

  5. 文档注释: 函数的文档注释相当有必要,很多时候我们无法只从函数名判断这个函数的用法: 接收什么参数,返回什么值,这时候一句简单的注释便能解决问题,当然准确的命名+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,可以在选中变量的上/下一行插入打印该变量的语句,以这个业务为例,聊聊如何根据单一职责原则来划分代码层次结构:

  1. 整体业务逻辑: 首先我们需要获取到插入的位置,然后获取到插入内容,同时为了保证插入代码和源代码的缩进相同,还要获取到当前的缩进,然后就是插入代码了,插入代码后还需要移动光标的位置到括号内,方便用户直接更改

  2. 对业务进行抽象,起始是一个层级,该层级内部又可以分为四个层级,依次类推,每个函数只干一个层级的事情

  1. 根据抽象层级写出的代码如下所示,这是第一个层级对应的函数,可以看到只用读名字就能知道该层级干了什么事情,无论是深入某个层级去了解具体细节,还是在当前层级了解整体业务,完全由读者掌控.

    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: () => {} 
}
当别人读代码的时候会知道这里有三个业务逻辑,每个对象对应一个
同时如果后期更改需求,可以快速找到对应的逻辑模块,进行修改.

以上为例,许多场景都可以使用事务隔离进行处理,即可提高可读性,同时提高后期的可维护性

写在最后

常用的技巧差不多就这些了,之后想起其他的再回来补充.也欢迎各位大佬进行指点斧正.祝大家都能写出自己的梦中情码.

相关推荐
new出一个对象3 小时前
uniapp接入BMapGL百度地图
javascript·百度·uni-app
你挚爱的强哥4 小时前
✅✅✅【Vue.js】sd.js基于jQuery Ajax最新原生完整版for凯哥API版本
javascript·vue.js·jquery
y先森4 小时前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy4 小时前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu10830189115 小时前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
IT女孩儿6 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡7 小时前
commitlint校验git提交信息
前端
虾球xz7 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇7 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒7 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript