为什么要有代码规范

"为什么要有代码规范?"

看到这个问题,可能行内人就会说"这是问题吗?这需要讨论吗?",因为现在已经是行内人的共同认知了。然而,对于未入行或刚入门的小伙伴们又确实是问题。而且,理清之后还能能帮他们建立更好的观念,让后面的工作走得更顺。

大神唐纳德.克努特在《计算机编程艺术》中,说过"代码是给人看的,顺带着给机器执行"。

"Programs are meant to be ready by humans and only icidentally for computers to execute."

------Donald Ervin Knuth《The Art of Computer Programming

怎么理解这句话呢?

乍一看,它是违反我们的直觉的,但是细细想来,又是非常合理的------代码在机器的世界里,最后都会转化成0和1,它本来的样子机器根本就不在乎;反而,代码在人类世界里,都是需要被反复阅读理解的,const a = 0const showDialog = false ,在人类世界完全就是不一样的语句。

所以,代码的的确确是写给人看的。

那既然代码都是写给人看的,我们就要想办法写出好看的代码。怎么个好看法呢?在这里我把它分成悦目和赏心两种。

目标一:悦目,看起来很舒服

悦目,就是字面上的看起来好看,要处理好标点符号、格式、排版的问题。

虽然不至于像政府的红头文件那样具体规范到每个字、每个词、每个标点,也不至于导致要像强迫症那样每敲一个字母都小心翼翼,但是起码要保证层级对齐,空格间隙一致。

而且很幸运的是,现在的代码工具都能解决大部分的格式问题。你只需要点击鼠标右键,进行格式化即可。

除了代码层面要好看,还可以规范到文件夹等项目架构上。比如,以下就是一个 angularjs 写的项目。

文件夹中,事无巨细地规定了各文件夹的功能:

  • @core 中, 有专门负责数据处理的 data ,本地数据模拟 mock,和常用的 js 工具库 utils。
  • @theme 中,分了组件、指令、布局、管道、样式,
  • pages 中,则是各个页面的组件、html、css

文件中,命名也很讲究:

  • 用 module 后缀表示模块的代码,如上 core.module.ts
  • 用 component 后缀表示组件的代码,如上 chartjs-bar.component.ts
  • 用 layout 后缀表示布局的代码,如上 one-column.layout.ts
  • 相关功能的命名前缀保持一致,如 chartjs-bar-horizontal.component.ts 和 chartjs-bar.component.ts

这样,整个目录结构阅读下来,就对项目整体有了很好的认识。如果现在让你去修改一个数据,你就能立马想到要去 @core/data 查看代码了。

目标二:赏心,降低心智负担

而赏心,则要让人减少心力消耗,也就是现在常说的降低心智负担。

1. 减少 bug 发生

试想想,你拿到一个旧项目,执行时,控制台输出一堆 warning,出了一身冷汗;然后到 99% 的时候,又来了几个 error,整个项目就彻底起不来,那不是整个人都崩溃了~

比如,容易引起 XSS 攻击的写法、Java 的空指针、前端的eval字符串转函数,这些都会在规范中作规定,指出处理方法。

再比如 vue 规范中的,"组件名为多个单词必要"。官方解释是:这样做可以避免跟现有的以及未来的 HTML 元素相冲突,因为所有的 HTML 元素名称都是单个单词的。不仅考虑了当前的情况,更考虑了未来可能出现的情况。

2. 让人更好理解

如何让人更好理解,在代码规范中占大篇幅的内容。

比如常说的命名问题,可以规定常用的动词,get,set,save,load,delete 等作为常用的方法名前缀;也可以规避拼音和英文混排的情况,因为这样会让人在两个语言中来回切换,还是十分痛苦的;如果是行业软件,提供行业内的英文单词表,对我们中国的开发者也更友好一些。

又比如注释,要把函数的功能,输入输出,甚至例子写得清楚明白。以下是前端工具库 lodash 深拷贝方法的注释,3行代码,却有 10 行的完整的注释:

scss 复制代码
**
 * This method is like `clone` except that it recursively clones `value`.
 * Object inheritance is preserved.
 *
 * @since 1.0.0
 * @category Lang
 * @param {*} value The value to recursively clone.
 * @returns {*} Returns the deep cloned value.
 * @see clone
 * @example
 *
 * const objects = [{ 'a': 1 }, { 'b': 2 }]
 *
 * const deep = cloneDeep(objects)
 * console.log(deep[0] === objects[0])
 * // => false
 */
function cloneDeep(value) {
    return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG);
}

另外,我们要注意的是:函数是有顺序、有层级的。

将函数拆分成短小精悍的函数,或将函数有规律地整理或者分层,不随便跳转的函数,都能让人快速的理解代码。虽然现在的编程语言已经不像以前的 Basic 那样有 goto 语句,但是还是经常有同学在函数中使用大段的 if else,并随意调用其他函数,这些同样会导致阅读起来费劲。

这些也可以写到我们的规范中。

示例 ,一个理想的前端 vue 代码:

xml 复制代码
<script>
import '...' from vue;
import '...' from '@utils/';
import '...' from './components/';
​
export default {
  components: {},
  props(){},
  data(){},
  methods: {
    // 其他一些被本组件调用的函数
    ...,
    // 最后的入口函数
    getData(),
    processData(),
    bindEvent(),
  },
  mounted() {
    this.getData();
    this.processData();
    this.bindEvent();
  }
}
</script>
<template>
...
</template>
<style>
...
</style>

可以看出其将代码作了一定的顺序排布:

  • 遵循先定义后使用的原则,定义变量的 script 放前面,template 后面;
  • import 从远及近地引入库。
  • 定义组件时,从外部引入的 component、props 先定义,然后才是本地的变量 data,最后是方法 methods 和入口mounted;
  • 方法中,越是底层的方法放在越上面,最后才放入口调用的方法。

这样处理之后,如果要阅读整体的代码,只需要从入口文件开始,进行阅读,就能大概理解全貌了;要理解代码细节的时候,再往上阅读即可。

总结

写出赏心悦目的代码,这是一个说大不大说小不小的目标,也是我们写代码第一天起就要去想的问题。

而代码规范需要为我们指明方向,我想这是代码规范存在的意义。

相关推荐
徐子颐1 分钟前
从 Vibe Coding 到 Agent Coding:Cursor 2.0 开启下一代 AI 开发范式
前端
小月鸭14 分钟前
如何理解HTML语义化
前端·html
jump68037 分钟前
url输入到网页展示会发生什么?
前端
诸葛韩信40 分钟前
我们需要了解的Web Workers
前端
brzhang1 小时前
我觉得可以试试 TOON —— 一个为 LLM 而生的极致压缩数据格式
前端·后端·架构
yivifu1 小时前
JavaScript Selection API详解
java·前端·javascript
这儿有一堆花1 小时前
告别 Class 组件:拥抱 React Hooks 带来的函数式新范式
前端·javascript·react.js
十二春秋1 小时前
场景模拟:基础路由配置
前端
六月的可乐1 小时前
实战干货-Vue实现AI聊天助手全流程解析
前端·vue.js·ai编程
一 乐2 小时前
智慧党建|党务学习|基于SprinBoot+vue的智慧党建学习平台(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·学习