防御式編程

編寫優(yōu)秀的代碼

  1. 代碼是程序可識別的代碼
  2. 代碼是程序員可識別的代碼

防御性編程

防御性編程(Defensive programming)是防御式設(shè)計(jì)的一種具體體現(xiàn),它是為了保證,對程序的不可預(yù)見的使用,不會造成程序功能上的損壞。它可以被看作是為了減少或消除墨菲定律效力的想法。防御式編程主要用于可能被濫用,惡作劇或無意地造成災(zāi)難性影響的程序上。---百度百科

為什么要進(jìn)行防御性編程

防御性編程是為了讓我寫出可維護(hù)以及更少的bug的一種編程方式,它可能完全讓我們寫出無bug的應(yīng)用程序所以我們在編寫代碼的時候要始終保持一顆警惕之心。通常的編碼方式是下面這種:

  • 編碼 -> 測試 -> 編碼 -> 測試-> .......
    這種方式去編寫和調(diào)試代碼,如果我們使用防御性編程編寫代碼之后基本上就可以使用下面這種方式進(jìn)行

  • 編碼 -> 測試 -> 測試 -> .....

如何減少bug


// 程序出Bug了?
//    ∩∩
//  ?。ā?ω?)
//   _| ?/(___(dá)
// ?。?└-(___/
// ?。?// 算了反正不是我寫的
//    ?⌒/ヽ-、_
// ?。?_/____ /
// ?。?// 萬一是我寫的呢
//    ∩∩
//   (′?ω?)
//   _| ?/(___(dá)
// ?。?└-(___/
// ?。?// 算了反正改了一個又出三個
//    ?⌒/ヽ-、_
// ?。?_/____ /
// ?。?

一個應(yīng)用程序一般是處理外部輸入,然后將處理結(jié)果輸出。一般在這個過程中有以下幾個地方會產(chǎn)生bug

  • 外部輸入 -> 程序處理 -> 輸出
  1. 外部輸入

    不要相信任何輸入,進(jìn)行入?yún)z測

  2. 程序處理

    注意拋出的異常,以及邏輯分支處理

  3. 程序輸出

    異常時的輸出,成功和失敗時的輸出

外部輸入

比如服務(wù)器返回的數(shù)據(jù),以及函數(shù)的一些入?yún)ⅰN覀儜?yīng)該建立和服務(wù)器返回?cái)?shù)據(jù)類型一樣的接口為了接下來的編碼工作更容易的進(jìn)行。


{
    "code": 1,
    "data": {
        "count": 3,
        "result": [{
            "gId": "49",
            "iconUrl": "http:\/\/pic.cdn.sunmi.com\/IMG\/5a715de5d6162.png",
            "goods_title": "銀豹零售版",
            "goods_describe": "全場景滿足中小零售門店經(jīng)營需求",
            "goods_unit": "3",
            "goods_spec": "標(biāo)準(zhǔn)版",
            "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": ""
}

我們的接口應(yīng)該是這樣的


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>,
}

編寫一個函數(shù)

編寫一個函數(shù)應(yīng)該注意這幾點(diǎn)

  • 參數(shù)
  • 返回值
  1. 參數(shù)

    對于函數(shù)的入?yún)⑹欠裥枰獧z查,做哪些檢查

    • 類型檢查

      對于js這種弱類型語言進(jìn)行類型檢查是必須的,如果沒有進(jìn)行類型檢查就會造成bug的產(chǎn)生比如

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

      這樣看起來似乎沒有問題,這是因?yàn)檫@看起來好像是我們這個方法從函數(shù)和參數(shù)的命名上是說我們查 看一個元素是否在數(shù)組中,似乎沒有錯,但是一般作為一個工具函數(shù)的話,我們肯定要考慮到多種情況就是如果傳入的參數(shù)array是一個null,或者undefined或者是字符串,或者是object類型怎么樣,當(dāng)然傳入一個字符串他也是能工作的,但是這不是我們創(chuàng)建這個函數(shù)的初衷。

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

      我們給array默認(rèn)傳一個空數(shù)組那么就可以解決了上面的array為空和undfied等情況,但是其他類型函數(shù)不能進(jìn)行工作。還是會報(bào)錯。那么肯定有人會說我創(chuàng)建這個函數(shù)就是讓用戶輸入數(shù)組,但是它輸入其他類型就是不對的。由于js的類型是運(yùn)行時才能確認(rèn)出來的,所以我們在編寫代碼的時候就應(yīng)該注意。

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

      當(dāng)然我們可以使用ts在編譯階段就能告訴我們這些錯誤

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

    一個函數(shù)的返回值應(yīng)該是確定的,除非這個函數(shù)是非受控的函數(shù)。

    
    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字符串轉(zhuǎn)換成一個對象,可能存在解析失敗的情況。我們看到這個函數(shù)就是一個非受控的函數(shù),有兩種返回值,空或者有值得情況。這一種返回值我們叫做option value 因?yàn)橥饨缡褂玫倪^程會進(jìn)行非空判斷。

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

