日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

现代软件工程讲义 3 代码规范与代码复审

發布時間:2023/12/10 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 现代软件工程讲义 3 代码规范与代码复审 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

請參考原址:http://www.cnblogs.com/xinz/archive/2011/11/20/2255971.html

第10章

代碼規范與代碼復審


在第9章中,同學們完成了WC程序,經過評比,九條的程序獲得了第一名。這時,阿超說,現代軟件產業經過幾十年的發展,已經不可能出現一個人單槍匹馬完成一個軟件的事情了,軟件都是在相互合作中完成的。阿超建議大家互相看看別人的代碼,在TFS中每個人都把各自項目的權限放寬,允許別人訪問,交流一下意見。

兩個小時后,小飛來抱怨說,九條的代碼都是一行到底,隨意縮進,跟他提了意見,他還說“編譯通過就行了”。

他們找到了九條。

九條:我打麻將的時候牌都是亂擺,贏的也不少呀。

阿超:為什么要亂擺?

九條:因為怕圍觀的人看清我的牌路,我自己清楚就行了。

上課了。阿超問大家,我們寫的代碼是給人看的,還是給機器看的?

雜曰:人也看,機器也看。

阿超:對,但是最終是人在看。而且和打麻將不同,我們的代碼要讓“旁觀者”看得清清楚楚。請看下一段代碼,如代碼清單10-1所示,如果你接手這樣的代碼,有什么感想?

代碼清單10-1??badly formatted code – big C[1]

????????????????#include "stdafx.h"

????????????#include?????????????"stdio.h"

??????????void test();

???????????????????int _tmain

???????????????????(int argc,

??????????????????????_TCHAR*???????????argv[])

??????????????????????????{ test(); return

????????????????????????????????????0; }

?

?????????????????????????????????char C[25][40];void d(int x,int y)

???????????????{C[x][y]=C[x][y+1]=32;}int f(int x){return (int)x*x*.08;}

???????????????void test(){int i,j;????????????????????????????????????char s[5]="TEST";

??????????for(i=0;i<25;i++)

?????????for(j=0;j<40;j++)

????????C[i][j]=s[(i+j)%4];

???????for(i=1;i<=7;i++)

???????{d(18-i,12);

???????C[20-f(i)][i+19]=

????????C[20-f(i)][20-i]=32;

?????????}d(10,13);d(9,13);

??????????d(8,14);d(7,15);

??????????????d(6,16);d(5,18);d(5,20);?????????????????????????d(5,22);d(5,26);

??????????????????d(6,23);d(6,25);d(7,25);for(i=0;i<25;i++,printf("\n"))

??????????????????????????????????for(j=0;j<40;printf("%c",C[i][j++]));}


同學們紛紛發言,基本上有如下的反應:

1Faint!!

2)重寫程序!!

3)找到原作者,暴打一頓!!!

4)讓此人從公司辭職!!!!

計算機只關心編譯后的機器碼,你的程序是什么樣的縮進風格,以及變量名是否有統一的規范等和機器碼的執行無關。但是,做一個有商業價值的項目,或者在團隊里工作,代碼規范相當重要。

我們講的“代碼規范”可以分成兩個部分。

1)代碼風格規范。主要是文字上的規定,看似表面文章,實際上非常重要。

2)代碼設計規范。牽涉到程序設計、模塊之間的關系、設計模式等方方面面,這里有不少與具體程序設計語言息息相關的內容(如C/C++/Java/C#),但是也有通用的原則,這里主要討論通用的原則。

10.1??代碼風格規范

代碼風格的原則是:簡明,易讀,無二義性。

提示:這是移山公司的一家之言,如果碰到爭執,關鍵是要本著“保持簡明,讓代碼更容易讀”的原則,看看如下爭執中的代碼規范是否能夠讓程序員們更好地理解和維護程序。

10.1.1??縮進

是用Tab鍵好,還是248個空格?

結論:4個空格,在VS2005和其他的一些編輯工具中都可以定義Tab鍵擴展成為幾個空格鍵。不用?Tab鍵的理由是Tab鍵在不同的情況下會顯示不同的長度。4個空格的距離從可讀性來說正好。

10.1.2??行寬

行寬必須限制,但是以前有些文檔規定的80字符行寬太小了(以前的計算機/打字機顯示行寬為80字符),現在時代不同了,可為100字符。

10.1.3??括號

在復雜的條件表達式中,用括號清楚地表示邏輯優先級。對于表達式比較長的for語句和if語句,為了緊湊起見可以適當地去掉一些空格,如for (i=0; i<10; i++)if ((a<=b) && (c<=d))

10.1.4??斷行與空白的{ }行

程序的結構是什么風格?下面有幾種格式,我們一一討論。

最精簡的格式A

if (condition)????DoSomething();

else?????DoSomethingElse();

有人喜歡這樣,因為可以節省幾行,但是不同的語句(Statement)放在一行中,會使程序調試(DeBug)非常不方便,如果要一步一步觀察conditioncondition有可能是包含函數調用的復雜表達式)中各個變量的變化情況,單步執行就很難了。

