代码质量管理——怎样写出文雅地代码

作为一个刚写代码不久的小菜鸟,事情的半年多让我越发意想到进步代码质量的重要性。夙昔只会关注完成功用,逐步的最先关注机能,现阶段则发明实在另有许多细节也是(如可读性、易用性、可保护性、一致性)进步代码质量的症结。“完成功用”跟“文雅地完成功用”是两回事。

注:大部份内容归结自收集,将多篇文章的看法汇总加工了一下,也融会了一些个人的看法。

准绳

  • 单一职责准绳
  • 易用性准绳
  • 可读性准绳
  • 庞杂性守恒准绳:不管你怎样写代码,庞杂性都是不会消逝的

    注:假如逻辑很庞杂,那末代码看起来就应该是庞杂的。假如逻辑很简朴,代码看起来就应该是简朴的。

单一职责准绳

面向对象五大设想形式基本准绳之一。即一部份代码只应该用于某一个特定功用,不应与其他功用耦合在一同

假定你的一个function同时完成了功用a和功用b,以后需求变动,你须要修正功用a,然则由于这两个功用都在一个function里,你就不能不再去确认是不是会影响到功用b。这就造成了不必要的本钱。

以下我总结了三个拆分代码的准绳:

“and”准绳

当你为你的要领定名时不能不加上“and”时,就该斟酌斟酌是不是是要把这个要领拆分一下了。

“100”准绳

当你的一个function凌驾一百行时,肯定要举行拆分了。

注:这里的100可以有点多,只是对我个人而言,100算是我的极限,总之就是相对不要将一个函数写的太长。

敕令、查询拆分准绳

我们开辟中大部份操纵可以总结为“敕令”和“查询”,如写cookie、修正data、发送post要求都可以叫“敕令”,而读取cookie、ajax猎取数据则以为是“查询”操纵。

函数式编程中考究“数据不可变”,即:

只需纯的没有副作用的函数,才是及格的函数。

副作用:指当挪用函数时,除了返回函数值之外,还对主挪用函数发生附加的影响。比方修正全局变量(函数外的变量)或修正参数。

优点是使得开辟越发简朴,可回溯,测试友爱,削减了任何可以的副作用。

将“敕令”与“查询”拆分实际上就是函数式编程头脑的部份表现,参考以下代码:

function getFirstName() {
    var firstName = document.querySelector("#firstName").value;
    firstName = firstName.toLowerCase();
    setCookie("firstName", firstName);
    if (firstName === null) {
        return "";
    }
    return firstName;
}
 
var activeFirstName = getFirstName();

经由过程名字来看,该要领是用于猎取first name的,但实际上它还设置了cookie,这是我们没有预感的。关于一个“查询”要领,它不应该有任何修正要领外变量的行动,即“副作用”。更好的写法以下:

function getFirstName() {
    var firstName = document.querySelector("#firstName").value
    if (firstName === null) {
        return "";
    }
    return firstName;
}
 
setCookie("firstName", getFirstName().toLowerCase());

一览无余,getFirstName只返回firstName,而设置cookie操纵在它之外举行。

易用性准绳

简朴

这里的简朴,重要归结为function的一些设想准绳,有以下几点:挪用简朴、易明白、削减影象本钱、参数处置惩罚。

以下,仅仅想完成修正dom色彩、宽度等属性,原生代码以下:

document.querySelector('#id').style.color = 'red'
document.querySelector('#id').style.width = '123px'
document.querySelector('#id').style.height = '456px'

而封装事后:

function a(selector, color, width, height) {
  document.querySelector(selector).style.color = color
  document.querySelector(selector).style.width = width
  document.querySelector(selector).style.height = height
}
a('#a', 'red')

霎时变得简朴可用了 ~

但该要领还存在一个题目,那就是定名太笼统了。。。除了开辟者本身之外不可以有人在不看源码的状况下一眼看出这个要领a是干吗的。那末咱再把这个要领名改写得更易明白一点:

function letSomeElementChange(selector, color, width, height) {
  document.querySelector(selector).style.color = color
  document.querySelector(selector).style.width = width
  document.querySelector(selector).style.height = height
}

