程序員修煉之道<二>

15、死程序不說謊

我們很容易掉進“它不可能發生”這樣一種心理狀態。
【很多時候我們在項目中遇到問題或者bug時,第一反應就是這不可能。但事實就是錯誤已經發生了,這說明非常、非常糟糕的事情已經發生,我們不能糾結“事情不可能”這個問題上,而是要弄清楚事情爲什麼會發生,思考解決方案,並編碼調試,最終把這種“不可能”消除】

要崩潰,不要破壞
儘早檢測問題的好處就是你可以更早的崩潰,Java和C++採用異常機制來捕獲意料之外的事情。如果沒有異常機制,或者庫不拋出異常,那就要確保自己對錯誤進行了處理,在C語言中,可以利用宏來完成這一功能。

# define CHECK(LINE, EXPECTED)                       \
{                                                    \  
    int rc = LINE;                                   \
    if (rc != EXPECTED)                              \   
    ut_abort(__FILE__,__LINE, $LINE, rc, EXPECTED); \
}

當你的代碼發現某件不可能的事情已經發生時,你的程序已經沒有存活能力。它做任何事情都會變得可疑,所以要儘快的終止它。死程序帶來的危害通常比病程序小得多。

16、斷言式編程

如果它不可能發生,用斷言確保它不會發生。斷言可能在編譯的時候被關閉,決不要把必須執行的代碼放在assert中。

不要用斷言代替真正的錯誤處理。

printf("Enter 'Y' orN': “);
ch = getchar();
assert((ch == 'Y') || (ch == ’N‘));

這種做法不是好idea,assert會調用exit退出整個程序,這可能不是你真正處理錯誤的意圖。

關於斷言的常見誤解:
【斷言給代碼增加了一些開銷。因爲它們檢查決不應該發生的事情,所以只會由代碼中的bug觸發。一旦代碼經過了測試併發布出去,它們就不再需要存在,應該被關閉,以使代碼運行得更快。斷言是一種調試設施。】

這裏有兩個明顯錯誤的假設:首先,假定測試能過找到所有的bug;其次,你的程序運行在一個非常”安全“的世界。第一條防線是檢查任何可能發生的錯誤,第二條防線是使用斷言設法檢查你疏漏的錯誤。

不應該使用斷言來控制程序的邏輯,例如:

void func(int a)
{
      if(a != 1)
     {
          .........
     }
     else
     { 
           assert(false);
     }
}

這種情況類似於利用斷言來處理錯誤。

你們認爲下面”不可能的事情”中,哪些可能發生
1) 一個月少於28天
2) 內角和不等於180度的三角形
3) 沒有60秒的一分鐘

17、何時使用異常

檢查每一個可能的錯誤(特別是意料之外的錯誤)是一種良好的習慣,但是對錯誤處理過頭了,可能會把你引向相當醜陋的代碼,你程序的正常邏輯可能會被錯誤處理完全遮蔽,隨處可見的只有錯誤處理。

18、怎麼配平資源

對於資源分配和解除分配的處理要有始有終,這意味着分配某項資源的例程或對象應該負責解除該資源的分配。

【嵌套的分配】
對於不止一個資源的例程或者對象:以與分配資源相反的次序解除資源的分配;在代碼的不同地方分配同一組資源,總是以相同的次序分配它們。這將降低發生死鎖的可能性。

purify(www.rational.com)和Insure++(www.parasoft.com)是兩種檢查運行中的程序內存泄露的工具

19、解耦與得墨忒耳法則

把你的代碼組織成最小組織單元(模塊),並限制它們之間的交互!

20、元程序設計

我們想要讓我們的系統變得高度可配置。

元數據是任何對應用進行描述的數據【應用該怎麼樣運行、它應該使用什麼資源,等等】,元數據在運行時、而不是在編譯時被訪問和使用。

爲一般情況編程程序,把具體情況放在別處。【將抽象放進代碼,細節放進元數據】

建議以純文本方式表示配置元數據,如果在應用啓動的時候加載配置,那如果需要改變配置的話,這會迫使你重新啓動應用程序。更爲靈活的方法是編寫能在運行時重新加載其配置的程序。

21、時間耦合

時間有兩個方面對我們很重要:併發和次序!

編寫線性代碼,我們很容易做出一些假定,把我們引向不整潔的編程!

對併發和時序依賴進行思考還能夠引導你設計更加整潔的接口

22、它只是視圖

不要把程序寫成一個大塊,而應該“分而治之”,把程序劃分爲模塊。每個模塊都有其自身的責任!

23、靠巧合編程

作爲開發者,我們時刻工作在雷區,我們應該避免靠巧合編程,而要深思熟慮地編程。

