自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

關(guān)于防御性編程,你應(yīng)該知道的事

開發(fā) 前端
關(guān)于防御性編程,這一概念開始來自于汽車的防御性駕駛技術(shù),意為你永遠(yuǎn)無法確定另一位司機將要做什么,才能確保他人做出危險動作時不會傷害到你。

提起編程,對于程序員同學(xué)而言并不陌生,關(guān)于防御性編程相信大家也有所耳聞,但是它具體包括哪些內(nèi)容呢?又有哪些行之有效的處理方案呢?我們又該如何正確應(yīng)用呢?

本文作者結(jié)合實際工作中的一些應(yīng)用經(jīng)驗,來全面解析一下防御性編程。

本文主要內(nèi)容:

  • 什么是防御性編程      
  • 防御性編程的重要性
  • 輸入檢查          
  • 斷言的應(yīng)用        
  • 錯誤處理          
  • 隔離              
  • 防御策略及建議    

1. 什么是防御性編程

關(guān)于防御性編程,這一概念開始來自于汽車的防御性駕駛技術(shù),意為你永遠(yuǎn)無法確定另一位司機將要做什么,才能確保他人做出危險動作時不會傷害到你。

防御性編程應(yīng)用過程中,并不是指讓你從保護(hù)自身,對他人持有“批判或攻擊”的態(tài)度,而是將保護(hù)的意識落地到自身程序上,通過一些防御手段讓你的代碼程序不因傳入的錯誤數(shù)據(jù)而出錯崩潰。大家通常會說,“代碼有問題很正常的呀”,的確是這樣,那更應(yīng)該在編寫程序的時候提高防御性的重要性,尤其核心程序能力,做好程序錯誤影響的包容性。

2. 防御性編程的重要性

隨著目前互聯(lián)網(wǎng)已滲透到各行各業(yè),每個細(xì)微的風(fēng)險問題都可能會被放大,足以影響整個行業(yè)。

  • 1996年6月4日,歐洲航天局的 Ariane 5 Flight 501 在起飛后 40 秒被引爆。因為導(dǎo)航軟件里的一個 bug,這個價值 10 億美金的運載火箭不得不自毀。
  • 2019年1月,拼多多被爆出現(xiàn)重大BUG,用戶可領(lǐng)100元無門檻券,造成大批用戶開始‘薅羊毛’,一晚上200多億都是話費充值。
  • 2019年5月時候,部分用戶反映其支付寶出現(xiàn)網(wǎng)絡(luò)故障,賬號無法登錄或支付。支付寶官方表示,該故障是由于杭州市蕭山區(qū)某地光纖被挖斷導(dǎo)致,這一事件造成部分用戶無法使用支付寶。

系統(tǒng)服務(wù)的穩(wěn)定性對于企業(yè)來說非常重要,不僅僅會對企業(yè)帶來直接的經(jīng)濟損失,甚至?xí)π袠I(yè)、人們的生活造成非常嚴(yán)重的影響。

3. 輸入檢查

在學(xué)習(xí)編碼的時候,估計大家都聽過“不要相信用戶的輸入”,指的就是對用戶輸入做檢查的必要性。談到輸入,常見Web開發(fā)主要包括以下兩個方面:

3.1 檢查所有來自系統(tǒng)外部的數(shù)據(jù)

在系統(tǒng)建設(shè)過程中,我們經(jīng)常會需要跟外部系統(tǒng)做數(shù)據(jù)交互處理,這里包括:文件、接口、消息隊列、表單用戶輸入等等,對于來自系統(tǒng)外部輸入的數(shù)據(jù)內(nèi)容,我們需要明確做到:

  • 數(shù)據(jù)格式是否準(zhǔn)確
  • 數(shù)據(jù)類型是否準(zhǔn)確
  • 數(shù)據(jù)長度是否準(zhǔn)確

對數(shù)據(jù)做預(yù)期準(zhǔn)確性檢查,保證輸入數(shù)據(jù)在我們程序的可接受范圍以內(nèi)。其實,所有的安全問題的本質(zhì)都是信任的問題。數(shù)據(jù)檢查,這個跟車站、機場的安全檢查相似。通過一個安全檢查(過濾,凈化)的過程,可以梳理未知的人或物,使其變得可信任。被劃分出來的具有不同信任級別的區(qū)域,我們稱為信任域,劃分兩個不同信任域之間的邊界,我們稱之為信任邊界。對于異常數(shù)據(jù)處理情況,做好防御檢查的,同時需要做好日志記錄,以防追后賬呢,哈哈~

3.2 檢查接口API的參數(shù)值