如许我们就可以一览无余该要领的作用 ~ 不过仍有可优化的处所。这么长的要领名谁记得住,要削减影象本钱啊,再改个名:

function setElement(selector, color, width, height) {
  document.querySelector(selector).style.color = color
  document.querySelector(selector).style.width = width
  document.querySelector(selector).style.height = height
}

OK,现在这个要领已满足它的职责而且很好用了,但还以为怪怪的。这一坨参数太碍眼。。。

function setElement(selector, opt) {
  const { color, width, height } = opt
  color && document.querySelector(selector).style.color = color
  width && document.querySelector(selector).style.width = width
  height && document.querySelector(selector).style.height = height
}

把多个参数兼并一下,并在内部做兼容处置惩罚,这个要领便易用多了。纵然不传第二个参数也不会有任何副作用。

一致性

假如有如许一个要领,猎取歌曲列表,并将其设置到div的innerText中:

function getSongs() {
  return $.get('/songs).then((response) {
      div.innerText = response.songs
  })
}

这就违犯了要领的内外一致性,也违犯了上文的单一职责准绳敕令、查询拆分准绳,由于它不仅猎取了歌单,同时还修正了innerText,要让其更合理:

  • 要么换个名字
  • 要么拆分为两个要领

低耦合

耦合是权衡一个递次单位对其他递次单位的依靠水平。耦合(或高耦合)是应该尽力防止的。假如你发明本身正在复制和粘贴代码并举行小的变动,或许重写代码,由于其他处所发生了变动,这就是高耦合的表现。

耦合会严峻影响代码的复用性及可扩展性,让后人保护时不能不修正以至重写这部份代码,不仅浪费时刻还会致使仓储中又多出一块类似的代码,很轻易让人疑惑。

同时,修正耦合度高的代码时常常会牵一发而动全身,假如修正时没有理清这些耦合关联,那末带来的效果可以会是灾难性的,特别是关于需求变化较多以及多人合作开辟保护的项目,修正一个处所会引起原本已运转稳固的模块毛病,严峻时会致使恶性循环,题目永久改不完,开辟和测试都在种种题目之间奔走劳顿,末了致使项目延期,用户满意度下降,本钱也增加了,这对用户和开辟商影响都是很卑劣的,种种风险也就显而易见了。

高内聚

不应该将没有任何联络的东西堆到一同。

内聚是一个类中变量与要领衔接强度的范例。高内聚是值得要的,由于它意味着类可以更好地实行一项事情。低内聚是不好的,由于它表明类中的元素之间很少相干。每一个要领也应该高内聚,大多数的要领只实行一个功用,不要在要领中增加‘分外’的指令,如许会致使要领实行更多的函数,同时也违反了上文的单一职责准绳

低内聚的表现:假如属性没有被类中的多个要领运用,这多是低内聚的标志。一样,假如要领在几种差别的状况下不能被重用,或许假如一个要领基础不被运用,这也多是低内聚的一个标志。

高内聚有助于减缓高耦合,高耦合是须要高内聚的标志。然则,假如两个题目同时存在,应该挑选内聚的体式格局。关于开辟者来讲,高内聚平常比低耦合更有协助,只管二者平常可以一同完成。

毛病处置惩罚

  • 可预感的毛病:诸如ajax回调、函数参数,这类题目很好处理,只需在开辟时多斟酌一步,对种种极度状况做好兼容即可。
  • 不可预感的毛病:类似兼容性题目,这类题目没法在开辟时准确预感的毛病,可以准备好抛错,console.error/log/warn,末了你还可以为本身的递次留些后路: try…catch。

可读性准绳

定名