```

如果代碼可以寫成下面的多好啊

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

js可以使用babel插件實(shí)現(xiàn)這種可選鏈,以后可能會加到es標(biāo)準(zhǔn)中去。[ts](https://github.com/Microsoft/TypeScript/issues/16)還不支持。其實(shí)在js中我們經(jīng)常能遇到這種情況比如要取得某個屬性我們都是 
```
   const data = response && response.result && response.result.data
``` 


一個完整的函數(shù)應(yīng)該是這樣的

```js

function name(params:type) {
  // 條件檢查
  if (condition) {
    return
  }

  // 變量聲明和初始化

  const name = null
  const age = null

  // 邏輯操作數(shù)據(jù)處理

}

```

#### if語句需不需要else

```js

if(condition) {
    // 條件滿足時的情況
} else {
    // 條件不滿足的情況
}

```
如果條件不滿足的情況我們不希望函數(shù)執(zhí)行下去

```
    if(!condition) {
        return
    }
    
    //處理?xiàng)l件滿足時的情況

```

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

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

```

減少變量的聲明

在聲明一個變量的時候應(yīng)該考慮是否需要這個變量,特別是全局變量.下面有兩個例子大家感覺那個代碼比較容易讀?


    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每個人的反應(yīng)不同

首先來看看遇到bug各種程序員是怎么反應(yīng)的:

理性型:這個 bug 能復(fù)現(xiàn)嗎?
自負(fù)型:這不可能,在我這是好好的。
經(jīng)驗(yàn)型:不應(yīng)該,以前怎么沒問題?
幻想型:可能是數(shù)據(jù)有問題。
無辜型:我好幾個星期都沒碰這塊代碼了!
樂觀型:只需要改一行代碼,不會影響其它程序的。
實(shí)踐型:你重啟一下服務(wù)試試。

---- 來自知乎如何減少bug

總結(jié):

1. 進(jìn)行code review
2. 編寫UT
3. 良好的編碼習(xí)慣(嚴(yán)謹(jǐn)?shù)倪壿嬎季S)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 防御式編程 在防御式駕駛中要建立這樣一種思維,那就是你永遠(yuǎn)也不能確定另一位司機(jī)將要做什么。這樣才能夠確保在其他人做...
    劉碩jessie閱讀 5,577評論 1 49
  • 主要思想: 子程序應(yīng)該不因傳入錯誤數(shù)據(jù)而被破壞, 哪怕是由其他子程序產(chǎn)生的錯誤數(shù)據(jù);換一種說法是, 程序員應(yīng)該承認(rèn)...
    娟子閱讀 2,646評論 0 1
  • 最近業(yè)余時間在閱讀《代碼大全》,閱讀“防御式編程”章節(jié)的時候非常受啟發(fā),自己之前對系統(tǒng)的錯誤處理這塊也確實(shí)隨意了。...
    henry_g閱讀 714評論 0 0
  • 當(dāng)你想要時間上的自由,那你必須努力做到金錢上的自由才行! 當(dāng)你一味地覺得,你把掙的錢給你最至親的人,是在幫助他們減...
    X阿霞閱讀 150評論 0 0
  • 《書都不會讀,你還想成功》 零散時間比你想象的要多 文/吳曉黎 什么樣的時間可以用來讀書?當(dāng)你的答案確定為利用一切...
    吉佳嚦嚦閱讀 285評論 0 1

友情鏈接更多精彩內(nèi)容