因此,我們還是要有斷行,這樣可以得到如下的結構——格式B

if (condition)

????DoSomething();

else

????DoSomethingElse();

這樣的結構,由于沒有明確的“{”和“}”來判斷程序的結構,在有多層控制嵌套的時候,就不容易看清結構和對應關系。下面的改進(格式C)雖好,但是阿超認為還是不夠清晰:

if ( condition) {

????DoSomething();

} else {

????DoSomethingElse();

}

于是我們最后做了這個選擇,每個“{”和“}”都獨占一行。就是格式D

if ( condition)

{

????DoSomething();

}

else

{

????DoSomethingElse();

}

在一個函數體內,邏揖上密切相關的語句之間不加空行,其它地方應加空行分隔。

10.1.5??分行

不要把多行語句放在一行上。

a = 1; b = 2;???????????// bogus

if (fFoo) Bar();????????// bogus

更嚴格地說,不要把不同的變量定義在一行上。

Foo foo1, foo2;?????????// bogus

10.1.6??命名

阿超:我在某個同學的程序中看到有些變量叫“lili”,“yunyun”,不知道這些變量在現實生活中有沒有什么意義。

下面哄笑起來。

果凍:(紅著臉問)那有些變量的確想不出名字,簡單的變量像ijk都用完了,怎么辦?

阿超:當我們的程序比“Hello World”復雜10倍以上的時候,像給變量命名這樣簡單的事看起來也不那么簡單了。我們就來談談如何起名字這個問題。程序中的實體、變量是程序員晝思夜想的對象,要起一個好的名字才行。大家都知道用單個字母給有復雜語義的實體命名是不好的,目前最通用的,也是經過了實踐檢驗的方法叫“匈牙利命名法”。例如:

fFileExist,表明是一個bool值,表示文件是否存在;

szPath,表明是一個以0結束的字符串,表示一個路徑。

如此命名的目的是讓程序員一眼就能看出變量的類型,避免在使用中出錯。早期的計算機語言(如BCPL)不作類型檢查,在C語言中,intbytecharbool大概都是一回事。下面這一句話:

if (i)

從語義來說,i可以是表示真/假的一個值,也可以表示長度是否為零,

還可以表示是否到了字符串的結束位置,或者可以表示兩個字符串比較的結果不相等(strcmp()返回-101)。從程序的文字上,很難看出確切的語義。

同樣是字符串類型,char *BSTR的有些行為是很不一樣的。

HRESULT的值也可以用來表示真假,但是HR_TRUE == 0HR_FALSE ==1,這和通常的true/false剛好相反。

大部分的程序,錯就錯在這些地方!在變量面前加上有意義的前綴,就可以讓程序員一眼看出變量的類型及相應的語義。這就是“匈牙利命名法”的用處。

匈牙利命名法的一些通用規定,見本書附錄B(第337頁)。

