第 21 章 決定什麼是重要的
良好軟體設計最重要的要素之一,是區分什麼重要、什麼不重要。應圍繞重要的事情設計軟體系統,儘量減少那些沒那麼重要的事情對系統其餘部分的影響。重要的事情應加以強調,讓人更容易注意到;不重要的事情則應儘可能隱藏起來。
本章概覽怎樣分清什麼重要、什麼不重要?
前面章節中的許多想法,核心都是區分什麼重要、什麼不重要。設計抽象就是如此:模組介面反映對使用者重要的資訊,而對使用者不重要的資訊應隱藏在實作中,不讓它們顯露在外。選擇變數名時,要挑出最能傳達變數資訊的幾個單字來組成名稱;這些單字表達的正是變數最重要的方面。如果效能對一個模組確實重要,就應圍繞效能目標來設計模組。在第 20.4 節的例子中,設計既要儘量減少效能關鍵路徑上的方法呼叫和特殊情況檢查,又要保持整潔、簡單、易理解。
21.1 如何決定什麼是重要的?
有時,系統的外部約束決定了什麼重要,比如第 20.4 節中的效能要求。更多時候,需要設計者自己判斷什麼重要。即使存在外部約束,設計者也必須弄清楚,要滿足這些約束,最重要的是什麼。
要決定什麼重要,可以看哪些做法能帶來更廣泛的收益:解決一個問題的同時,也能解決許多其他問題;或者掌握一條資訊,就更容易理解許多其他事情。例如,在第 6.2 節關於文字儲存的討論中,用於插入和刪除一段字元的通用介面可以解決許多問題,而 backspace 這樣的專用方法只能解決單個問題。通用介面能解決的問題更多。在文字類介面這一層,是否為響應退格鍵而呼叫介面並不重要,真正重要的只是需要刪除文字。不變條件也能帶來類似的收益:一旦瞭解變數或結構的不變條件,就可以預測它在多種情況下的行為。
有多個備選方案時,更容易判斷什麼最重要。例如,選擇變數名時,先在腦中列出與變數相關的單字,再挑出最能傳達資訊的幾個,用它們組成變數名。這就是“設計兩次”原則的一個例子。
有時很難看出什麼最重要,經驗不足的年輕開發人員尤其容易遇到這種困難。這時,我建議先提出一個假設:“我認為這是最重要的事情。”然後據此構建系統,看看實際效果如何。如果假設正確,就想想為什麼正確,當時有哪些線索可以供今後參考。如果假設錯誤,也沒關係:想想為什麼會錯,當時是否有線索能幫助你避免這個選擇。無論結果如何,你都能從經驗中學習,逐漸做出更好的選擇。
21.2 最小化重要的事情
儘量減少需要關注的事情,系統就會更簡單。例如,儘量減少構造物件時必須指定的參數數量,或提供符合最常見用法的預設值。對於確實重要的事情,也要儘量減少需要考慮它們的地方。模組內部隱藏的資訊,模組外的程式碼不必關心。如果例外能在系統較低層級完全處理,系統其餘部分就不必關心它。如果設定參數能根據系統行為自動計算出來,而不必提供給管理員手動設定,管理員也就無需關注它。
21.3 如何強調重要的事情
確定了什麼重要,就應在設計中加以強調。一種方法是讓它更醒目:重要的事情應出現在容易被看到的地方,例如介面文件、名稱,或經常使用的方法的參數中。另一種方法是重複,讓關鍵思想反覆出現。第三種方法是賦予它核心地位:最重要的事情應處於系統核心,決定周圍部分的結構。例如,作業系統的裝置驅動程式介面就處於核心地位,因為成百上千個驅動程式都依賴它。
當然,反過來也成立:如果一個想法容易被看到、反覆出現,或對系統結構有顯著影響,那麼它就是重要的。
同樣,不重要的事情應淡化處理。應儘可能將它們隱藏起來,不讓開發人員頻繁接觸,也不讓它們影響系統結構。
21.4 常見的錯誤
判斷什麼重要時,可能犯兩類錯誤。第一類是把太多事情視為重要。這樣,不重要的事情就會干擾設計,增加複雜性和認知負荷。例如,方法中的一些參數與大多數呼叫者無關。另一個例子是第 4.7 節討論的 Java I/O 介面:它迫使開發人員關注緩衝與非緩衝 I/O 的區別,而這種區別幾乎從來都不重要(開發人員幾乎總是需要緩衝,不想浪費時間顯式請求它)。把太多事情視為重要,往往會導致淺類。
第二類錯誤是未能認識到某件事的重要性。這會導致重要資訊被隱藏,或重要功能沒有提供,開發人員只能反覆實作這些功能。這類錯誤會降低開發效率,並導致“未知的未知”問題。
譯者圖解隱藏什麼,必須先問誰需要知道
21.5 開啟思路
關注最重要的事情,這個想法也適用於軟體設計之外的其他領域。在技術寫作中,使文件易於閱讀的最佳方法,是在開頭明確幾個關鍵概念,再圍繞它們組織其餘內容。討論系統細節時,將細節與整體概念聯絡起來,也有助於理解。
關注重要的事情也是一種很好的生活哲學:確定對你最重要的幾件事,儘可能把精力放在這些事情上。不要把時間都浪費在你認為既不重要、也無益的事情上。
“好品味”指的是區分什麼重要、什麼不重要的能力。良好的品味是優秀軟體設計師的重要素質之一。