定名应该保证他人经由过程称号一眼就可以晓得这个变量保留的是什么,或许这个要领是用来做什么的。

  • 平常变量、属性用名词以下:

    var person = {
      name: 'Frank'
    }
    var student = {
      grade: 3,
      class: 2
    }
  • bool变量、属性用(形容词)或许(be动词)或许(神态动词)或许(hasX),以下:

    var person = {
      dead: false, // 假如是形容词,前面就没必要加 is,比方isDead 就很空话
      canSpeak: true, //神态动词有 can、should、will、need 等,神态动词背面接动词
      isVip: true, // be 动词有 is、was 等,背面平常接名词
      hasChildren: true, // has 加名词
    }
  • 平常函数、要领用(动词)开首:

    var person = {
      run(){}, // 不及物动词
      drinkWater(){}, // 及物动词
      eat(foo){}, // 及物动词加参数(参数是名词)
    }
  • 回调、钩子函数:

    var person = {
      beforeDie(){},
      afterDie(){},
      // 或许
      willDie(){}
      dead(){} // 这里跟 bool 争执,你只需差别时暴露 bool dead 和函数 dead 就行,怕争执就用上面的 afterDie
    }
    button.addEventListener('click', onButtonClick)
    var component = {
      beforeCreate(){},
      created(){},
      beforeMount(){}
    }
  • 定名一致性

    • 递次一致性:比方 updateContainerWidth 和 updateHeightOfContainer 的递次就使人很别扭
    • 时刻一致性:有可以跟着代码的变迁,一个变量的寄义已差别于它一最先的寄义了,这个时刻你须要实时改掉这个变量的名字。

这一条是最难做到的,由于写代码轻易,改代码难。假如这个代码构造得不好,极可以会涌现牵一发而动全身的状况(如全局变量就很难改)

解释

不须要多花梢,只需把作用、用法形貌清晰即可。要领的范例解释应该以下:

/**
 * [function_name description]
 * @param  {[type]} argument [description]
 * @return {[type]}          [description]
 */
function function_name(argument) {
  // body...
}

将要领的参数与返回值都写清晰,我现在用的IDE是sublime,运用Docblockr插件可以自动天生格式化解释,很轻易。

Bad Smell

项目中我们常常可以遇这类代码,它们仍可用,然则很“臭”,外洋管这类代码有一个统称,即“bad smell”。以下这类代码可以说是很“臭”了:

  • 内外不一的代码
  • 过期的解释
  • 逻辑很简朴,然则看起来很庞杂的代码
  • 反复的代码
  • 类似的代码
  • 老是一同涌现的代码
  • 未运用的依靠
  • 差别作风的代码

款式范例

  1. 准确定名:class必须用“-”写法,不要用驼峰和下划线。
  2. 准确嵌套:一般状况下肯定要将class嵌套闭合,不然就相当于增加到全局,假如有反复定名的class就会受影响。
  3. 谢绝copy:假如想复用已有的款式,直接在原有class上用“,”语法支解,就可以运用,不要再copy一份款式,会让两份款式都被运用,就要斟酌款式掩盖的题目,很不友爱。
  4. 滥用class:没有必要加的class不要加,每一个class的增加都应该有明白来由。滥用class的话可以会致使款式掩盖,不应运用这个款式的处所用了这个款式。
  5. 慎用 !important,会强行掩盖一切同属性款式,一旦运用后会让代码难以保护,开辟过程当中相对不要依靠该要领。以下总结了一些运用 !important的履历:

    • 肯定要优化斟酌运用款式划定规矩的优先级来处理题目而不是 !important
    • 只需在须要掩盖全站或外部 css(比方援用的 ExtJs 或许 YUI )的特定页面中运用 !important
    • 处理紧要线上题目可以运用,但以后也要尽快用可保护的体式格局将代码替代返来
    • 永久不要在全站局限的 css 上运用 !important
    • 永久不要在你的插件中运用 !important

说得轻易,做起来难

破窗效应

此理论以为环境中的不良征象假如被听任存在,会诱使人们仿效,以至变本加厉。一幢有少量破窗的修建为例,假如那些窗不被修理好,可以将会有损坏者损坏更多的窗户。终究他们以至会突入修建内,假如发明无人居住,或许就在那边定居或许放火。一面墙,假如涌现一些涂鸦没有被清洗掉,很快的,墙上就布满了杂乱无章、不堪入目的东西;一条人行道有些许纸屑,不久后就会有更多渣滓,终究人们会视若天经地义地将渣滓随手抛弃在地上。这个征象,就是犯罪心理学中的
破窗效应,在编程范畴一样存在。

要做到:只需是经由你手的代码,都会比之前好一点。

参考文章:

    原文作者:小歪
    原文地址: https://segmentfault.com/a/1190000013397521
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