03三思而後行:前期準備
1. 軟件開發食物鏈:程序員是軟件食物鏈的最後一環。架構師吃掉需求,設計師吃掉架構,而程序員則消化設計。
2. 需求變更
? “一旦客戶接受了一份需求文檔,就再也不做更改”是一個美好的願望。然而,對一個典型的項目來說,在編寫代碼之前,客戶無法可靠地描述他們想要的是什麽。問題並不在於客戶是低級生物。就如同你做這個項目的時間越長,對這個項目的理解也就越深入一樣,客戶參與項目的時間越長,他們對項目的理解也就越深入。開發過程能夠幫助客戶更好地理解自己的需求,這是需求變更的主要來源。
3. 程序組織
? 在架構中,你應該能發現對那些曾經考慮過的最終組織結構的替代方案的記敘,找到之所以選用最終的組織結構,而不用其他替代方案的理由。有一份 對設計實踐的綜述認為,“維護‘設計緣由’”至少與“維護設計本身”一樣重要。
? 應該明確定義各個構造快的責任。每個構造快應該負責某一個區域的事情,並且對其他構造塊負責的區域知道的越少越好。通過使各個構造快對其他構造塊的了解達到最小,你能將設計的信息局限於各個構造塊之內。應該明確定義每個構造塊的通訊規則。對於每個構造塊,架構應該描述他能直接使用那些構造塊,能間接使用那些構造塊,不能使用那些構造塊。
4. 主要的類
? 架構應該詳細定義所用的主要的類。它應該指出每個主要的類的責任,以及該類如何與 其他類交互。它應該包含對類的集成體系、狀態轉換、對象持久化等的描述。
? 架構應該記敘曾經考慮過的其他類設計方案,並給出選用當前的組織結構的理由。架構無需詳細說明系統中的每一個類。瞄準80/20法則:對那些構成系統80%的行為的20%的類進行詳細說明。
5. 數據設計
? 架構應該描述所用到的主要文件和數據表的設計。它 應該描述曾經考慮過的其他方案,並說明做出選擇的理由。在構建期間,這些信息能讓你洞察架構師的思想。在維護階段,這種洞察力是無價之寶。離開它,你就就像看一部沒有字幕的外語片。
? 數據通常只應該由一個子系統或一個類直接訪問。架構應該詳細定義所用數據庫的高層組織結構和內容。架構應該解釋為什麽單個數據庫比多個數據庫要好,解釋為什麽不用平坦的文件而要用數據庫。
6.用戶界面設計
? 用戶界面常常在需求階段進行詳細說明。如果沒有,就應該在軟件架構中進行詳細說明。架構應該詳細定義Web頁面格式、GUI、命令行接口等主要元素。精心設計的用戶界面架構決定了最終做出來的時“人見人愛的程序”還是“沒人愛用的程序”。
? 架構應該模塊化,以便在替換為新用戶界面時不影響業務規則和程序的輸出部分。例如,架構應該使我們很容易地做到:砍掉交互式界面的類,插入一組命令行的類。這種替換能力常常很有用,尤其因為命令行界面便於單元級別和子系統級別的軟件測試。
7. 資源管理
? 架構應該描述一份管理稀缺資源的計劃。稀缺資源包括數據庫連接、線程、句柄等。在內存受限的應用領域,如驅動程序開發和嵌入式系統中,內存管理是架構應該認真對待的另一個重要領域。架構應該估算在正常情況和極端情況下的資源管理使用量。在簡單的情況下,估算數據應該說明:預期的實現環境有能力所提供的資源。在更復雜的情況中,也許會要求應用程序更主動地管理器擁有的資源。如果這樣,那麽“資源管理器”應該和系統的其他部分一樣進行認真的架構設計。
8. 可伸縮性
? 可伸縮性是指系統增長以滿足未來需求的能力。架構應該描述系統如何應對用戶數量、服務器數量、網絡節點數量、數據庫記錄數、數據庫記錄的長度、交易量等的增長。如果預計系統不會增長,而且可伸縮性不是問題,那麽架構應該明確地列出這一假設。
9.錯誤處理
? 錯誤處理已被證實為現代計算機科學中最棘手的問題之一,你不能武斷地處理它。有人估計程序中高達90%的代碼用來處理異常情況、進行錯誤處理、或作簿記工作。既然這麽多代碼致力於處理錯誤,那麽在架構中就應該清楚地說明一種“一致的地處理錯誤”的策略。
? 錯誤處理常被視為是“代碼約定層次”的事情——如果真有人註意它的話。但是因為錯誤處理牽連到整個系統,因此最好在架構層次上對待它。下面是一些需要考慮的問題。
錯誤處理是進行糾正還是僅僅進行檢測?如果是糾正,程序可以嘗試從錯誤中恢復過來。如果僅僅是檢測,那麽程序可以像“沒有發生任何事”一樣繼續運行,也可以退出。無論哪一種情況,都應該通知用戶說檢測到一個錯誤。
錯誤檢測是主動還是被動?系統可以主動地預測錯誤——例如,通過檢查用戶輸入的有效性——也可以在不能避免錯誤的時候,被動地響應錯誤——例如,當用戶輸入的組合產生了一個數值溢出的錯誤時。前者可以掃清障礙,後者可以清除混亂。同樣,無論采用哪種方案,都與用戶界面有影響。
程序如何傳播錯誤?程序一旦檢測到錯誤,它可以立即丟棄引發該錯誤的數據;也可以把這個錯誤當成一個錯誤,並進入錯誤處理狀態;或者可等到所有處理完成,再通知用戶說在某個地方發現了錯誤。
錯誤消息的處理有什麽約定?如果架構沒有詳細定義一個一致的處理策略,那用戶界面看起來就像“令人困惑的亂七八糟的抽象拼貼畫”,由程序的不同部分的各種界面拼接而成。要避免這種外觀體驗,架構應該建立一套有關錯誤消息的約定。
如何處理異常?架構應該規定代碼何時能夠拋出異常,在什麽地方捕獲異常,如何記錄這些異常,以及如何在文檔中描述異常,等等。
在程序中,在什麽層次上處理錯誤?你可以在發現錯誤的地方處理,可以將錯誤傳遞到專門處理錯誤的類進行處理,或者沿著函數調用鏈往上傳遞錯誤。
每個類在驗證其輸入數據的有效性方面需要負何種責任?是每個類負責驗證自己的數據的有效性,還是有一組類負責驗證整個系統的數據的有效性?某個層次上的類是否能假設它接收的數據是幹凈的。
你是希望用運行環境中內建的錯誤處理機制,還是想建立自己的一套機制?事實上,運行環境所擁有的某種特定的錯誤處理方法,並不一定是符合你的需求的最佳方法。
10.容錯性
? 架構還應該詳細定義所期望的容錯種類。容錯是增強系統可靠性的一組技術,包括檢測錯誤;如果可能的話從錯誤中恢復;如果不能從錯誤中恢復,則包容其不利影響。
? 舉個例子:為了計算某數的平方根,系統的容錯策略有一下幾種。
系統在檢測到錯誤的時候退回去,再試一次。如果第一次的結果是錯誤的,那麽系統可以退回到之前一切正常的時刻,然後從該點繼續運行。
系統擁有一套輔助代碼,以備在主代碼吹次的時候使用。在本例中,如果發現第一次的答案似乎有錯,系統就切換到另一個計算平方根的子程序,以取而代之。
系統使用一種表決算法。它可以有三個計算平方根的類,每一個都使用不同的計算方法。每個類都計算平方根,然後系統對結果進行比較。根據系統內建的容錯機制的種類,系統可以以三個結果的均值、中值或眾數作為最終結果。
系統使用某個不會對系統其余部分產生危害的虛假值代替這個錯誤的值。
其他容錯方法包括,在遇到錯誤的時候,讓系統轉入某種“部分運轉”的狀態,或者轉入某種“功能退化”的狀態。系統可以自動關閉或重啟。
03三思而後行:前期準備