這里將向大家分享的是一些我對(duì)編程的思考總結(jié),這些經(jīng)驗(yàn)在我畢生編程生涯中曾幫助我在無數(shù)的事情上作出正確的決定。這些編程策略有些是很顯然的,但實(shí)際編程中往往被人們忽略。
下面的例子是用Python寫的,但這些概念適用于任何編程語言。
1. 異常處理和if-else語句的用法
編程的時(shí)候,有些邊界情況我們需要確保能正確的處理。對(duì)這些情況我們通常的做法是使用if
語句來檢查是否是這種情況。當(dāng)程序運(yùn)行時(shí),這些檢查動(dòng)作每次都會(huì)執(zhí)行,來驗(yàn)證是否是遇到了這些特殊場景。如果你使用的編程語言有異常處理系統(tǒng)——你可以利用它們來處理這些邊界情況。
C語言里沒有異常處理系統(tǒng)。它依賴于錯(cuò)誤碼來通知調(diào)用的函數(shù)發(fā)生了什么。返回0是成功,負(fù)數(shù)則表示失敗。所以,調(diào)用者需要用if-else
來檢查返回碼。沒有其它的方法。
但對(duì)于那些有異常處理系統(tǒng)的編程語言,我們可以很好的利用它們。但我們需要使用if-else
配合異常處理機(jī)制來處理這些邊界情況或錯(cuò)誤。
一個(gè)簡單的例子
想象有一個(gè)后臺(tái)運(yùn)行程序,它在啟動(dòng)和停止時(shí)都會(huì)檢查一個(gè)pid文件。它會(huì)調(diào)用下面的函數(shù)來獲取pid。主調(diào)函數(shù)使用異常捕獲來確保程序邏輯不會(huì)出現(xiàn)意外。
下列情況時(shí)這個(gè)函數(shù)會(huì)被調(diào)用 -
- 這個(gè)后臺(tái)程序啟動(dòng)時(shí)
- 這個(gè)后臺(tái)程序停止時(shí)
每種情況時(shí)主函數(shù)要做的事 -
啟動(dòng)時(shí)
- 如果pid文件存在,意味著后臺(tái)程序中運(yùn)行。這個(gè)程序自己會(huì)停止,會(huì)提示有另一個(gè)實(shí)例已經(jīng)在運(yùn)行。
- 讀取這個(gè)文件時(shí)如果返回錯(cuò)誤,這說明沒有pid文件,說明這個(gè)程序沒有運(yùn)行(除非讀取文件時(shí)發(fā)生意外)。這時(shí)就創(chuàng)建pid文件,啟動(dòng)程序。
停止時(shí)
- 如果發(fā)現(xiàn)了pid文件,停止前刪除這個(gè)文件。如果沒有發(fā)現(xiàn)pid文件,那該怎么辦?這說明后臺(tái)程序根本沒有運(yùn)行。報(bào)告給用戶。
- 下面就是我們上面提到的主程序會(huì)調(diào)用的獲取pid的代碼。注意我們使用異常捕獲和if-else語句來處理這些情況。
方法 1
- # 這種使用異常的方式不好,屬于被動(dòng)防御式編程。
- def read_pid_file():
- try:
- f = open('daemon.pid', 'r')
- pid = int(f.read())
- return pid
- # 沒有發(fā)現(xiàn)文件,也可能是IO錯(cuò)誤
- except IOError:
- raise "Faild to Read file"
- # 有人在文件里放的不是數(shù)字,這能怪誰?
- except ValueError:
- raise WrongPID
- # 捕獲所有其它異常
- # 這個(gè)有點(diǎn)像
- # 過度使用異常處理
- except Exception:
- raise SomeUnKnownError
方法 2
- # 使用If/else方法。主調(diào)函數(shù)需要檢查無返回值情況
- # 異常情況
- def read_pid_file():
- if os.path.exists('daemon.pid'):
- try:
- f = open('file.pid', 'r')
- # 對(duì)于支持異常處理機(jī)制的編程語言,
- # 如果有操作失敗,拋出異常
- # 這里跟C語言有區(qū)別
- return int(f.read())
- except (ValueError, IOError):
- pass
方法 3
- # 事實(shí)上,我們知道可能會(huì)發(fā)生什么,如果pid讀文件
- # 文件時(shí)有錯(cuò)誤,主調(diào)函數(shù)會(huì)捕獲它。
- # 我們使用的編程語言有異常處理機(jī)制。
- # 我們可以在這里利用上。
- def read_pid_file():
- f = open('daemon.pid', 'r')
- return int(f.read())
兩種錯(cuò)誤處理方式都是我們保證程序無誤的重要途徑。
何時(shí)使用if-else
語句
- 當(dāng)我們知道可能會(huì)有什么情況發(fā)生時(shí)。也許會(huì)分很多種情況。(C語言的錯(cuò)誤碼機(jī)制就是一個(gè)很好的例子)。
- 我們通常是基于輸入值使用if-else來控制執(zhí)行路徑。
- 何時(shí)使用異常處理
- 你想捕獲一個(gè)異常,或者捕獲一些異常但自己不處理,交給系統(tǒng)去處理。支持異常機(jī)制的編程語言會(huì)在最頂層捕獲這些異常,并報(bào)告給用戶。
2. 代碼優(yōu)化
找出程序的主執(zhí)行路徑——你的程序大部分時(shí)間都執(zhí)行這些模塊。首先優(yōu)化這部分代碼,但也不要在程序?qū)崿F(xiàn)的***次迭代中進(jìn)行優(yōu)化。那些處理邊界情況或失敗/異常處理的地方,這部分代碼不需要優(yōu)化,除非它們引起了值得注意的性能問題。
3. 代碼行數(shù)
不要試圖壓縮代碼行數(shù),但你應(yīng)該壓縮每個(gè)任務(wù)的代碼行數(shù)。寫簡單的函數(shù)/方法,每個(gè)函數(shù)/方法只完成一個(gè)任務(wù),而不是多個(gè),除非你有很好的理由。
人們通常喜歡為了減少代碼行數(shù)而在一個(gè)代碼片段里完成大量的工作,這會(huì)導(dǎo)致代碼異常復(fù)雜,這種代碼試圖支持各種情況的處理,而大多時(shí)候只是其中的一種情況會(huì)發(fā)生。多余的情況處理會(huì)給執(zhí)行造成成本。
4. 多學(xué)習(xí)操作系統(tǒng)和編譯器知識(shí)
了解機(jī)器,理解機(jī)器內(nèi)部里事情是如何工作的。這將會(huì)幫助理解各種不同瓶頸產(chǎn)生的原因。這能幫助你找到代碼運(yùn)行時(shí)為什么會(huì)發(fā)生奇怪的現(xiàn)象。
5. 運(yùn)用管理技術(shù)
在編程中運(yùn)用管理技術(shù)。針對(duì)不同目的使用正確的工具。我有自己的喜好,但我努力克服。
6. 忽略上面所有的策略
有時(shí)候事情就是這樣!而且這樣并不一定是壞事。我們編程時(shí)經(jīng)常這樣——當(dāng)我們開發(fā)一個(gè)新原型,或針對(duì)一個(gè)特殊問題找一個(gè)解決方案,這時(shí)我們?nèi)绾螌?shí)現(xiàn)并不重要,重要的是在定型后我們?nèi)绾瓮瓿伤鼈?。我想大多時(shí)候我們都是這樣做的。誰都知道,先打草稿,后動(dòng)真的。
請(qǐng)?jiān)谠u(píng)論里留下你對(duì)這些觀點(diǎn)的想法。