在上一回中,我們談到了軟體開發工具所提供的自動化,對程式設計者所帶來的幫助。而軟體程式的開發,從最早完全倚靠程式設計者腦力的模式,漸漸地,因為有了這些自動化的工具做為輔助,讓程式設計者少掉了不少負擔,也大大提升了開發的生產力。

為了軟體開發所衍生出來的自動化工具,也已經涵蓋了各種不同的面向、提供不同的作用。除了有不少工具是用來輔助產出程式碼,或是提供更高階的語義以便利程式的撰寫之外,也有一些工具著眼在協助程式設計者提升程式碼品質的。這些自動化工具的目的,並不在於更自動化地產出程式碼,而是針對已經撰寫完成的程式碼進行檢核,找出其中可能存在的品質問題,進而協助程式設計者修正。

利用工具分析程式碼
關於程式碼的品質,其實是一個很複雜的議題,因為程式碼的品質並不是一個容易量化的概念。什麼是品質好?什麼是品質不好?我們沒有辦法很簡單的定量數字來加以表示。另一方面,針對不同的需求,品質的意義也會有所不同。

即使如此,要描述出一些我們所認為不好的程式碼可能具備的特性及規則,還是有辦法的。倘若,我們能夠利用自動化的工具分析程式碼,了解是否具備這些不好的特性,那麼,所分析出來的結果,就能夠做為程式設計者改善程式碼的參考依據。

事實上,現在也的確有不少工具,能夠針對你所寫下的程式碼進行分析、找出其中存在的潛在問題供你參考,甚至自動幫你修正問題。

當前工具軟體分析程式碼的方式
針對程式進行分析的方式,一般來說可以區分為兩類,一類稱為「靜態分析」,而另一類則稱為「動態分析」。

所謂的「靜態分析」,便是在不實際執行程式的情況下,單純就程式碼的內容進行分析。這種方式,僅能分析到程式碼「靜態」的特性。相反的,「動態分析」便是實際將程式碼運行起來同時分析。這種方式,可以收集到程式在執行期的行為及資訊以進行分析。

這兩種方式各有優缺點。靜態分析的工具運作方式簡單,只需要針對程式碼(有可能是編譯好的執行碼或未編譯的原始碼)進行分析,適用於找出程式碼本身即能顯露出的問題。但是,針對那些必須實際運行程式,才有辦法偵測出來的問題,就無法倚靠靜態分析的工具找尋出來。例如,像記憶體的洩露問題(memory leak),或是非法的記憶體存取操作,都無法透過靜態分析的工具找到。

相反的,使用動態分析的工具,因為能夠收集到程式在執行期運行的諸般資訊。但是,為了盡可能涵蓋到最多的程式碼執行範圍(也就是盡可能多的執行路徑),必須設計涵蓋率高的測試案例,因為,進行動態分析時,通常會依照設計好的測試案例來執行程式。這麼一來,測試案例的品質,也就和動態分析結果的好壞息息相關了。

靜態分析擅長之處
因為靜態分析和動態分析各有其優缺點、也各具特質,它們分別適用的應用領域也不盡相同。這一次,讓我們先來談談程式原始碼的靜態分析吧。

統一排版規則及命名慣例
當我們撰寫完程式後,單從原始碼本身,就足以分析出不少攸關程式碼品質的資訊。

舉個最簡單的例子來說──程式碼的排版規則及命名慣例。很多開發團隊都會規範撰寫程式碼時的排版規則及命名慣例,無疑地,同一個開發團隊最好使用同一個排版規則及命名慣例。但是,怎麼確保這件事呢?傳統上,除了開發成員的自我約束之外,我們可能會透過程式碼審閱(code review)的活動來找出不符合排版規則,或是命名慣例的程式碼。然而,透過人工的方式來審核這樣的事情,不僅浪費時間、也浪費人力。而程式碼是否符合排版規則及命名慣例,卻是可以輕易透過對程式碼的靜態分析,來做判斷。

重構
除了簡單的排版規則及命名慣例的檢查之外,程式碼的靜態分析也可以協助我們分析更進階類型的品質特性。例如,最近幾年「重構(refactoring)」的方法頗為風行,許多程式設計者都採用重構的方法,來持續改善他們程式的品質。

重構方法的基本觀念,便是有一些所謂「程式碼的壞味道」,每一種壞味道的特性及結構都不盡相同,但都意謂著程式碼品質上的潛在問題。基本上,重構的方法列出了每一種壞味道的特性及結構,告訴你如何判斷各種壞味道。除此之外,重構方法也告訴你如何調整程式碼,來消除每一種壞味道。

在重構方法被發明出來之初,是倚靠程式設計者自己的力量來聞出程式碼的壞味道,接著也靠設計者自己來予以消除。但這需要重構的壞味道,既然在程式原始碼中有既定的規則,那麼,自然而然,便有機會可以利用針對程式碼的靜態分析工具,來加以判斷,甚至加以消除。

現在,也有為數不少的自動化重構工具問世。有了這些工具之後,程式設計者不旦不需憑藉著自己的力量,來嗅出程式碼中的壞味道,也不需要在聞出壞味道後,自己手動來加以消除。透過自動化的重構工具,能夠在極短時間內就偵測出劣化的程式碼,而且在消除過程中,不會犯下人工所會犯下的錯誤,可以確保解決問題時的正確性。

有了自動化的重構工具,對於倚賴重構方法的開發團隊來說,可以說是提供了極佳的便利性。原先必須花在重構過程的時間及人力成本,都獲得相當多的節省。這讓採用諸如極限編程之類開發方法的敏捷開發團隊,在開發速度上更快。因此,自動化的工具,讓他們更可以實現時時刻刻都可以進行重構的目標。

Debug
除此之外,靜態分析也有助於找出暗藏的程式碼臭蟲。例如,對C/C++來說,程式設計者有時候可能會在未初始化某一變數的情況下,進而使用該變數。此時,因為該變數從未指派過任何值,因此,其值可能為任意的可能值。這種臭蟲有時十分難找,為什麼呢?

有時候,這未經被初始化過後的變數,在特定的機器執行時(例如撰寫者自己的機器上),因為記憶體中的值大致相同,即使該變數未經初始化,但仍有可能是不會造成錯誤的值,而且,即使反覆執行,結果仍舊相同。但是,若是同樣的程式搬到另一部機器,甚至換另一種編譯模式(例如,從除錯模式改為釋出模式),問題就會發生。

這種難以重現、甚至在開發者自己的機器上無法重現的問題,可以說是相當難以查覺。

正如你所知道的,後繼的Java改良了這個問題,但對C/C++的程式設計者來說,這也不打緊。憑藉著自動化的分析工具,在靜態時期就能找出這種未經初始化卻加以使用的變數。這當然有助於發掘潛在可能會有的臭蟲。此外,像是將指向區域變數的指標做為函式的回傳值之類的問題,都是可以透過程式碼的靜態分析偵測出來的。

像上述所提到的這些影響程式碼品質的問題,都是在原始碼層次上,就具有既定的模式及規則,所以,它們都可以透過靜態分析來加以察覺。自動化的靜態分析,便可以做為一個有效的工具,來協助我們改善程式碼的品質。

 

專欄作者

熱門新聞

Advertisement