還有一些地方不適合用“匈牙利命名法”,比如,在一些強類型的語言(如C#)中,不同類型的值是不能做運算的,對類型有嚴格的要求,例如C#?中,if()語句只能接受bool值的表達式,這樣就大大地防止了以上問題的發生。在這樣的語言中,前綴就不是很必要的,匈牙利命名法則不適用了。Microsoft .Net Framework就不主張用這樣的法則。

10.1.7??下劃線問題

下劃線用來分隔變量名字中的作用域標注和變量的語義,如:一個類型的成員變量通常用m_來表示。移山公司規定下劃線一般不用在其他方面。

10.1.8??大小寫問題

由多個單詞組成的變量名,如果全部都是小寫,很不易讀,一個簡單的解決方案就是用大小寫區分它們。

Pascal——所有單詞的第一個字母都大寫;

Camel——第一個單詞全部小寫,隨后單詞隨Pascal格式,這種方式也叫lowerCamel

一個通用的做法是:所有的類型//函數名都用Pascal形式,所有的變量都用Camel形式。

/類型/變量:名詞或組合名詞,如MemberProductInfo等。

函數則用動詞或動賓組合詞來表示,如get/set; RenderPage()

10.1.9??注釋

誰不會寫注釋?但是,需要注釋什么?

不要注釋程序是怎么工作的(How),你的程序本身就應該能說明這一問題。

//this loop starts the i from 0 to len, in each step, it

// does SomeThing

for (i = 0; i<len; i++)

{
?????????DoSomeThing();

}

以上的注釋是多余的。

注釋是用來解釋程序做什么(What),為什么這樣做(Why),以及要特別注意的地方的,如下:

//go thru the array, note the last element is at [len-1]

for (i = 0; i<len; i++)

{

????DoSomeThing();

}

復雜的注釋應該放在函數頭,很多函數頭的注釋都是解釋參數的類型等的,如果程序正文已經能夠說明參數的類型in/out等,就不要重復!

注釋也要隨著程序的修改而不斷更新,一個誤導的(Misleading)注釋往往比沒有注釋更糟糕。

另外,注釋(包括所有源代碼)應只用ASCII字符,不要用中文或其他特殊字符,它們會極大地影響程序的可移植性

在現代編程環境中,程序編輯器可以設置各種好看的字體,我們可以使用不同的顯示風格來表示程序的不同部分。

注意: 有些程序設計語言的教科書對于基本的語法有詳細的注釋, 那是為了教學的目的, 不宜在正式項目中也這么做。

?

下面的例子中,有很多注釋, 但是那些注釋是非常必要的呢? 哪些錯誤處理是多余的?

Protected Sub?txtSSN_TextChanged(ByVal?sender As Object,?ByVal?e As?System.EventArgs) Handles?txtSSN.TextChanged

Try??‘Provides error trapping

??'_______________________________________________________________________ '

??'?txtSSN_TextChanged

??‘?????Activated by entering SSN.

??'?????Transfer form value to local class variable. '_______________________________________________________________________ '

??' anOrder.SSN

??'?????Holds the SSN for processing in all forms '?txtSSN?' Form object that holds user entered SSN ' '_______________________________________________________________________ '

??anOrder.SSN =?txtSSN.Text

Catch ex As Exception ' Error trapping. '_______________________________________________________________________ ‘

?????' Output system error message to user on form under form title and

?????' send details to database

??'_______________________________________________________________________ '?subErrorReporting("txtSSN_TextChanged",?ex.Message)

?End Try

End Sub

?

10.2??代碼設計規范

代碼設計規范不光是程序書寫的格式問題,而且牽涉到程序設計、模塊之間的關系、設計模式等方方面面,這里有不少與具體程序設計語言息息相關的內容(如CC++JavaC#),但是也有通用的原則,這里主要討論通用的原則。如果你只想為了“爽”而寫程序,那么可以忽略下面的原則;如果你寫的程序會被很多人使用,并且你自己會加班Debug?你的程序,那最好還是遵守下面的規定。

10.2.1??函數

現代程序設計語言中的絕大部分功能,都在程序的函數(Function, Method)中實現,關于函數最重要的原則是:只做一件事,但是要做好。

10.2.2??goto

問:我們能不能用goto

答:函數最好有單一的出口,為了達到這一目的,可以使用goto。只要有助于程序邏輯的清晰體現,什么方法都可以使用,包括goto

如代碼清單10-2

代碼清單10-2

HRESULT??HrDoSomething(int parameter)

{

//parameter check and initialization

//processing part 1

If (SomeCode() != ok)
????{

????//set HR value
????????Goto Error;

}

//processing part 1

If (SomeCode() != ok)
????{

????//set HR value
????????Goto Error;

}

Error:

????//clean up
????return hr;

}

10.2.3??錯誤處理

80%的程序代碼,都是對各種已經發生和可能發生的錯誤的處理。

——阿超

如果錯誤會發生,那就讓程序死的地方離錯誤產生的地方越近越好。

——阿超

1.參數處理

DeBug版本中,所有的參數都要驗證其正確性。在正式版本中,從外部(用戶或別的模塊)傳遞過來的參數要驗證其正確性。

2.斷言

如何驗證正確性?那就要用Assert(斷言)。斷言和錯誤處理是什么關系?

當你覺得某事肯定如何,你可以用斷言。

Assert (p != NULL);

然后可以直接使用變量p;

如果你認為某事可能會發生,這時就要用錯誤處理。

如:

……

p = AllocateNewSpace(); // could fail

if (p == NULL)

{ // error handling.

}

else

{ // use p to do something

}

10.2.4??如何處理C++中的類

注意,除了關于異常(Exception)的部分,大部分其他原則對C#也適用。

1.類

1)使用類來封裝面向對象的概念和多態(Polymorphism)。

2)避免傳遞類型實體的值,應該用指針傳遞。換句話說,對于簡單的數據類型,沒有必要用類來實現。

