防御式编程

编写优秀的代码

  1. 代码是程序可识别的代码
  2. 代码是程序员可识别的代码

防御性编程

防御性编程(Defensive programming)是防御式设计的一种具体体现,它是为了保证,对程序的不可预见的使用,不会造成程序功能上的损坏。它可以被看作是为了减少或消除墨菲定律效力的想法。防御式编程主要用于可能被滥用,恶作剧或无意地造成灾难性影响的程序上。---百度百科

为什么要进行防御性编程

防御性编程是为了让我写出可维护以及更少的bug的一种编程方式,它可能完全让我们写出无bug的应用程序所以我们在编写代码的时候要始终保持一颗警惕之心。通常的编码方式是下面这种:

  • 编码 -> 测试 -> 编码 -> 测试-> .......
    这种方式去编写和调试代码,如果我们使用防御性编程编写代码之后基本上就可以使用下面这种方式进行

  • 编码 -> 测试 -> 测试 -> .....

如何减少bug


// 程序出Bug了?
//    ∩∩
//   (´・ω・)
//   _| ⊃/(___
//  / └-(___/
//   ̄ ̄ ̄ ̄ ̄ ̄ ̄
// 算了反正不是我写的
//    ⊂⌒/ヽ-、_
//  /⊂_/____ /
//   ̄ ̄ ̄ ̄ ̄ ̄ ̄
// 万一是我写的呢
//    ∩∩
//   (´・ω・)
//   _| ⊃/(___
//  / └-(___/
//   ̄ ̄ ̄ ̄ ̄ ̄ ̄
// 算了反正改了一个又出三个
//    ⊂⌒/ヽ-、_
//  /⊂_/____ /
//   ̄ ̄ ̄ ̄ ̄ ̄ ̄

一个应用程序一般是处理外部输入,然后将处理结果输出。一般在这个过程中有以下几个地方会产生bug

  • 外部输入 -> 程序处理 -> 输出
  1. 外部输入

    不要相信任何输入,进行入参检测

  2. 程序处理

    注意抛出的异常,以及逻辑分支处理

  3. 程序输出

    异常时的输出,成功和失败时的输出

外部输入

比如服务器返回的数据,以及函数的一些入参。我们应该建立和服务器返回数据类型一样的接口为了接下来的编码工作更容易的进行。


{
    "code": 1,
    "data": {
        "count": 3,
        "result": [{
            "gId": "49",
            "iconUrl": "http:\/\/pic.cdn.sunmi.com\/IMG\/5a715de5d6162.png",
            "goods_title": "银豹零售版",
            "goods_describe": "全场景满足中小零售门店经营需求",
            "goods_unit": "3",
            "goods_spec": "标准版",
            "sId": "218",
            "goods_price": "180.00",
            "goods_type": "1",
            "num": "1",
            "subTotal": 180,
            "cart_id": "1615",
            "unit": "0",
            "begin_num": "1"
        }],
        "total": 14716,
        "number": 15
    },
    "msg": ""
}

我们的接口应该是这样的


interface GoodItem {
  gId: string,
  iconUrl: string,
  goodsTitle: string,
  goodsDescribe: string,
  goodsUnit: string,
  goodsSpec: string,
  sId: string,
  goodsPrice: string,
  goodsType: string,
  num: string,
  subTotal: number,
  cartId: string,
  unit: string,
  beginNum: string
}

interface CartListResponse {
  code: number,
  result: Array<GoodItem>,
}

编写一个函数

编写一个函数应该注意这几点

  • 参数
  • 返回值
  1. 参数

    对于函数的入参是否需要检查,做哪些检查

    • 类型检查

      对于js这种弱类型语言进行类型检查是必须的,如果没有进行类型检查就会造成bug的产生比如

      function contain(item, array) {
        return array.indexOf(item) !== -1
      }
      

      这样看起来似乎没有问题,这是因为这看起来好像是我们这个方法从函数和参数的命名上是说我们查 看一个元素是否在数组中,似乎没有错,但是一般作为一个工具函数的话,我们肯定要考虑到多种情况就是如果传入的参数array是一个null,或者undefined或者是字符串,或者是object类型怎么样,当然传入一个字符串他也是能工作的,但是这不是我们创建这个函数的初衷。

      
      function contain(item, array=[]) {
          return array.indexOf(item) !== -1
      }
      
      

      我们给array默认传一个空数组那么就可以解决了上面的array为空和undfied等情况,但是其他类型函数不能进行工作。还是会报错。那么肯定有人会说我创建这个函数就是让用户输入数组,但是它输入其他类型就是不对的。由于js的类型是运行时才能确认出来的,所以我们在编写代码的时候就应该注意。

      function contain(item, array=[]) {
          if (!_.isArray(array)) {
              return false
          }
          
          return array.indexOf(item) !== -1
      }
      

      当然我们可以使用ts在编译阶段就能告诉我们这些错误

      
      function contain<T>(item: T, array: Array<T>) {
          return array.indexOf(item) !== -1
      }
      
      
  2. 返回值

    一个函数的返回值应该是确定的,除非这个函数是非受控的函数。

    
    function jsonParse(string: string): ?object {
        if (string.length === 0) {
          return null
        }
    
        let object = null
    
    
        try {
          object = JSON.parse(string)
        } catch (error) {
          // 处理错误
          console.log(error)
        }
        return object
    

}

