如何編寫高質量的程序

如何編寫高質量的程序

學習任何編程語言都會有一個基本的過程,開始的時候學習基本的語法,然後學習各種庫,框架,開始做各種項目。在做項目的過程中,隨着代碼量的增加,我們會漸漸感到失去對程序的掌控能力,bug開始增加,牽一髮而動全身,顧此失彼。這充分說明了編寫高質量程序的重要性,這裏的“高質量”主要指程序的正確性,可讀性,可維護性。

什麼是高質量的程序

正確性

程序正確性的重要程度無需多言,尤其在一些特殊領域,例如芯片製造業,航天業,武器製造業,對程序正確性往往有着極其嚴格的要求,因爲一旦程序出錯,代價往往是巨大的。在這些領域,需要使用形式化方法(formal methods)來自動驗證程序的正確性,也就是說你需要證明程序的正確性,而不僅僅保證程序在大多數情況下是正確的。在其它領域,對正確性沒有這麼高要求,形式化方法也不適用,但是我們還是需要使用其它手段,例如測試,code review等等來保證軟件的正確性。

可讀性

可讀性可以幫助程序作者理清思路,思路清晰後,程序不容易出錯。另外,其它程序員在維護你的代碼時,更容易理解你的意思,方便修改bug,方便擴展。

不要浪費自己的時間,更不要浪費別人的時間。

可維護性

這裏的可維護性主要指程序應對變化的能力。程序在完成基本功能後,可能會發生各種改變:用戶需求變了,性能達不到要求需要重新實現算法,等等。一旦程序的一個點發生改變,其它點如果也需要同時手動改變,那麼程序會變的不可控制,出bug的機會會增加。想像一下,我們的程序是一個盒子,在添加新功能時,如果只需要把新模塊插到一個地方,新模塊就可以被系統使用,這樣的程序可維護性是很高的。但是如果添加新功能時,需要把原來的程序盒子拆開,其它模塊也需要相應修改,才能加入新模塊,這樣的程序可維護性就很差。

提高程序質量的重要措施

Code Review
爲代碼做複查,是保證程序質量的有效手段,複查時需要檢查代碼風格,一致性,安全,是否正確實現了需求等方面。






測試

爲什麼強調先編寫測試用例,再實現程序?先編寫測試用例的意義在於,讓編寫程序的人對程序本身有更好的理解。因爲你首先得明白什麼樣的程序是正確的,然後才能寫出正確的程序。測試用例其實是對程序正確性的一種描述。

爲什麼強調自動化測試,而不是手動測試?因爲自動化測試可以增加測試的便捷度,而人們通常會更多地使用那些便捷度高的東西。我在做個人項目的時候就發現,在編寫了自動測試的腳本後,我每改動一點程序,就會自動運行一下腳本,在此之前,我明知道測試很重要,但是還是不會測試的如此頻繁。這樣的好處是可以方便定位bug,否則在系統經過了大量改動之後,出了bug都不知道可能在哪裏。

在對程序進行重構時,很重要的一點就在於,一定要先寫好測試用例,然後每改動一點,就自動測試一下,保證程序始終保持在可控狀態。

良好的編程風格

良好的編程風格,可以增強程序的可讀性,一個結構清晰的程序,你會更容易從中發現錯誤。另一方面,當程序發生變化時,很可能引入新的bug,良好的編程風格可以減少這種bug的出現。下面是與編程風格相關的一些措施。

  • 風格指南

找一份你使用的編程語言的風格指南,例如Google的編程語言風格指南系列,Python的PEP8,並一直遵守這份指南的內容,如果有自動化工具幫助你保持這種風格,那再好不過。

  • 最佳實踐

尋找你所使用語言的最佳實踐,他們可讀性強,經過了大量實踐的考驗,被廣泛接受,所以儘可能多地使用他們。

例如Python 的 The Hitchhiker's Guide to Python

  • 起一個好名字

變量,函數名,類名,都需要一個好名字。程序本身是對解決方案的一種描述,一個好的名字會增強這種描述性,也會讓你的思維集中於解決方案,同時讓其它人更容易理解你的解決方案。

  • 不要直接使用常量

在程序中直接使用的常量,一般被稱爲 Magic Numbers, 一方面它不利於其它程序員對程序的理解,因爲沒有人知道這個常量代表什麼。另一方面,多個常量之間可能是有關係的,直接使用常量根本反應不出這種關係。

  • 同一變量名不要有多種含義

首先這種做法降低了可讀性,一個變量前面一個含義,後面一個含義,這會給閱讀程序的人帶來困擾。

  • 儘可能保證變量作用域小

儘量減少變量定義的點與變量最後一次使用的點之間的跨度,這樣可以使變量與其相關代碼變得緊湊,提高可讀性,不用在使用變量時再去很多的地方查看其它引用。

  • 保證函數短小精悍

過長的函數會讓讀者陷入細節的泥潭,還需要前後來回看才能明白前面一大段和後面一大段代碼的關係。將函數分解,然後給函數起一個好名字,讀者馬上就能明白這段代碼在做什麼。

提高應變能力

程序應對變化的能力強,可擴展性就強,也更容易在變化時保證正確性,這樣的程序可維護性強。下面是一些提高程序應變能力的措施。

  • 不要使用常量

不要使用常量的另一個原因在於常量可能變化,如果程序中多次引入了這個常量,那麼一旦這個常量要發生變化,就需要同時改動許多地方,這時候,如果有些地方沒有改,就會使程序不一致,可能引入bug。

  • 同一變量名不要有多種含義