3)對于有顯式的構造和析構函數,不要建立全局的實體,因為你不知道它們在何時創建和消除。

4)只有在必要的時候,才使用“類”。


2Class vs. Struct

如果只是數據的封裝,用Struct即可。

3.公共/保護/私有成員PublicPrivateProtected

按照這樣的次序來說明類中的成員:publicprotectedprivate

4.數據成員

1)數據類型的成員用m_name說明

2)不要使用公共的數據成員,要用inline訪問函數,這樣可同時兼顧封裝和效率。

5.虛函數Virtual Functions

1)使用虛函數來實現多態(Polymorphism)。

2)只有在非常必要的時候,才使用虛函數。

3)如果一個類型要實現多態,在基類(Base Class)中的析構函數應該是虛函數。

6.構造函數Constructors

1)不要在構造函數中做復雜的操作,簡單初始化所有數據成員即可。

2)構造函數不應該返回錯誤(事實上也無法返回)。把可能出錯的操作放到HrInit()FInit()中。

下面是一個例子(見代碼清單10-3):

代碼清單10-3

class Foo

{

public:

Foo(int cLines) { m_hwnd = NULL; m_cLines = cLines}

virtual ~Foo();

HRESULT HrInit();

void DoSomething();

private:

HWND m_hwnd;

int m_cLines;

};

7.析構函數

1)把所有的清理工作都放在析構函數中。如果有些資源在析構函數之前就釋放了,記住要重置這些成員為0NULL

2)析構函數也不應該出錯。

8NewDelete

1)如果可能,實現自己的New/Delete,這樣可以方便地加上自己的跟蹤和管理機制。自己的New/Delete可以包裝系統提供的New/Delete

2)檢查New的返回值。New不一定都成功。

3)釋放指針時不用檢查NULL

9.運算符(Operators

1)在理想狀態下,我們定義的類不需要自定義操作符。只有當操作符的確需要時。

2)運算符不要做標準語義之外的任何動作。例如,“==”的判斷不能改變被比較實體的狀態。

3)運算符的實現必須非常有效率,如果有復雜的操作,應定義一個單獨的函數。

4)當你拿不定主意的時候,用成員函數,不要用運算符。

10.異常(Exceptions

1)異常是在“異乎尋常”的情況下出現的,它的設置和處理都要花費“異乎尋常”的開銷,所以不要用異常作為邏輯控制來處理程序的主要流程。

2)了解異常及處理異常的花銷,在C++語言中,這是不可忽視的開銷。

3)當使用異常時,要注意在什么地方清理數據。

4)異常不能跨過DLL或進程的邊界來傳遞信息,所以異常不是萬能的。

11.類型繼承(Class Inheritance

1)當有必要的時候,才使用類型繼承。

2)用Const標注只讀的參數(參數指向的數據是只讀的,而不是參數本身)。

3)用Const標注不改變數據的函數。

10.3??代碼復審

阿超:代碼復審看什么?是不是把你的代碼拿給別人看就行了?

雜曰:1)別人根本就不懂,給他們講也是白講。

2)我是菜鳥,別的大牛能看得上我的代碼么?

3)也就是形式而已,說歸說,怎么做,還是我說了算。

