《代码大全2》第3章 三思而后行,前期准备
目錄
前言
本章主題
3.1 前期準備的重要性
3.1.1 處于不同階段強調質量
3.1.2 前期準備對”構建活動“的影響
3.1.3 準備不周全的誘因
3.1.4 我理解的準備周全(純屬個人理解)
3.2 辨明你所從事的軟件的類型
3.2.1 高度迭代開發法與序列式開發法
?3.2.2 兩種開發法的選擇
下個議題:如何判斷前期準備工作是否到位
3.3 問題定義的先決條件
3.4 需求的先決條件
3.4.1 為什么要有正式的需求
3.4.2 穩定需求的神話
3.4.3 在構建期間處理需求變更
3.4.4 核對表:需求
1. 針對功能需求
2. 針對非功能需求(質量需求)
3. 需求的質量
4. 需求的完備性
3.5 架構的先決條件
3.5.1 架構的典型組成部分
1. 程序組織
2. 主要的類
3. 數據存儲設計
4. 業務規則
5. 用戶界面設計
6. 資源管理
7. 安全性
8. 性能
9. 可伸縮性
10. 互用性
11. 國際化/本地化
12. 輸入/輸出
13. 錯誤處理
14. 容錯性
15. 架構的可行性
16. 過度工程
17. 關于”買“還是”造“的決策
18. 關于復用的決策
19. 變更策略
20. 架構的整體質量
3.5.2 核對表:架構
針對各架構主題
架構的總體質量
3.6 花費在前期準備上的時間長度
核對表:前期準備
《Code_Complete_2》持續更新中......_@來杯咖啡的博客-CSDN博客這本書有意設計成使你既可以從頭到尾閱讀,也可以按主題閱讀。1. 如果你想從頭到尾閱讀,那么你可以直接從第2章“用隱喻來更充分地理解軟件開發”開始鉆研。2. 如果你想學習特定的編程技巧,那么你可以從第6章“可以工作的類”開始,然后根據交叉引用的提示去尋找你感興趣的主題。3. 如果你不確定哪種閱讀方式更適合你,那么你可以從第3章3.2節“辦明你所從事的軟件的類型”開始。.....................https://blog.csdn.net/qq_43783527/article/details/126275083
前言
????????木匠的諺語“瞄兩次,切一次”(Measure twice, cut once/三思而后行)與軟件開發中的構建部分有密切聯系,構建活動差不多占整個項目成本的 65%。最糟糕的軟件項目最終會進行兩三次(甚至更多)構建。將項目中最昂貴的部分執行兩遍,這無論在軟件行業還是在其他行業都是愚蠢的主意。
????????就像修建建筑物一樣,項目的成敗很大程度上在構建活動開始之前就已經注定了。如果地基沒打好,或者計劃不充分,那么你在構建期間能做的無非是盡量讓損害最小罷了。
本章主題
????????本章描述軟件構建必須做的準備工作。本章是為成功的軟件構建打地基,并沒有直接討論構建活動。
?1、清楚的知道”準備工作“有哪幾個活動組成
準備工作由下面幾個活動組成,本章也是重點對以下活動進行敘述:
構建活動由下面幾個活動組成:
2、準備工作-架構的先決條件,是我們開發需要認真關注的事情。
3.1 前期準備的重要性
????????使用高質量的實踐方法是那些能創造高質量軟件的程序員的共性。這些高質量的實踐方法在項目的初期、中期、末期都強調質量。
3.1.1 處于不同階段強調質量
????????如果你在項目的末期強調質量,那么你會強調系統測試。當提到軟件質量保證的時候,許多人都會想到測試。但是測試只是完整的質量保證策略的一部分,而且不是最有影響的部分。測試是不可能檢查出諸如“制造了一個錯誤的產品”,或者“使用錯誤的方法制造正確的產品”之類的缺陷的。這樣的缺陷必須在測試之前解決——更確切地說是在構建活動之前。
????????如果你在項目中期強調質量,那么你會強調構建實踐。這些實踐是本書絕大部分篇幅的關注點。
????????如果你在項目的開始階段強調質量,那么你就會計劃、要求并且設計一個高質量的產品。如果你用為 Pontiac Aztek 做的設計來開始整個生產過程,那么你可以想盡辦法來測試,它也絕對不會變成勞斯萊斯。也許你能造出最好的 Aztek,但如果想要的是一輛勞斯萊斯,那么你就得從頭開始做計劃。在軟件開發中,你也需要在定義問題、定下解決方案的規格,以及設計解決方案的時候做出這種計劃"。
3.1.2 前期準備對”構建活動“的影響
????????由于構建活動是軟件項目的中間階段,在你開始構建的時候,項目前期工作己經或多或少為這個項目的成功或失敗打下了基礎。然而,在構建過程中,你至少應該能辦明當時的形勢如何,如果你看到失敗的烏云已經出現在地平線上時,就退回到項目的前期工作吧。
????????本章的其余部分將仔細講述為什么合適的準備工作是非常重要的,并且告訴你如何判定“是否已經準備好開始構建工作了”。
3.1.3 準備不周全的誘因
??????? 1、造成準備工作不充分的一個常見原因是,那些分配去做前期準備活動的開發人員并不具備完成這一任務的專業技能。(個人補充:或者說是讓原本不是舊項目的開發人員去給該舊項目加磚添瓦)
- 項目規劃、創作引人注目的商業案例、分析出全面而準確的需求、創建高質量的架構等活動都需要一定的技能,這些技能不是輕而易舉就能獲得的。但是絕大多數開發人員都沒有接受過針對這些活動的訓練。當開發人員不知道如何進行這些前期工作的時候,建議“做更多的前期工作”就完全沒有用;如果不能首先把這項工作做好,那么做再多也沒有意義!說明如何進行這些活動已經超出了本書的范圍,不過在本章最后的“更多資源”中,提供了許多獲取這些專業技能的途徑。
??????? 2、程序員不做準備工作的最后一個原因是,管理者們對那些“花時間進行構建活動的前期淮備的程序員”的冷漠已經到了人神共憤的程度(簡單理解就是:管理者們只想讓我們盡快我們寫代碼)。Barry Boehm、 GradyBooch 及 Karl Wiegers 等人25 年來一直在擂響需求和設計的戰鼓,因此你可以期望,管理者們應該已經開始明白:軟件開發不僅僅是寫代碼。
3.1.4 我理解的準備周全(純屬個人理解)
????????我理解的準備周全包含兩部分。第一部分是”產品文檔“足夠清晰,第二部分是”詳設“已經確定。產品文檔讓我們知道了“要做什么”?當我們確認”可以做“的時候,詳設再來告訴我們具體”怎么做“?
3.2 辨明你所從事的軟件的類型
????????不同種類的軟件項目,需要在“準備工作”和“構建活動”之間做出不同的平衡。每一個項目都是獨特的,但是項目可以歸入若干種開發風格。表3-2 列出了三種最常見的軟件項目種類,并且列出了各種項目最適合的典型實踐。
????????在真實項目中,你會找到表中所列這三種主調的無數種變奏。
3.2.1 高度迭代開發法與序列式開發法
??????? 1、開發商業系統的項目往往受益于高度迭代的開發法,這種方法的“計劃、需求、架構”活動與“構建、系統測試、質量保證”活動交織在一起。
????????2、性命攸關的系統往往要求采用序列式的方法——“需求穩定”是確保“超高等級的可靠性”的必備條件之一。?
?3.2.2 兩種開發法的選擇
????????絕大多數的項目都不會完全使用序列式開發法或者完全使用迭代式開發法。預先詳細說明 100%的需求和設計是不切實際的,不過對絕大多數項目來說,“盡早把哪些是最關鍵的需求要素和架構要素確定下來”是很有價值的。
????????一條很有用的經驗規則是:
- 計劃好預先對大約 80%的需求做出詳細說明,并給“稍后再進行詳細說明的額外需求”分配一定的時間。然后在項目進行過程中,實施系統化的變更控制措施——只接受那些最有價值的新需求。
- 另一種替代方案是,預先只對最重要的20%的需求做出詳細說明,并且計劃以小幅增量開發軟件的剩佘部分,隨著項目的進行,對額外的需求和設計做出詳細說明。
下個議題:如何判斷前期準備工作是否到位
????????既然你已經研究過表3-2,并且確定了何種前期準備適合你的項目,那么本章接下來將要討論的是:如何判斷每一項特定的前期準備工作是否到位。
3.3 問題定義的先決條件
????????在開始構建之前,首先要滿足的一項先決條件是,對這個系統要解決的問題做出清楚的陳述。這有時稱為“產品設想/product vision ”、“設想陳述/visionstatement”、“任務陳述/mission statement” 或者“產品定義/product definition”。這里將它稱為“問題定義/problem definition”。由于這本書是關于軟件構建的,本節不打算告訴你如何去寫問題定義,而是告訴你如何辦認是否已經寫好了問題定義,以及它能否成為構建活動的良好基礎。
????????“未能定義問題”的處罰是,你浪費了大量時間去解決錯誤的問題。這是雙重處罰,因為你也沒有解決正確的問題。?
3.4 需求的先決條件
????????“需求”詳細描述軟件系統應該做什么,這是達成解決方案的第一步。
3.4.1 為什么要有正式的需求
????????要求一套明確的需求,這點很重要,理由很多。
??????? 1、明確的需求有助于確保是用戶(而不是程序員)駕馭系統的功能。如果需求明確,那么用戶就可以自行評審,并進行核準。否則,程序員就常常會在編程期間自行決定需求。明確的需求免得你去猜測用戶想要的是什么。
??????? 2、明確的需求還有助于避免爭論。在開始編程之前,先把系統的范圍 ((scope)確定下來。如果你和另外一個程序員對于“程序應該做什么”意見不一致,你們可以查看書面的需求,以解決分岐。
??????? 3、重視需求有助于減少開始編程開發之后的系統變更情況。如果你在編碼過程中發現了一個代碼上的錯誤,你只需要修改幾行的代碼,然后就能繼續工作。但是如果你在編碼的時候發現了一個需求錯誤,那你就得改變設計,使之符合更改后的需求。你可能需要扔掉部分舊的設計,并且因為要與已經寫好的代碼相適應,可能導致新的設計,與在項目之初進行同樣的設計相比,花費更長的時間。此外,還需要廢棄那些受此次需求變更影響的代碼和測試用例,還需要編寫新的代碼和測試用例。即便是未受影響的代碼也需要重新測試地方的改變沒有引入任何新的錯誤。
3.4.2 穩定需求的神話
????????“一旦客戶接受了一份需求文檔,就再也不做更改”是一個美好的愿望。然而,對一個典型的項目來說,在編寫代碼之前,客戶無法可靠地描述他們想要的是什么。問題并不在于客戶是低級生物。就如同你做這個項目的時間越長,對這個項目的理解也就越深入一樣,客戶參與項目的時間越長,他們對項目的理解也就越深入。開發過程能夠幫助客戶更好地理解自己的需求,這是需求變更的主要來源 (Curtis,Krasner, and Iscoe 1988; Jones 1998; Wiegers 2003)。
????????典型情況下需求會有多少改動?IBM 和其他公司的研究發現,平均水平的項目在開發過程中,需求會有25%的變化(Boehm 1981, Jones 1994, Jones 2000)。在典型的項目中,需求變更導致的返工占到返工總量的75%到85%(Leffingwell1997, Wiegers 2003)。
3.4.3 在構建期間處理需求變更
????????在構建期間,要最好地應對需求變更,有以下一些可以采用的方式。
??????? 1、使用本節末尾的需求核對表來評估你的需求的質量 。如果你的需求不夠好,那么就停止工作,退回去,先把它做好,再繼續前進。當然,因為在此期間你會停止編碼,所以感覺似乎進度會落后。不過,假設你正開車從芝加哥到洛杉磯,突然看到紐約的路牌,那么停下來查看路線圖是浪費時間嗎?當然不是,如果沒有對準正確的方向,那就要停下來檢查一下路線”。
??????? 2、確保每一個人都知道需求變更的代價。 客戶只要想到一個新功能就會很興奮。在興奮時血液會涌向大腦,人會暈頭暈腦,他會把所有你們開過的討論需求的會議、簽字儀式。以及已經完成的需求文檔統統拋諸腦后。最簡單的對付這種新功能中毒癥患者的辦法是說:“咦,這聽起來是一個很不錯的主意。不過由于它不是需求文檔里的內容,我會整理一份修訂過的進度表和成本估計表,這樣你可以決定是現在實施,還是過一陣子再說” 。“進度”和“成本”這兩個字眼比咖啡和洗冷水澡都要提神,許多“必須要有/must haves”很快會變成“有就最好/ nice tohaves"。
??????? 3、建立一套變更控制程序。 如果你的客戶激情不減,那就要考慮建立一個正式的變更控制委員會,評審提交上來的更改方案。客戶改變他們的想法,認識到他們需要更多的功能,這不是壞事。問題是他們提出更改方案太頻繁了,讓你跟不上進度。如果有一套固定的變更控制程序,那么大家都會很愉快—你知道自己只需在特定時候處理變更;而客戶知道你打算處理他們的提議。
????????4、使用能適應變更的開發方法。 某些開發方法讓你 “對需求變更做出響應”的能力最大化。演進原型(evolutionary prototyping)法能讓你在投入全部精力建造系統之前,先探素系統的需求。演進交付(evolutionary delivery)是一種分階段交付系統的方法。你可以建造一小塊、從用戶獲得一點反饋、調整一點設計、做少量改動,再多建造一小塊。關鍵在于縮短開發周期,以便更快地響應用戶的要求。
??????? 5、放棄這個項目。 如果需求特別糟糕,或者極不穩定,而上面的建議沒有一條能奏效,那就取消這個項目。即使你無法真的取消這個項目,也設想一下取消它之后會是怎樣的情況。在取消它之前想想它有可能會變得多糟糕。假如在某種情況下你可以放棄這個項目,那么至少也要問問自己,目前的情況和你所設想的那種情況有多大距離。
3.4.4 核對表:需求
????????這張需求核對表包含了一系列的問題一一問問自己項目的需求工作做得如何。本書并不會告訴你如何做出好的需求分析,所以列表里面也不會有這樣的問題。在開始構建之前,用這份列表做一次“心智健全”檢查,看看你的地基到底有多堅固——用 “需求里氏震級”來衡量。
????????并不是核對表中所有的問題都適用于你的項目。如果你做的是一個非正式項目,那么你會發現有些東西根本就不需要考慮。你還會發現一些問題你需要考慮,但不需要做出正式的回答。如果你在做一個大型的、正式的項目,你也許就要逐條考慮了。
1. 針對功能需求
- 是否詳細定義了系統的全部輸入,包括其來源、精度、取值范圍、出率等?
- 是否詳細定義了系統的全部輸出,包括目的地、精度、取值范圍、出率、格式等?
- 是否詳細定義了所有輸出格式(Web 頁面、報表,等等)?
- 是否詳細定義了所有硬件及軟件的外部接口?
- 是否詳細定義了全部外部通信接口,包括握手協議、糾錯協議、通信等?
- 是否列出了用戶想要做的全部事情?
- 是否詳細定義了每個任務所用的數據,以及每個任務得到的數據?
2. 針對非功能需求(質量需求)
- 是否為全部必要的操作,從用戶的視角,詳細描述了期望響應時間?
- 是否詳細描述了其他與計時有關的考慮,例如處理時間、數據傳輸率、系統吞吐量?
- 是否詳細定義了安全級別?
- 是否詳細定義了可靠性,包括軟件失靈的后果、發生故障時需要保護的至關重要的信息、錯誤檢測與恢復的策略等?
- 是否詳細定義了機器內存和剩余磁盤空間的最小值?
- 是否詳細定義了系統的可維護性,包括適應特定功能的變更、操作環境的變更、與其他軟件的接口的變更能力?
- 是否包含對“成功”的定義?“失敗”的定義呢?
3. 需求的質量
- 需求是用用戶的語言書寫的嗎?用戶也這么認為嗎?
- 每條需求都不與其他需求沖突嗎?
- 是否詳細定義了相互競爭的特性之間的權衡--例如,健壯性與正確性之間的權衡?
- 是否避免在需求中規定設計(方案)?
- 需求是否在詳細程度上保持相當一致的水平?有些需求應該更詳細地描述嗎?有些需求應該更粗略地描述嗎?
- 需求是否足夠清晰,即使轉交給一個獨立的小組去構建,他們也能理解嗎?開發者也這么想嗎?
- 每個條款都與待解決的問題及其解決方案相關嗎?能從每個條款上溯到它在問題域中對應的根源嗎?
- 是否每條需求都是可測試的?是否可能進行獨立的測試,以檢驗滿不滿足各項需求?
- 是否詳細描述了所有可能的對需求的改動,包括各項改動的可能性?
4. 需求的完備性
- 對于在開始開發之前無法獲得的信息,是否詳細描述了信息不完全的區域?
- 需求的完備度是否能達到這種程度:如果產品滿足所有需求,那么它就是可接受的?
- 你對全部需求都感到很舒服嗎?你是否已經去掉了那些不可能實現的需求——那些只是為了安撫客戶和老板的東西?
3.5 架構的先決條件
????????由于本書是關于軟件構建的,因此本節不會告訴你如何開發一個軟件的架構。因為架構比需求離構建活動又近了一步,所以對架構的討論也會比對需求的討論更詳細一些。
????????好的架構使得構建活動變得更容易。糟糕的架構則使構建活動幾乎寸步難行。圖3-7顯示了糟糕的架構的另一個問題。
?????????在構建期間或者更晚的時候進行架構變更,代價也是高昂的。修復軟件架構中的錯誤所需的時間與修復需求錯誤所需的時間處于同一數量級——即,多于修復編碼錯誤所需的時間(Basili and Perricone 1984, Willis 1998)。架構變更如同需求變更一樣,看起來一個很小的改動,影響也許是非常深遠的。無論為了修正錯誤還是改進設計而引發架構變更,越早識別出變更越好。
3.5.1 架構的典型組成部分
很多組成部分是優秀的系統架構所共有的。
????????如果你自己構建整個系統,那么在架構工作會與更詳細的設計工作有重疊部分。在這種情況下,你至少應該思考架構的每個組成部分。
????????如果你目前從事的系統的架構是別人做的,你應該能夠不費力地找出其中重要的組成部分(無須戴.上獵鹿帽、牽著獵犬、手拿放大鏡)。
????????在這兩種情況中,你都需要考慮以下的架構組成部分。
1. 程序組織
????????系統架構首先要以概括的形式對有關系統做一個綜述。如果沒有這種綜述,要想將成干的局部圖片(或十多個單獨的類)拼成一幅完整的圖畫是相當傷腦筋的。如果系統是小小的只有12塊的智力拼圖玩具,你那一歲的小孩也能在眨眼功夫解決它。不過把12 個子系統拼到一起要困難一些,而且如果你不能將它們拼起來,那么就無法理解你正在開發的那個類對系統有何貢獻。
????????在架構中,你應該能發現對那些曾經考慮過的最終組織結構的替代方案的記敘,找到之所以選用最終的組織結構,而不用其他替代方案的理由。如果對某個類在系統中的角色沒有一個清晰的構思,那么編寫這個類就是一件令人灰心喪氣的工作。描述其他組織結構,才能說明架構最后選定的這種系統組織結構的緣由,并且表明各個類都是慎重考慮過的。有一份對設計實踐的綜述發現,“維護‘設計的緣由’”至少與“維護設計本身”一樣重要(Rombach 1990)。
????????架構應該定義程序的主要構造塊 (building blocks)。根據程序規模不同,各個構造塊可能是單個類,也可能是由許多類組成的一個子系統。每個構造塊無論是一個類還是一組協同工作的類和子程序,它們共同實現一種高層功能,諸如與用戶交互、顯示 web 頁面、解釋命令、封裝業務規則、訪問數據,等等。每條列在需求中的功能特性(feature)都至少應該有一個構造塊覆蓋它。如果兩個或多個構造塊聲稱實現同一項功能,那么它們就應該相互配合而不會沖突。
????????應該明確定義各個構造塊的責任。每個構造塊應該負責某一個區域的事情,并且對其他構造塊負責的區域知道得越少越好。通過使各個構造塊對其他構造塊的了解達到最小,你能將設計的信息局限于各個構造塊之內。
2. 主要的類
關于”類的設計“可以詳細看:第6章 可以工作的類。
????????架構應該詳細定義所用的主要的類。它應該指出每個主要的類的責任,以及該類如何與其他類交互。
- 它應該包含對類的繼承體系、狀態轉換、對象持久化等的描述。如果系統足夠大,它應該描述如何將這些類組織成一個個子系統。
- 架構應該記述曾經考慮過的其他類設計方案,并給出選用當前的組織結構的理由。
- 架構無須詳細說明系統中的每一個類。瞄準 80/20 法則:對那些構成系統80%的行為的 20%的類進行詳細說明 (Jacobsen, Booch, and Rumbaugh 1999;Kruchten 2000)。
3. 數據存儲設計
????????架構應該描述所用到的主要文件和數據表的設計。它應該描述曾經考慮過的其他方案,并說明做出選擇的理由。
- 如果應用程序要維護一個客戶ID 的列表,而架構師決定使用順序訪問的列表(sequential-access list)來表示該ID 表,那么文檔就應該解釋為什么順序訪問的列表比隨機訪問的列表(random-access list)、堆棧、散列表要好。
- 在構建期間,這些信息讓你能洞察架構師的思想。在維護階段,這種洞察力是無價之寶。離開它,你就像看一部沒有字幕的外語片。
????????數據通常只應該由一個子系統或 一個類直接訪問;例外的情況就是透過訪問器類(access class)或訪問器子程序(access routine)——以受控且抽象的方式——來訪問數據。詳細的解釋請看第5.3節中的“隱藏秘密(信息隱藏)”。
????????架構應該詳細定義所用數據庫的高層組織結構和內容。
- 架構應該解釋為什么單個數據庫比多個數據庫要好(反之亦然),
- 解釋為什么不用平坦的文件而要用數據庫,指出與其他訪問同一數據的程序的可能交互方式,說明會創建哪些數據視圖(view),等等。
4. 業務規則
????????如果架構依賴于特定的業務規則,那么它就應該詳細描述這些規則,并描述這些規則對系統設計的影響。例如,假定要求系統遂循這樣-條業務規則:客戶信息過時的時間不能超過30 秒。在此情況下,架構就應該描述這條規則對架構采用的“保持客戶信息及時更新且同步”的方法的影響。
5. 用戶界面設計
????????用戶界面常常在需求階段進行詳細說明。如果沒有,就應該在軟件架構中進行詳細說明。架構應該詳細定義 web 頁面格式、GUI、命令行接口 (command lineinterface) 等的主要元素。用戶界面設計值得用整本書的篇幅來討論,不過這超出了本書的范圍。
6. 資源管理
????????架構應該描述一份管理稀缺資源的計劃。稀缺資源包括數據庫連接、線程、句柄(handle)等。在內存受限的應用領域,如驅動程序開發和嵌入式系統中,內存管理是架構應該認真對待的另一個重要領域。架構應該估算在正常情況和極端情況下的資源使用量。在簡單的情況下,估算數據應該說明:預期的實現環境(運行環境)有能力提供所需的資源。在更復雜的情況中,也許會要求應用程序更主動地管理其擁有的資源。如果是這樣,那么“資源管理器/resource manager” 應和系統的其他部分一樣進行認真的架構設計。
7. 安全性
????????架構應該描述實現設計層面和代碼層面的安全性的方法。如果先前尚未建立威脅模型(threat model),那么就應該在架構階段建立威脅模型。在制定編碼規范的時候應該把安全性牢記在心,包括處理緩沖區的方法、處理非受信(untrudted)數據(用戶輸入的數據、cookies、配置數據(文件)和其他外部接口輸入的數據)的規則、加密、錯誤消息的細致程度、保護內存中的秘密數據,以及其他事項。
8. 性能
????????如果需要關注性能,就應該在需求中詳細定義性能目標。性能目標可以包括資源的使用,這時,性能目標也應該詳細定義資源(速度、內存、成本)之間的優先順序。
????????架構應該提供估計的數據,并解釋為什么架構師相信能達到性能目標。如果某些部分存在達不到性能目標的風險,那么架構也應該指出來。如果為了滿足性能目標,需要在某些部分使用特定的算法或數據類型,架構也應該說清楚。架構中也可以包括各個類或各個對象的空間和時間預算。
9. 可伸縮性
????????可伸縮性是指系統增長以滿足未來需求的能力。架構應該描述系統如何應對用戶數量、服務器數量、網絡節點數量、數據庫記錄數、數據庫記錄的長度、交易量等的增長。如果預計系統不會增長,而且可伸縮性不是問題,那么架構應該明確地列出這一假設。
10. 互用性
????????如果預計這個系統會與其他軟件或硬件共享數據或資源,架構應該描述如何完成這一任務。
11. 國際化/本地化
12. 輸入/輸出
????????輸入輸出(VO)是架構中值得注意的另一個領域。架構應該詳細定義讀取策略(reading scheme)是先做(look-ahead)、后做(look-behind)還是即時做(just-in-time)。而且應該描述在哪一層檢測 VO 錯誤:在字段、記錄、流,或者文件的層次。
13. 錯誤處理
????????錯誤處理己被證實為現代計算機科學中最棘手的問題之一,你不能武斷地處理它。有人估計程序中高達 90%的代碼是用來處理異常情況、進行錯誤處理、或做簿記(housekeeping)工作,意味著只有10%的代碼是用來處理常規的情況(Shaw inBentley 1982)。既然這么多代碼致力于處理錯誤,那么在架構中就應該清楚地說明一種“一致地處理錯誤〞的策略。
????????錯誤處理常被視為是“代碼約定層次/coding-convention-level” 的事情一—如果真有人注意它的話。但是因為錯誤處理牽連到整個系統,因此最好在架構層次上對待它。下面是一些需要考慮的問題。
- 錯誤處理是進行糾正還是僅僅進行檢測?如果是糾正,程序可以嘗試從錯誤中恢復過來。如果僅僅是檢測,那么程序可以像“沒有發生任何事”一樣繼續運行,也可以退出。無論哪一種情況,都應該通知用戶說檢測到一個錯誤。
- 錯誤檢測是主動的還是被動的?系統可以主動地預測錯誤—例如,通過檢查用戶輸入的有效性——也可以在不能避免錯誤的時候,被動地響應錯誤——例如,當用戶輸入的組合產生了一個數值溢出錯誤時。前者可以掃清障礙,后者可以清除混亂。同樣,無論采用哪種方案,都與用戶界面有影響。
- 程序如何傳播錯誤?程序一旦檢測到錯誤,它可以立刻丟棄引發該錯誤的數據;也可以把這個錯誤當成一個錯誤,并進入錯誤處理狀態;或者可以等到所有處理完成,再通知用戶說在某個地方發現了錯誤。
- 錯誤消息的處理有什么約定?如果架構沒有詳細定義一個一致的處理策略,那用戶界面看起來就像“令人困惑的亂七八糟的抽象拼貼畫”,由程序的不同部分的各種界面拼接而成。要避免這種外觀體驗,架構應該建立一套有關錯誤消息的約定。
- 如何處理異常(exceptions)? 架構應該規定代碼何時能夠拋出異常,在什么地方捕獲異常,如何記錄(log)這些異常,以及如何在文檔中描述異常,等等。
- 在程序中,在什么層次上處理錯誤?你可以在發現錯誤的地方處理,可以將錯誤傳遞到專門處理錯誤的類進行處理,或者沿著函數調用鏈往上傳遞錯誤。
- 每個類在驗證其輸入數據的有效性方面需要負何種責任?是每個類負責驗證自己的數據的有效性,還是有一組類負責驗證整個系統的數據的有效性?某個層次上的類是否能假設它接收的數據是干凈的(clean,即,沒有錯誤)?
- 你是希望用運行環境中內建的錯誤處理機制,還是想建立自己的一套機制?事實上,運行環境所擁有的某種特定的錯誤處理方法,并不一定是符合你的需求的最佳方法。
14. 容錯性
????????架構還應該詳細定義所期望的容錯種類。容錯是增強系統可靠性的一組技術,包括檢測錯誤;如果可能的話從錯誤中恢復;如果不能從錯誤中恢復,則包容其不利影響。
????????其他容錯方法包括,在遇到錯誤的時候,讓系統轉入某種“部分運轉/partialoperation” 的狀態,或者轉入某種“功能退化/degraded functionality” 的狀態。系統可以自動關閉或重啟。這些例子經過了必要的簡化。容錯是一個吸引人的復雜主題——可惜,它超出了本書的范圍。
15. 架構的可行性
????????設計師多半會關注系統的各種能力,例如是否達到性能目標,能夠在有限的資源下運轉,實現環境(運行環境)是否有足夠的支持。架構應該論證系統的技術可行性。如果在任何一個方面不可行都會導致項目無法實施,那么架構應該說明“這些問題是如何經過研究的〞-—通過驗證概念的原型(proof-of-conceptprototype)、研究、或其他手段。必須在全面開展構建之前解決掉這些風險。
16. 過度工程
????????架構應該清楚地指出程序員應該“為了謹慎起見寧可進行過度工程(overengineering)”,還是應該做出最簡單的能工作的東西。
????????詳細定義一種過度工程(裕度工程)的方法尤其重要,因為許多程序員會出于專業自豪感,對自己編寫的類做過度工程。通過在架構中明確地設立期望目標,就能避免出現“某些類異常健壯,而其他類勉強夠健壯”的現象。
17. 關于”買“還是”造“的決策
????????最激進的構建軟件的解決方案是根本不去構建它——購買軟件,或者免費下載開源的軟件。
????????如果架構不采用現貨供應的組件,那么就應該說明“自己定制的組件應該在哪些方面勝過現成的程序庫和組件”。
18. 關于復用的決策
??????? 如果開發計劃提倡使用業已存在的軟件、測試用例、數據格式或其他原料,架構應該說明:如何對復用的軟件進行加工,使之符合其他架構目標——如果需要使之符合的話。
19. 變更策略
??????? 1、因為對于程序員和用戶來說,構建軟件產品都是一個學習過程,所以在開發過程中產品很可能會發生變化。這些變更來自不穩定的數據類型和文件格式、功能需求的變更、新的功能特性,等等。這些變更可能是計劃增加的新功能,也可能是沒有添加到系統的第一個版本中的功能。因此,軟件架構師面臨的一個主要挑戰是,讓架構足夠靈活,能夠適應可能出現的變化。
交叉參考:關于有系統地處理變更的具體辦法,見第 28.2節“配置管理”。
?????? 2、 架構應當清楚地描述處理變更的策略。架構應該列出已經考慮過的有可能會有所增強的功能,并說明“最有可能增強的功能同樣也是最容易實現的”。如果變更很可能出現在輸入輸出格式、用戶交互的風格、需求的處理等方面,那么架構就應該說明:這些變更已經被預料到了,并且任何單一的變更都只會影響少數幾個類。架構應對變更的計劃可以很簡單,比如在數據文件中放入版本號、保留一些供將來使用的字段、或者將文件設計成能夠添加新的表格。如果使用了代碼生成器,那么架構應該說明,可預見的變更都不會超出該代碼生成器的能力范圍。
設計中的 bug 常常不易發現;隨著演化的進行,系統不斷增加新的功能特性和用途,早期的設計假設漸漸被忘記,這時設計中的bug 就會現身。—FerandoJ. Corbato
??????? 3、架構應該指出“延遲提交/delay commitment”所用的策略(延遲提交是指推遲茉些因素的確定時間,做晚綁定,以增強靈活性)。比如說,架構也許規定使用表驅動(table-driven)技術(而不使用硬編碼的if語句)。它也許還規定“表”中的數據是保存在外部文件中,而非直接寫在程序代碼中,這樣就能做到在不重新編譯的情況下修改程序。???
交叉引用:關于延遲提交的完整描述,見第5.3節中的“有意識地選擇綁定時間”?????
20. 架構的整體質量
3.5.2 核對表:架構
????????以下是一份問題列表,優秀的架構應該關注這些問題。這張核對表的意圖并非用做一份有關如何做架構的完全指南,而是作為一種實用的評估手段,用來評估軟件食物鏈到了程序員這一頭還有多少營養成分。這張核對表可用做你自己的核對表的出發點。就像“需求”的核對表一樣,如果你從事的是非止式項目,那么你會發現其中某些條款甚至都不用去想。如果你從事的是更大型的項目,那么大多數條款都會是很有用的。
針對各架構主題
- 程序的整體組織結構是否清晰?是否包含一個良好的架構全局觀(及其理由)?
- 是否明確定義了主要的構造塊(包括每個構造塊的職責范圍及與其他構造塊的接口)?
- 是否明顯涵蓋了“需求”中列出的所有功能(每個功能對應的構造塊不太多也不太少)?
- 是否描述并論證了那些最關鍵的類?
- 是否描述并論證了數據設計?
- 是否詳細定義了數據庫的組織結構和內容?
- 是否指出了所用關鍵的業務規則,并描述其對系統的影響?
- 是否描述了用戶界面設計的策略?
- 是否將用戶界面模塊化,使界面的變更不會影響程序其余部分?
- 是否描述并論證了處理 VO 的策略?
- 是否估算了稀缺資源(如線程、數據庫連接、句柄、網絡帶寬等)的使用量,是否描述并論證了源管理的策略?
- 是否描述了架構的安全需求?
- 架構是否為每個類、每個子系統、或每個功能域(functionality area)提出空間與時間預算?
- 架構是否描述了如何達到可伸縮性?
- 架構是否關注互操作性?
- 是否描述了國際化/本地化的策略?
- 是否提供了一套內聚的錯誤處理策略?
- 是否規定了容錯的辦法(如果需要)?是否證實了系統各個部分的技術可行性?
- 是否詳細描述了過度工程(overengineering)的方法?
- 是否包含了必要的“買 vs. 造”的決策?
- 架構是否描述了如何加工被復用的代碼,使之符合其他架構目標?
- 是否將架構設計得能夠適應很可能出現的變更?
架構的總體質量
- 架構是否解決了全部需求?
- 有沒有哪個部分是“過度架構/overarchitected”或“欠架構/underarchitected'是否明確宣布了在這方面的預期指標?
- 整個架構是否在概念上協調一致?
- 頂層設計是否獨立于用作實現它的機器和語言?
- 是否說明了所有主要的決策的動機?
- 你,作為一名實現該系統的程序員,是否對這個架構感覺良好?
3.6 花費在前期準備上的時間長度
????????花費在問題定義、需求分析、軟件架構上的時間,依據項目的需要而變化。一般說來,一個運作良好的項目會在需求、架構以及其他前期計劃方面投入10%~20%的工作量和 20%~30%的時間(McConnell 1998, Kruchten 2000)。這些數字不包括詳細設計的時間——那是構建活動的一部分。
????????如果需求不穩定,同時你從事的是一個大型的正式項目,那你就很可能需要與需求分析師合作,以解決構建活動早期指出的需求問題。你要為“與需求分析師協商〞預留一些時間,還應預留時間給需求分析師修訂需求,這樣你才能得到一份可行的需求。
????????如果需求不穩定,同時你從事的是一個小型的非正式的項目,那你很可能需要自己解決需求方面的問題。要預留足夠的時間,將需求定義足夠清晰,讓需求的不穩定性對構建活動的負面影響降至最低。
????????如果需求在任何項目上都不穩定——無論正式項目或非正式項目——那就將需求分析工作視為獨立的項目來做。在完成需求之后,估計項目余下的部分要花多少時間。這是明智的辦法,因為在弄清楚要做的是什么之前,沒人相信你能估算出合理的進度表。這就好比你是一名承包商,有人請你建一棟房子。客戶問你:“完成這項工作要花多少錢?”你會合理地詢問:“你想要我做什么?”客戶說:“我不能告訴你,不過我想知道需要花費多少錢?”你該明智地感謝他浪費了你的時間,然后轉身回家。
????????在為軟件架構分配時間的時候,要使用與需求分析類似的方法。如果軟件是你以前沒有做過的類型,應當為“在新的領域中做設計”的不確定性預留更多時問。你要確保創建良好架構所需要的時間,不會被“為做好其他方面工作所需要的時間”所擠占。如果有必要,將架構工作也作為獨立的項目來對待。
核對表:前期準備
- 你是否辨明了自己所從事的軟件的類型,并對所用的開發方法做出相應的剪裁?
- 是否充分明確地定義了需求?而且需求足夠穩定,能開始構建了?(詳見需求核對表。)
- 是否充分明確地定義了架構,以便開始構建?(詳見架構核對表。)
- 是否已經指出你的(當前)項目中獨有的風險(以避免構建活動面臨不必更的風險)?
總結
以上是生活随笔為你收集整理的《代码大全2》第3章 三思而后行,前期准备的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Arcgis For Android实现
- 下一篇: 【js】不间断空格 特殊的空格-ASCI