對于系統(tǒng)內(nèi)部接口API請求,需要檢查程序的輸入?yún)?shù)的值。這個跟檢查來自外部系統(tǒng)的數(shù)據(jù)一樣。

/**
* 請求處理通用類
**/
public class CommonRequest {
@NotBlank(message="參數(shù)str不能為空")
private String str;
@NotNull(message = "參數(shù)i不能為空")
private Integer i;

@Min(value =0,message = "最小值不能小于0")
private int min;

@Max(value=100,message = "最大值不能大約100")
private int max;
}

通常情況下,需要驗證如下幾項:

  • 字段必傳和非必傳
  • 字段類型是否一致
  • 參數(shù)值是否合法
  • 長度是否符合要求

對于接口參數(shù)/字段異常情況,大家可以按照以下思路來驗證問題:

  • Q1:如果參數(shù)缺失或者漏傳,會有默認(rèn)值么?
  • Q2:如果參數(shù)問題,業(yè)務(wù)邏輯會發(fā)生哪些不合理的情況?
  • Q3:字段缺失、不合法情況,對于寫操作,是否會造成垃圾數(shù)據(jù)的產(chǎn)生?

注意:補充一個關(guān)鍵情況,需要結(jié)合業(yè)務(wù)場景來評估可能的影響范圍。

必要情況,設(shè)置白名單而不是黑名單。

舉個栗子,在你設(shè)置圖像擴展名的時候,不要設(shè)置無效的類型,而是檢查有效的類型并排除其他類型。在 PHP 有無數(shù)的開源校驗庫,讓你的工作更簡單。

要記住:進(jìn)攻是最好的防守。總而言之,不要將代碼外部的函數(shù)調(diào)用或方法調(diào)用想得太過美好。請確保你調(diào)用外部的API和庫之前理解并測試了錯誤。

4. 斷言的應(yīng)用

4.1 何謂斷言?

所謂斷言,是指在開發(fā)期間使用的,讓程序在運行時進(jìn)行自檢的代碼。通常是一個子程序或者宏。

斷言的目的為了表示與驗證軟件開發(fā)者預(yù)期的結(jié)果,當(dāng)程序執(zhí)行到斷言的位置時,對應(yīng)的斷言應(yīng)該為真;若斷言不為真時,程序會中止執(zhí)行,并給出錯誤信息。

舉個例子:

如果系統(tǒng)假定一份數(shù)據(jù)信息文件所包含的記錄數(shù)不超過20000,那么程序中可以設(shè)置一個斷定記錄數(shù)<=20000 的斷言。只要 記錄數(shù)<= 20000,這一斷言都不會觸發(fā),然而一旦記錄數(shù)超過20000,它就會斷言程序存在一個錯誤。

4.2 斷言的形式

斷言可以有兩種形式:

  • assert Expression1
  • assert Expression1:Expression2

其中 Expression1 應(yīng)該總是一個布爾值,Expression2是斷言失敗時輸出的失敗消息的字符串。

如果Expression1為假,則拋出一個 AssertionError,這是一個錯誤,而不是一個異常,也就是說是一個不可控制異常(unchecked Exception),AssertionError由于是錯誤,所以可以不捕獲,但不推薦這樣做,因為那樣會使你的系統(tǒng)進(jìn)入不穩(wěn)定狀態(tài)。

public class TestAssert{undefined
public static void main(String[] args){undefined
String name = "abner chai";
//String name = null;
assert (name!=null):"變量name為空null";
System.out.println(name);
}
}

5. 錯誤處理

根據(jù)前面的介紹,斷言可以用于處理代碼中不應(yīng)該發(fā)生的錯誤,那又該如何處理那些預(yù)料中可能要發(fā)生的錯誤呢?

異常和錯誤處理是防御性編程的一個組成部分。

想象一下,啟動了一個異步操作,運行并輸出結(jié)果,沒有異常,這是一個理想的情況。如果在執(zhí)行過程中發(fā)生錯誤怎么辦?與任何未處理的異常一樣,應(yīng)用程序通常會崩潰。假設(shè)任何異步操作都會成功運行而沒有任何錯誤,那么可能會失敗。

高級語言中一般會采用try catch方式捕獲異常處理,如下示例:

try {
//邏輯代碼
} catch (exception e){
//異常處理代碼
}

try{
//邏輯代碼
} finally {
//一定要執(zhí)行的代碼
}

try {
//邏輯代碼
} catch (exception e){
//異常處理代碼
} finally{
//一定要執(zhí)行的代碼
}

而Golang的錯誤處理規(guī)范也是Go語言的最大亮點之一。

  • error接口

標(biāo)準(zhǔn)庫把error定義為接口類型, 以便于自己定義錯誤類型。

type error interface{
Error() string
}
  • Painc