代碼復審的正確定義:看代碼是否在“代碼規范”的框架內正確地解決了問題(見表10-1)。

10-1??復審的形式

??

??

??

自我復審

自己?vs.?自己

用同伴復審的標準來要求自己。不一定最有效,因為開發者對自己總是過于自信。如果能持之以恒,則對個人有很大好處

同伴復審

復審者?vs.?開發者

簡便易行

團隊復審

團隊?vs.?開發者

有比較嚴格的規定和流程,用于關鍵的代碼,以及復審后不再更新的代碼。

覆蓋率高——有很多雙眼睛盯著程序。但是有可能效率不高(全體人員都要到會)

軟件工程中最基本的復審手段,就是同伴復審。

誰來做代碼復審?即最有經驗,熟悉這一部分代碼的人。對于至關重要的代碼,我們要請不止一個人來做代碼復審。

復審的目的在于:

1)找出代碼的錯誤。如:

a.?編碼錯誤,比如一些能碰巧騙過編譯器的錯誤。

b.?不符合項目組的代碼規范的地方。

2)發現邏輯錯誤,程序可以編譯通過,但是代碼的邏輯是錯的。

3)發現算法錯誤,比如使用的算法不夠優化。

4)發現潛在的錯誤和回歸性錯誤——當前的修改導致以前修復的缺陷又重新出現。

5)發現可能改進的地方。

6)教育(互相教育)開發人員,傳授經驗,讓更多的成員熟悉項目各部分的代碼,同時熟悉和應用領域相關的實際知識。

10.3.1??為啥要做代碼復審

問:為什么非得做代碼復審不可?難道開發人員沒有能力寫出合格的代碼?既然你招我進了移山公司,就是相信我有這個能力,對不對?

答:首先,在代碼復審中發現的問題,絕大多數都可以由開發者獨立發現。從這一意義上說,復審者是在替開發者干開發者本應干的事情。

問:這么說如果開發者做到完美,復審者的時間和精力是一種浪費了?

答:不對,即使是完美,代碼復審還有“教育”和“傳播知識”的作用。更重要的是,不管多么厲害的開發者都會或多或少地犯一些錯誤,有欠考慮的地方,如果有問題的代碼已簽入到產品代碼中,再要把所有的問題找出來就更困難了。大家學習軟件工程都知道越是項目后期發現的問題,修復的代價越大。代碼復審正是要在早期發現,并修復這些問題。

另外,在代碼復審中的提問與回應能幫助團隊成員互相了解,就像練武之人互相觀摩點評一樣。在一個新成員加入一個團隊的時候,代碼復審能非常有效地幫助新成員了解團隊的開發策略、編程風格及工作流程。

問:新成員是否應該在完全掌握了這些方面之后再寫代碼?

答:理論上是如此。但是如果我們要“完全掌握”,可能需要比較長的時間,另外,如果不開發實際的軟件,這樣的“完全掌握”有意義么?還是在實際中學習吧。這也是“做中學”(Learning by Doing)思想的體現。

10.3.2??代碼復審的步驟

在復審前——

1)代碼必須成功地編譯,在所有要求的平臺上,同時要編譯DeBug| Retail版本。編譯要用團隊規定的最嚴格的編譯警告等級(例如C/C++中的W4)。

2)程序員必須測試過代碼。什么叫測試過?最好的方法是在DeBugger中單步執行。

問:有些錯誤處理的分支我不能執行到怎么辦?

答:如果你作為作者都不能讓程序執行到那里,那誰能保證這些錯誤處理的正確性呢?

同時也可以加上OutputDeBugString等輸出來監視程序的控制流。

3)程序員必須提供新的代碼,以及文件差異分析工具。WindiffVSTS自帶的工具都可以。VSTS中可以通過Shelveset來支持遠程代碼復審。

4)復審者可以選擇面對面的復審、獨立復審或其他方式。

5)在面對面的復審中,一般是開發者控制流程,講述修改的前因后果。但是復審者有權在任何時候打斷敘述,提出自己的意見。

6)復審者必須把反饋意見逐一提出。注意,復審者有權提出很多看似吹毛求疵的問題,復審者不必每一件事都要親自調查,開發者有義務給出詳盡的回答。例如:

復審者:你在這里申請了這個資源,你是如何保證它在所有路徑下都能正確釋放的?

