Jan 08 2008
Code Complete, Second Edition

書名:Code Complete, Second Edition
作者:Steve McConnell
譯者:譚詠歸
出版:Microsoft Press; 2nd edition (June, 2004) / 學貫
語言:英文版 / 繁體中文版
Code Complete 是一本很不可思議的好書。書中的內容,沒有模糊不清的理論,而是立即可運用在現行專案或程式中的各種技術。有太多太多的實用知識,完整詳細地解答了我長久以來的疑惑與困擾。
軟體的開發,存在許多不同的階段 (Phase) 與面向,Code Complete 的主要內容,是著重於軟體開發的建構 (Construction) 階段。Construction 一般常會被認為是進行 Coding 或 Programming 的階段;但是在這個階段中,其實還包含了架構設計、細節設計、建構規劃、單元測試等等許多不同的活動程序。
書中的內容從軟體建構的定義開始介紹,從 High-Level 的角度論述「設計」在建構階段中所扮演的角色,與實際可用的設計程序。接著每個章節探討一個主題,由最常見的 Class 與 Routine 設計與實做層面開始,逐步論述各種設計與實做上的考量。而後又討論了 Defensive Programming 與 Pseudocode Programming Process 兩個相當有用的設計方法。
接續的章節往 Low-Level 的建構層面邁進,先以程式中最基本的組成元素,變數的使用開始論述,包括變數的一般使用原則、變數命名、一般資料型態,與非尋常資料型態的變數。變數的設計與使用,經常容易被忽略或是獲得比較少的注意,但是對於一個程式的優劣勝敗來說,變數絕對是具有相當程度的影響力。接著介紹程式中很重要的控制元素,也就是各種控制結構的使用。從直述式結構、條件式結構、迴圈式結構開始,再接續討論非尋常的控制結構、表格驅動方法,與結構式程式設計的一般性原則。結構式程式設計主要的立論在於,無論任何的控制流程,都應該能夠從 Sequence、Selection 與 Iteration 三種架構所建構出來。
接續的章節,再重新回到 High-Level 的觀點, 闡述軟體品質的特徵、專案大小的取捨、建構階段的管理、整合技術,如何深遠地影響到整個專案的運作,與進一步的建構階段。然後是 Developer Testing、Debugging、Refactoring,以及常被過度強調的 Code Tuning 考量與技術。還有一個章節討論較為少見的協同式建構 (Collaborative Construction) 流程。到了書中的最後一個部分,討論的則是比較屬於心理層面的主題,包括很重要也很具爭議性的程式寫作風格與版面配置,以及如何達成不說自明 (Self-Documenting) 的程式碼。最有意思的部分,是書中的最後兩個章節,分別討論了個人特質對於程式建構的影響,與整本書總結整理的部分。
貫穿全書的重要理念主要有以下幾點:
- 克服複雜度:
軟體設計與建構的一個主要目標,就是克服複雜度。 許多程式設計實例背後的動機,都是為了能夠降低程式的複雜度。而降低複雜度,可以說是成為一個有效率的程式設計師,最重要的關鍵。大部分人的思考容量是有限制的,所以我們應該盡力最小化,一個人在同一時間內,需要思考的程式數量。可以說所有軟體設計技術的目標,都是在於將一個複雜的問題,分解成許多簡單的部分。
一個專案的失敗,通常可能是導因自不良的需求、不良的計畫、不良的管理等等因素。但是如果失敗的原因主要是來自技術面的話,那麼這個原因通常是「未被控制的複雜度」(Uncontrolled Complexity)。因此,盡力控制複雜度 (Manage Complexity),可說是在軟體開發中最重要的一項議題。
而一個測量程式複雜度 (Programming Complexity) 的方法,就是你為了瞭解一個程式,而必須在同一時間之內,保持在心裡思考的物件的總數。這種「心智把戲」(Mental Juggling) 的行為,就是程式設計最困難的面向之一,也是程式設計為何需要比其他活動更多專注力的理由之一。有兩個辦法可以對付複雜度: 其一就是藉由更多的「心智練習」以增進操弄心智把戲的能力,然而程式寫作本身就是一件足夠的心智練習,因此能增進的幅度相當有限。其二是降低程式的複雜度,以及為了瞭解它所需要付出的專注力。
根據 Edsger Dijkstra 的論述:大多數的程式設計,都是意圖補償人類極為有限的腦容量。程式設計最佳的人,是那些瞭解他們自己的腦袋有多小的人。他們是謙遜的。學習越多以彌補不足的腦袋容量的人,就會成為越好的程式設計師。越是謙遜的人,越能夠快速的增進。
『Good programmers are humble.』
- 程序 (Process) 的重要性:
在一個小型的專案中,個別程式設計師的才能,是影響軟體品質的最大因素,其中某部分的成功因素,可以歸功於個人選擇使用的程序。然而在比較大型的專案中,相較於個人的技能來說,組織化的特徵程序能夠帶來更大的影響。
即使是一個很好的團隊,他們所能夠貢獻的能力,並不是單純所有個人能力的加總而已。人們在一起工作的方法,會決定他們的能力是有相加的效果,或是相減的效果。程序之所以對於軟體開發很重要的原因,在於品質必須要從軟體專案的第一步就建構於其中。
- 程式撰寫考量的出發點,應該以「人」而非「電腦」做為第一優先考量:
程式碼在很多情況下都會被閱讀,無論是自己或其他人,在修改、除錯、維護的時候,都會需要閱讀程式碼。所以想盡各種辦法,使用各種技術,使程式碼具備可讀性、易讀性是很重要的主題。你應該要花費心力在撰寫良好的程式碼上,以致於你可以只做一次,而非需要重複又重複地閱讀差勁的程式碼。
沒有一個單一技術的應用,可以區別出一個易讀的程式或不易讀的程式,但是由許多小部分閱讀性的改進,能夠累積出重要而可觀的成效。程式設計中,較少部分的工作,是為了撰寫程式讓電腦能夠閱讀它;而較多部分的工作,是在於使得其他的人類能夠閱讀它。因此,程式設計師在撰寫程式的時候,應該要偏好「閱讀時的便利性」,而非「撰寫時的便利性」。
『Any fool can write code that a computer can understand. Good programmers write code that humans can understand.』
- 迭代 (Iterate)、重複:
「設計」是一個奇特的問題 (Design is a wicked problem)。奇特問題 (Wicked Problem) 是指,唯有當這個問題被解決之時,才有辦法清楚的對它做出定義。聽起來像是似是而非的矛盾一樣,而「設計」正是屬於這種類型的奇特問題。設計不會是一開始就如泉湧般直接而完整呈現的,通常會經過許多重複檢視、討論、實做程式碼的經驗後,而逐漸演化與改進的。因此,所謂的設計,其實是一種迭代的過程。
單次的設計通常無法達到最理想的結果;設計本身就是一個不斷反覆琢磨的程序。使用某個方法解決了問題之後,往往可以對這個問題本身獲得更好、更深入的洞察力,可以使我們學習到解決這個問題,更好、更適切的方法。 所以我們可以說,設計本身是一種啟發探索性 (Heuristic) 的程序,而非決定論 (Deterministic) 的程序。這一點,對於軟體專案來說亦然。
最後,作者提到相當重要的一點,就是必須將各種書中的技術視為工具箱中的工具,然後使用自己的判斷,選出適合進行各項工作的工具。這本書裡討論了很多好的程式實例,但不是意指需要拿來當作嚴格遵行的一組標準;而是使用這本書當作討論的基礎,當作良好程式實例的資料全集,以確認出對自己專案最有利的程式實例。
多數的程式設計書籍,都是教導「如何把程式寫好」,然而卻僅有少之又少的書籍教導「如何寫出好程式」。這不是文字上的把戲,而是根本上的不同立足點。一本普通的 C++ 書籍,會教導讀者虛擬與多型的使用語法;一本優秀的 C++ 書籍,會教導讀者虛擬與多型的使用語意;更深入的書籍,或許會教導讀者虛擬與多型背後的設計思維與實做細節。然而,卻鮮少有書籍教導其合適的使用時機,並且能夠和其他可選擇的做法,做優缺點的比較。
什麼樣的情境下使用 Inheritance 會比 Containment 好?到底應該使用繼承類別以達成 Virtual Function 的效用,還是使用 Function Pointer,還是簡單的 Case-Switch?要傳入單一個物件當作參數,還是傳入多個一般資料型態變數當作參數比較合適?要使用深層的巢狀控制結構,還是使用其他控制結構減少巢狀層數?什麼樣的程式才叫做最佳化?怎麼樣才能有效的運用 80/20 法則於最佳化的程序中?還有更多更多可能你我都曾經在腦袋中一閃而過的疑慮。
如果,這本書不能夠提供一個令所有人滿意而一致認同的解答,至少它能夠成為一個驅動思考的啟發點。
Code Complete 目前也有繁體中文版本囉!書名是軟體建構之道。如果你平時的工作非常忙碌,沒有太多時間可以閱讀書籍,一年只能選擇一本書來讀的話,我誠心誠意百分百推薦這本!即使是在兩年多前就閱讀過這本書,現在偶爾拿出當時所做的筆記與摘錄翻閱,仍然能夠從中獲得不少煥然一新的思考啟發與心得印證,絕對是一本值得一讀再讀的好書!