同一變量名不要有多種含義另一個原因在於,多種含義之間可能會相互影響,第一次寫程序時你可能記得這些影響,但是以後對程序進行改動的時候,你可能就忘記了。例如函數內一段代碼執行後,索引i 的值等於一個長度,但是這段代碼後,你沒有將i賦值給另一個變量len,而是直接使用它。等過一段時間後,你或者其它人修改這段程序時,很可能忘了這段代碼執行後i的值需要等於一個長度,因爲這是一種隱式的約定,所以很容易被忽視。

  • 儘可能保證變量作用域小

保證變量作用域小也有利於重構。當一個函數變得很長時,你可能需要將它分解成多個函數,這時候,如果變量跨度小,就可以很方便地提取函數,不用來回查找與此函數相關的變量的引用。

  • 減少代碼重複

如果有一段代碼在很多地方重複,這就告訴你,需要把他們提取成一個函數。因爲代碼的重複意味着這是一塊獨立的邏輯,獨立的邏輯可以抽象成一個函數。另一方面,一旦這段邏輯需要發生變化,只需要修改這個函數就可以了,不需要把所有地方都手動修改一遍。

  • 數據驅動

數據驅動的意思是用數據表示來代替程序邏輯。例如,我們需要一個程序,判斷某個月有幾天,在實現時,最好用一個數組表示各個月的天數,需要哪個月直接查詢就好,而不要使用大量的if語句來作邏輯判斷。這只是一個小例子,它提醒我們,如果程序中含有大量判斷語句,就應該想一想,能不能用數據來驅動邏輯,這樣需要修改的時候,我們直接修改數據就好,而不用修改程序邏輯。

我曾經接手過一個項目,這個項目其實是一個工具集,根據用戶的選擇,調用不同的工具。原始的代碼裏,就使用了大量if語句,並且每個工具其實調用方式和代碼都很相似。這樣,我每次添加新工具時,就需要找到多個if語句塊,作相應修改。如果用數據驅動的話,我們完全可以去掉這些if語句,在用戶的選擇與工具之間建立對應關係,這樣每當新添加工具時,只需要把工具加到系統裏,系統會根據這個表直接找到這個工具。這其實和之前舉的盒子的例子很相似,添加新工具時,只需要把工具插到盒子上的槽上,根本不用打開盒子。這就大大提高了程序的可擴展性。

控制複雜度

要保證軟件的高質量,很重要的一方面在於控制複雜度。控制複雜度的一個很重要的手段在於分解複雜的事物。我們之所以覺得一個事物複雜,是因爲同一時間需要關心的事情太多,把複雜事物分解後,每次我們只需要關心很少的事情,這樣就控制住了複雜度。

  • 不要使函數或類過大

如果一個函數或類過大,他們會變得過分複雜,你同一時間需要關心許多細節。將函數或類變小之後,你的思維在一段時間內可以集中在同一個抽象層次,而不必過於深入其細節,這樣更容易發現程序中的缺陷,因爲你每次只需要關心很少的事情。在最高層,你只需要關心模塊之間的關係,關心算法的流程,不必關心模塊內部的事情。在最低層,你只需要關心一個模塊內部的事情,而不必關心其它事情。

  • 不要使函數參數過多

函數參數過多可能說明這個函數負責了太多的事情,你需要將這個函數分解。另一方面,你需要從邏輯上考慮,這些參數是不是一個整體,如果是一個整體,那麼直接傳過來一個結構體,或者傳過來一個對象,是不是更合適?

  • 不要使抽象層次過多

如果一個函數或類被分解爲過多的抽象層次,在模塊內部,你確實只需要關心很小的事情,但是這時候,由於模塊過多,抽象層次過深,他們之間的關係又使複雜度增長起來。

使用自動化工具

自動化工具迫使我們養成良好的編程習慣,而且不容易出錯。再次強調:

    工具越是使用方便,你越會頻繁使用它。

所以,儘可能地讓你的工具使用便捷。 例如:

  • 使用一些靜態檢測工具在編輯時自動幫助你檢測程序的不良風格
  • 使用靜態檢測工具檢測程序常見錯誤
  • 使用重構工具幫助你重構
  • 使用自動化測試工具在保存時自動運行測試

注意事項

沒有什麼事情是一成不變的,所有的法則都需要考慮具體的情況。如果你要用一個法則,需要真正明白自己爲什麼要用,需要去權衡,而不要爲了能用上這個法則而生搬硬套。

好好問問自己:

  • 變化真的存在麼?
  • 真的需要抽象麼?
  • 真的需要面向對象麼?
  • 真的xxx麼?

參考資料

這篇文章是我這段時間閱讀過一些書後的想法,書目有

  • 代碼大全(Code Complete)
  • 重構——改善既有代碼的設計(Refactoring Improving the Design of Existing Code)
  • 程序設計實踐(The Proactice of Programming)

在閱讀這些書的同時,我還在維護其它人的代碼,做自己的個人項目。在閱讀的過程中,我會不斷地想到我做的項目哪裏有問題,可以用書中提到的方法去修改,因此印象深刻。這些書單純讀也非常有好處,但是如果可以結合到自己的項目中,會有更大裨益。因爲只有產生了強烈的共鳴,才能保證真正理解了一個東西。

上面提到的一些措施,都是我遇到過的,所以印象比較深刻,這幾本書中還有大量提高程序質量的方法,我這裏只是一個引子,希望給有心人打開一扇窗戶。

轉載地址 http://blog.csdn.net/on_1y/article/details/18238851

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