怎樣深思熟慮地編程
(1)總是意識到你在做什麼。
(2)不要盲目地編程。試圖構建你不熟悉的應用,或是使用你不熟悉的技術,就是希望自己被巧合誤導。
(3)按照計劃行事。
(4)依靠可靠的事物。不要依靠巧合或假定。
(5)爲你的假定建立文檔。
(6)不要只是測試你的代碼,還要測試你的假定。
(7)爲你的工作劃分優先級。
(8)不要做立時的奴隸。不要讓已有的代碼支配將來的代碼。
作爲一個新手,我現在編寫代碼基本上都是靠已有的代碼在支撐,這是一個學習的過程,應該儘量避免這樣做,如果新手不這樣做的話,可能就是在使用自己不熟悉的技術了。

24、算法速率

簡單循環、嵌套循環、二分法、分而治之和組合的時間複雜度。

25、重構

隨着程序的演化,我們有必要重新思考早先的決策,並重寫部分代碼。代碼需要演化,它不是靜態的事物。

重寫、重做和重新架構代碼合起來稱爲重構(refactoring)。以前設計的東西都可以根據新的事實、更深的理解、變化的需求等等,重新進行設計。

【應該在何時進行重構】:重複、非正交的設計、過時的知識、改善性能。

時間壓力常常被用作不進行重構的藉口。追蹤需要重構的事物,如果你不能立刻重構某樣東西,一定要把它列入計劃,確保收到影響的代碼最少。

怎麼進行良好的重構:
(1)不要試圖在重構的時候增加新功能;
(2)在開始重構之前,確保你擁有良好的測試;
(3)採取短小、深思熟慮的步驟。如果你使你的步驟保持短小,並在每一個步驟之後進行代碼測試,你將能夠避免長時間的測試。

26、邪惡的嚮導

你在使用嚮導,卻不理解它製作出的所有代碼,你就無法控制你自己的應用。不要使用你不理解的嚮導代碼。

嚮導與庫調用或標準的操作系統服務不一樣,嚮導生成的代碼最終會變成應用的完整組成部分,並沒有被分解出來。

27、需求之坑

開發必須解決商業問題,而不只是滿足陳述的需求。用文檔記載需求背後的原因將在每天進行實現決策時給你的團隊帶來無價的信息。

28、解開不可能解開的謎題

在面對棘手的問題時,列出所有在你面前的可能途徑。不要排除任何東西,不管它聽起來有多無用或者愚蠢。逐一檢查列表中的每一項,並解釋爲何不能採用某個特定的途徑。對你的約束進行分類,並劃分優先級。

有時候你會發現,當你在處理一個問題的時候似乎比你想象的要難很多。感覺自己好像是走錯了路,認爲一定有比這更容易的方法!這時正是你退回一步的時候,問問自己以下問題:
(1)是否真的有更加容易的方法?
(2)你是在設法解決真正的問題,還是被外圍的技術問題轉移了注意力?
(3)這件事爲什麼是一個問題?
(4)是什麼使它如此難以解決?
(5)它必須以這種方式完成嗎?
(6)它真的必須完成嗎?
很多時候,對需求的重新詮釋能讓整個問題全部消失。

29、等你準備好

當你面對一件任務時,如果你反覆感覺到疑慮,或是體驗到某種勉強,你就要注意它。你可能無法馬上指出問題的所在,但你需要好好靜下來理清思路,找出問題的來源。

30、規範陷阱

對有些事情“做”勝於“描述”,要知道,隨着規範越來越詳細,你得到的回報會遞減,甚至會是負回報。

31、注重實效的團隊

(1)不要留破窗戶:團隊作爲一個整體,不應該容忍破窗戶——-那些小小的、無人修正的不完美。
(2)時刻注意周圍的變化:確保每個人都主動地監視環境的變化,對新需求進行持續的度量。
(3)交流:團隊中的開發者必須相互交談。創立品牌,啓動項目時,給項目區一個響亮的名字,最好是不尋常的某種東西,這樣很容易讓人記住。
(4)不要重複你自己:重複會造成工作的浪費,並且可能會帶來維護的噩夢。
(5)正交性:認爲項目的各種活動——-分析、設計、編碼、測試———會孤立地發生,這是一個錯誤。它們只是看待同一問題的不同方式。可以按功能劃分團隊,這種分組方式能夠極大地減少各個開發者之間的相互影響。
(6)自動化:使團隊所做的每一件事情自動化。

32、無情的測試

早測試、常測試、自動測試。bug被發現得越早,進行修補的成本就越低。好的項目擁有測試代碼可能比產品代碼還要多。要通過全部測試,編碼纔算完成。
單元測試——-集成測試———驗證和校驗——–資源耗盡、錯誤及恢復——–性能測試—–可用性測試

33、全部都是寫

代碼中的註釋:把項目的那些難以描述、容易忘記,卻又不能記載在別的任何地方的東西記載下來。
大家都喜歡看到簡單的模塊級頭註釋、關於重要數據與類型說明的註釋、以及給每一個類和每一個方法所加的簡單頭註釋、用以描述函數的用法和任何不明瞭的事情。

34、極大的慾望

項目的成功是有它在多大程度上滿足了用戶的期望來衡量的。不符合用戶預期的項目註定是失敗的,不管交付的產品在絕對的意義上有多好。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章