開發者:這個……我要再檢查檢查。

或者——

開發者:這個是這樣保證的,我用了SmartPointer,然后這里有try/catch/ finally……

要記住復審者是通過問這些問題來確保軟件質量的,而不是有意找碴。

7)開發者必須負責讓所有的問題都得到滿意的解釋或解答,或者在TFS中創建新的工作項以確保這些問題將來會得到處理。例如:

復審者:這一段代碼可能會被多個線程調用,代碼是thread-safe么,我怎么沒有看到對共享資源的保護?

開發者:我一時得不出結論,讓我在TFS中開一個“任務”來跟蹤此事。

8)對于復審的結果,雙方必須達成一致的意見。

a.?打回去——復審發現致命問題,這些問題解決之前不能簽入代碼;

b.?有條件地同意——發現了一些小問題,在這些問題得到解決或記錄之后,代碼可以簽入,不需要再次復審;

c.?放行——代碼可以不加新的改動,簽入源碼控制服務器。

避免不必要的繁文縟節,我們做代碼復審的目的是為了減少錯誤的發生,而不是找一個人來對著你的代碼點頭。一些簡單的修改不是非得要一個復審者來走一遍形式。在項目開發的早期斤斤計較于一些細枝末節(例如:幫助文件里的拼寫錯誤,數據文件格式不夠最優化等)也是于大局無補的,但是,這些問題并不是不用處理了,我們必須建立一些優先級較低的工作項來跟蹤這些事情。

10.3.3??在代碼復審中還要做什么

好的復審者不光是要注意到程序員修改了什么,還要把眼光放遠,問一些這樣的問題:

“你這樣修改了之后,有沒有別的功能會受影響?”

“項目中還有別的地方需要類似的修改么?”

“有沒有留下足夠的說明,讓將來維護代碼時不會出現問題?”

“對于這樣的修改,有沒有別的成員需要告知?”

“導致問題的根本原因是什么?我們以后如何能自動避免這樣的情況再次出現?”

有些修改看似聰明有效率,但是這樣的修改有可能會讓以后的開發和維護更困難。


10.3.4??在代碼復審后要做什么

人不能兩次踏入同一條河流,程序員不能兩次犯同樣的錯誤。在代碼復審后,開發者應該把復審過程中的記錄整理出來:

1)更正明顯的錯誤。

2)對于無法很快更正的錯誤,要在TFS中創建Bug把它們記錄下來。

3)把所有的錯誤記在自己的一個“我常犯的錯誤”表中,作為以后自我復審的第一步。

有些人喜歡在程序中加一些特定的標記,來跟蹤各種“要做的事情”,例如:

//$todo:??make this function thread-safe

//$review: is this function thread-safe???Need to look at it again

//$bug: when input array is very large, this function might lead //to crash

這些標記最好是加上人名,以示負責。如:

//$bug (AChao): when input array is very large, this function will //???become very slow due to O(N*N) algorithm

在代碼復審過程中,$review標記的問題要一一討論,在代碼復審過后,所有的$review標記要清除。在一個里程碑或正式版本發布之前,所有的$todo:$bug:標記都要清除。

做標記是不錯的辦法,但是如果開發者光記得做標記,最后卻沒有真正去研究和改正這些潛在的問題,這些todoreviewBug就會被遺棄在代碼中。過了一段時間后,后來的程序員也不敢碰它們——因為沒有人能真正了解上一個版本的$todo是真的要馬上做,還是已經做過了(done)了,只是沒有更新$todo的注釋,或者問題早已通過別的方式解決了。其根本原因在于團隊沒有用TFS(或者其他的管理軟件)進行記錄,沒有人會跟蹤這些事情。

10.3.5??代碼復審的核查表

下面是移山公司總結的代碼復審核查表,我們可以在復審中使用,也可以加上自己認為重要的注意事項。

?

1.概要部分

1)代碼能符合需求和規格說明么?

2)代碼設計是否有周全的考慮?

3)代碼可讀性如何?

4)代碼容易維護么?

5)代碼的每一行都執行并檢查過了嗎?

2.設計規范部分

1)設計是否遵從已知的設計模式或項目中常用的模式?

2)有沒有硬編碼或字符串/數字等存在?

3)代碼有沒有依賴于某一平臺,是否會影響將來的移植(如Win32Win64)?