```

上面这段代码是把一个json字符串转换成一个对象,可能存在解析失败的情况。我们看到这个函数就是一个非受控的函数,有两种返回值,空或者有值得情况。这一种返回值我们叫做option value 因为外界使用的过程会进行非空判断。

```js
const people = jsonParse("{"age":4}")
if(people) {
    console.log(people.age)
}

```

如果代码可以写成下面的多好啊

```js
const people = jsonParse("{"age":4}")
console.log(people?.age)
```

js可以使用babel插件实现这种可选链,以后可能会加到es标准中去。[ts](https://github.com/Microsoft/TypeScript/issues/16)还不支持。其实在js中我们经常能遇到这种情况比如要取得某个属性我们都是 
```
   const data = response && response.result && response.result.data
``` 


一个完整的函数应该是这样的

```js

function name(params:type) {
  // 条件检查
  if (condition) {
    return
  }

  // 变量声明和初始化

  const name = null
  const age = null

  // 逻辑操作数据处理

}

```

#### if语句需不需要else

```js

if(condition) {
    // 条件满足时的情况
} else {
    // 条件不满足的情况
}

```
如果条件不满足的情况我们不希望函数执行下去

```
    if(!condition) {
        return
    }
    
    //处理条件满足时的情况

```

#### switch 语句一定要有defautl

```js
    
    switch (key) {
      case value:
        
        break;
    
      default:
        break;
    }

```

减少变量的声明

在声明一个变量的时候应该考虑是否需要这个变量,特别是全局变量.下面有两个例子大家感觉那个代码比较容易读?


    enum PeopleType {
      none = '0',
      man = '1',
      woman = '2'
    }

 function getPeopleType(type:PeopleType) {
    let peopleType = null

    switch (type) {
      case PeopleType.none:
        peopleType = 'none'
        break;
      case PeopleType.man:
        peopleType = 'man'
        break;
      case PeopleType.woman:
        peopleType = 'woman'
        break;
      default:
        peopleType = 'none'
        break;
    }

    return peopleType
  }

    enum PeopleType {
      none = '0',
      man = '1',
      woman = '2'
    }

  function getPeopleType(type:PeopleType) {
    if (type === PeopleType.none) {
      return 'none'
    }

    if (type === PeopleType.man) {
      return 'man'
    }

    if (type === PeopleType.woman) {
      return 'woman'
    }

    return 'none'
  }

面对bug每个人的反应不同

首先来看看遇到bug各种程序员是怎么反应的:

理性型:这个 bug 能复现吗?
自负型:这不可能,在我这是好好的。
经验型:不应该,以前怎么没问题?
幻想型:可能是数据有问题。
无辜型:我好几个星期都没碰这块代码了!
乐观型:只需要改一行代码,不会影响其它程序的。
实践型:你重启一下服务试试。

---- 来自知乎如何减少bug

总结:

1. 进行code review
2. 编写UT
3. 良好的编码习惯(严谨的逻辑思维)
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容

  • 防御式编程 在防御式驾驶中要建立这样一种思维,那就是你永远也不能确定另一位司机将要做什么。这样才能够确保在其他人做...
    刘硕jessie阅读 5,420评论 1 49
  • 主要思想: 子程序应该不因传入错误数据而被破坏, 哪怕是由其他子程序产生的错误数据;换一种说法是, 程序员应该承认...
    娟子阅读 2,345评论 0 1
  • 最近业余时间在阅读《代码大全》,阅读“防御式编程”章节的时候非常受启发,自己之前对系统的错误处理这块也确实随意了。...
    henry_g阅读 634评论 0 0
  • 当你想要时间上的自由,那你必须努力做到金钱上的自由才行! 当你一味地觉得,你把挣的钱给你最至亲的人,是在帮助他们减...
    X阿霞阅读 128评论 0 0
  • 《书都不会读,你还想成功》 零散时间比你想象的要多 文/吴晓黎 什么样的时间可以用来读书?当你的答案确定为利用一切...
    吉佳呖呖阅读 238评论 0 1