为什么要有代码规范

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

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

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

"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;
  • 方法中,越是底层的方法放在越上面,最后才放入口调用的方法。

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

总结

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

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

相关推荐
沙尘暴炒饭几秒前
uniapp 前端解决精度丢失的问题 (后端返回分布式id)
前端·uni-app
昙鱼15 分钟前
springboot创建web项目
java·前端·spring boot·后端·spring·maven
天天进步201520 分钟前
Vue项目重构实践:如何构建可维护的企业级应用
前端·vue.js·重构
小华同学ai23 分钟前
vue-office:Star 4.2k,款支持多种Office文件预览的Vue组件库,一站式Office文件预览方案,真心不错
前端·javascript·vue.js·开源·github·office
APP 肖提莫24 分钟前
MyBatis-Plus分页拦截器,源码的重构(重构total总数的计算逻辑)
java·前端·算法
问道飞鱼36 分钟前
【前端知识】强大的js动画组件anime.js
开发语言·前端·javascript·anime.js
k093337 分钟前
vue中proxy代理配置(测试一)
前端·javascript·vue.js
傻小胖39 分钟前
React 脚手架使用指南
前端·react.js·前端框架
程序员海军1 小时前
2024 Nuxt3 年度生态总结
前端·nuxt.js
m0_748256781 小时前
SpringBoot 依赖之Spring Web
前端·spring boot·spring