4)開發者新寫的代碼能否用已有的Library/SDK/Framework中的功能實現?在本項目中是否存在類似的功能可以調用而不用全部重新實現?

5)有沒有無用的代碼可以清除?(很多人想保留盡可能多的代碼,因為以后可能會用上,這樣導致程序文件中有很多注釋掉的代碼,這些代碼都可以刪除,因為源代碼控制已經保存了原來的老代碼。)

3.代碼規范部分

1)修改的部分符合代碼標準和風格么(詳細條文略)?

4.具體代碼部分

1)有沒有對錯誤進行處理?對于調用的外部函數,是否檢查了返回值或處理了異常?

2)參數傳遞有無錯誤,字符串的長度是字節的長度還是字符(可能是單/雙字節)的長度,是以0開始計數還是以1開始計數?

3)邊界條件是如何處理的?Switch語句的Default是如何處理的?循環有沒有可能出現死循環?

4)有沒有使用斷言(Assert)來保證我們認為不變的條件真的滿足?

5)對資源的利用,是在哪里申請,在哪里釋放的?有沒有可能導致資源泄露(內存、文件、各種GUI資源、數據庫訪問的連接,等等)?有沒有可能優化?

6)數據結構中是否有無用的元素?

5.效能

1)代碼的效能(Performance)如何?最壞的情況是怎樣的?

2)代碼中,特別是循環中是否有明顯可優化的部分(C++中反復創建類,C#?string?的操作是否能用StringBuilder?來優化)?

3)對于系統和網絡調用是否會超時?如何處理?

6.可讀性

代碼可讀性如何?有沒有足夠的注釋?

7.可測試性

代碼是否需要更新或創建新的單元測試?

還可以有針對特定領域開發(如數據庫、網頁、多線程等)的核查表。

10.4??本章討論

九條:哇,這么多酷的C++?功能都不能用,那我們還學什么C++,為了迎接考試,我都把Operator OverloadPolymorphism背得滾瓜爛熟了,為什么不讓我用?

阿超:我們寫程序是為了解決問題,不是“為賦新詞強說愁”,這些高級的語言特性,不是不讓用,而是要用得慎重,不要動不動就寫三五個類,一個套一個,要把注意力集中在能否用簡潔的方法解決問題上來。

荔荔:這么多規范,我不知道怎么寫第一行程序了。

二柱:自我復審也很重要——把代碼擺在面前,當作是別的菜鳥寫的。把你通常問別人的,以及別人會問你的問題都自己問一遍。這樣就能發現不少問題。

九條:如果開發者很厲害,那么復審者就沒有什么作用,也許這些復審都是走過場?

小飛:笑話,同理可以推論,如果開發者很厲害,那么測試人員也沒什么作用,也是走過場,干脆把他們送回家得了。

荔荔給阿毛講自己剛寫好的代碼,阿毛對于這個代碼要解決的問題還沒有什么了解,荔荔說什么,阿毛就“啊,啊”地附和。最后,阿毛也提不出什么意見,荔荔倒是在自己描述的過程中發現了一些問題。

阿毛:這樣的代碼復審有用么?

阿超:還是有一點用處,至少確保代碼的作者把代碼的邏輯和思想系統地表達了一遍,這樣做本身就能發現不少問題。

?

問:數據庫的代碼有沒有規范?

答:有,見本書附錄B(第337頁)。

?

問: 這些規范啊, 建議啊, 都是細枝末節的東西, 我們要做世界級的軟件,搞這些東西是不是太小家子氣了?

答: 首先世界級的軟件也會因為小小的紕漏而導致世界級的問題 - 例如一段時間以來我們常常聽到的安全漏洞和緊急補丁。 其次,軟件的開發是一個社會性的活動, 有它的規律。 其中一個規律就是 “破窗效應” (參見?broken windows theory),如果團隊成員看到同伴們連一些細小的規范都不遵守, 那自己還要嚴格執行單元測試么?? 另一個成員看到這個模塊連單元測試都沒有, 那他自己也隨意修改算了。。。? 這樣下去, 整個軟件的質量可想而知。

?



[1]?來源于某次微軟俱樂部程序競賽,略有修改。


總結

以上是生活随笔為你收集整理的现代软件工程讲义 3 代码规范与代码复审的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。