golang的內(nèi)置方法,能夠改變程序的控制流。當(dāng)函數(shù)調(diào)用了panic,函數(shù)會停止運行,但是defer函數(shù)會運行,程序會在當(dāng)前panic的goroutine全部退棧以后crash。

  • Recover

recover也是golang的內(nèi)置方法,用于恢復(fù)發(fā)生panic的goroutine的控制,recover只在defer函數(shù)中生效。如果當(dāng)前goroutine將要發(fā)生panic的話, recover會捕獲這個panic,并恢復(fù)正常執(zhí)行。

  • Defer

聊到panic和recover,需要聊聊defer這個關(guān)鍵字,后面會看到defer在異常處理機制中起到的作用。go的defer是用來延遲執(zhí)行函數(shù)的,延遲的發(fā)生是在調(diào)用函數(shù)的returen之后。

6. 隔離

所謂隔離,是指程序可以包容由錯誤造成的損害,稱為一種容損策略。這個在軟件行業(yè)中最常見的方案,就是多機房建設(shè)。實現(xiàn)服務(wù)雙機房部署建設(shè),承受單機房故障,保障用戶體驗。這個實現(xiàn)的難點主要有如下三點:

  • 跨機房網(wǎng)絡(luò)延遲和帶寬限制導(dǎo)致的數(shù)據(jù)層面一致性問題
  • 機房之間流量調(diào)度
  • 業(yè)務(wù)改動不能太大

各個大廠對于核心服務(wù)多機房部署的實現(xiàn),簡單列舉以下幾種實現(xiàn)方案:

  • 高德

基于地理位置單元化,不同服務(wù)集群間雙向數(shù)據(jù)復(fù)制,內(nèi)部調(diào)用路由。

  • 微博

MySQL多機房同步(寫入時寫但機房,有專門的組件負(fù)責(zé)同步寫入到另一個機房)。

隔離的應(yīng)用,同時體現(xiàn)了在架構(gòu)設(shè)計上規(guī)定應(yīng)該如何應(yīng)用如何處理錯誤的價值。

7. 防御策略及建議

在防御性編程的路上,沒有銀彈。在產(chǎn)品中保留過多的防御性代碼,則會與精簡代碼實現(xiàn)產(chǎn)生相矛盾的地方。從產(chǎn)品本身出發(fā),在不影響用戶體驗的使用的情況下,使程序能夠穩(wěn)定的運行,梳理了如下幾項建議:

  • 保留重要錯誤檢查的代碼,去掉檢查細(xì)微錯誤的代碼
  • 保留讓程序穩(wěn)妥地崩潰的代碼,去掉會導(dǎo)致程序硬性崩潰的代碼
  • 確認(rèn)代碼中的錯誤消息是友好的,為技術(shù)支持人員做好錯誤信息記錄

其實,對于防御性編程,我們其實是要在保障程序穩(wěn)定和程序不過于臃腫之間找到一個合理的平衡。防御式編程技術(shù)可以讓錯誤更容易發(fā)現(xiàn),更容易修改,并減少錯誤對代碼的破壞,斷言可以幫助人們更早的發(fā)現(xiàn)錯誤,關(guān)于如何處理錯誤輸入的決策是一項關(guān)鍵的錯誤處理決策,也是一項關(guān)鍵的高層設(shè)計決策。防范看似微小的錯誤,收益價值可能遠(yuǎn)遠(yuǎn)超出你的想象。

責(zé)任編輯:武曉燕 來源: 架構(gòu)精進(jìn)之路
相關(guān)推薦

2023-12-15 08:17:13

防御性編程代碼

2015-11-05 18:03:15

虛擬化云計算資源池

2017-11-03 13:43:24

云計算Saas信息化

2024-10-09 12:03:06

2022-04-26 06:21:59

編程動態(tài)內(nèi)存

2020-08-23 21:07:16

編程PythonJava

2024-07-26 10:01:16

2018-05-30 12:04:36

LinuxUbuntu 18.0

2012-02-07 13:29:35

2020-06-05 10:36:30

云計算容器安全

2023-09-27 22:52:52

2022-05-07 19:18:16

防御性編碼代碼

2017-10-12 10:20:13

服務(wù)器運行壽命

2023-12-12 09:27:07

編程碼農(nóng)

2023-12-12 13:18:11

2022-10-11 23:50:43

JavaScript編程Promise

2016-11-01 23:16:52

光纖光纖線纜

2022-11-04 08:22:14

編譯代碼C語言

2010-09-02 18:56:09

NoSQL數(shù)據(jù)庫DBA

2010-08-09 13:20:36

Flex
點贊
收藏

51CTO技術(shù)棧公眾號