編寫優(yōu)秀的代碼
- 代碼是程序可識別的代碼
- 代碼是程序員可識別的代碼
防御性編程
防御性編程(Defensive programming)是防御式設(shè)計的一種具體體現(xiàn)厉熟,它是為了保證,對程序的不可預(yù)見的使用白翻,不會造成程序功能上的損壞绢片。它可以被看作是為了減少或消除墨菲定律效力的想法。防御式編程主要用于可能被濫用巢株,惡作劇或無意地造成災(zāi)難性影響的程序上熙涤。---百度百科
為什么要進行防御性編程
防御性編程是為了讓我寫出可維護以及更少的bug的一種編程方式,它可能完全讓我們寫出無bug的應(yīng)用程序所以我們在編寫代碼的時候要始終保持一顆警惕之心那槽。通常的編碼方式是下面這種:
編碼 -> 測試 -> 編碼 -> 測試-> .......
這種方式去編寫和調(diào)試代碼等舔,如果我們使用防御性編程編寫代碼之后基本上就可以使用下面這種方式進行編碼 -> 測試 -> 測試 -> .....
如何減少bug
// 程序出Bug了?
// ∩∩
// 』胖病(′?ω?)
// _| ?/(___
// 〉咏健/ └-(___/
//  ̄ ̄ ̄ ̄ ̄ ̄ ̄
// 算了反正不是我寫的
// ?⌒/ヽ-只锭、_
// ≡憾/?_/____ /
// 『硖堋 ̄ ̄ ̄ ̄ ̄ ̄ ̄
// 萬一是我寫的呢
// ∩∩
// ∽莨恕(′?ω?)
// _| ?/(___
// / └-(___/
// 》蠼谩 ̄ ̄ ̄ ̄ ̄ ̄ ̄
// 算了反正改了一個又出三個
// ?⌒/ヽ-汉额、_
// /?_/____ /
// ≡趺! ̄ ̄ ̄ ̄ ̄ ̄ ̄
一個應(yīng)用程序一般是處理外部輸入妓灌,然后將處理結(jié)果輸出。一般在這個過程中有以下幾個地方會產(chǎn)生bug
- 外部輸入 -> 程序處理 -> 輸出
-
外部輸入
不要相信任何輸入祥山,進行入?yún)z測
-
程序處理
注意拋出的異常掉伏,以及邏輯分支處理
-
程序輸出
異常時的輸出,成功和失敗時的輸出
外部輸入
比如服務(wù)器返回的數(shù)據(jù)岖免,以及函數(shù)的一些入?yún)ⅰN覀儜?yīng)該建立和服務(wù)器返回數(shù)據(jù)類型一樣的接口為了接下來的編碼工作更容易的進行话侧。
{
"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)該注意這幾點
- 參數(shù)
- 返回值
-
參數(shù)
對于函數(shù)的入?yún)⑹欠裥枰獧z查瞻鹏,做哪些檢查
-
類型檢查
對于js這種弱類型語言進行類型檢查是必須的鹿寨,如果沒有進行類型檢查就會造成bug的產(chǎn)生比如
function contain(item, array) { return array.indexOf(item) !== -1 }
這樣看起來似乎沒有問題,這是因為這看起來好像是我們這個方法從函數(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ù)不能進行工作丙唧。還是會報錯。那么肯定有人會說我創(chuàng)建這個函數(shù)就是讓用戶輸入數(shù)組培漏,但是它輸入其他類型就是不對的胡本。由于js的類型是運行時才能確認(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 }
-
-
返回值
一個函數(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 因為外界使用的過程會進行非空判斷蜈垮。
```js
const people = jsonParse("{"age":4}")
if(people) {
console.log(people.age)
}
```
如果代碼可以寫成下面的多好啊
```js
const people = jsonParse("{"age":4}")
console.log(people?.age)
```
js可以使用babel插件實現(xiàn)這種可選鏈,以后可能會加到es標(biāo)準(zhǔn)中去课兄。[ts](https://github.com/Microsoft/TypeScript/issues/16)還不支持晨继。其實在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
}
//處理條件滿足時的情況
```
#### 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īng)該空扎,以前怎么沒問題?
幻想型:可能是數(shù)據(jù)有問題转锈。
無辜型:我好幾個星期都沒碰這塊代碼了!
樂觀型:只需要改一行代碼竿痰,不會影響其它程序的砌溺。
實踐型:你重啟一下服務(wù)試試。
---- 來自知乎如何減少bug
總結(jié):
1. 進行code review
2. 編寫UT
3. 良好的編碼習(xí)慣(嚴(yán)謹(jǐn)?shù)倪壿嬎季S)