軟件技術發展的使命之1就是控制復雜度(Complexity)。從高級語言的產生,到結構化編程,再到面向對象編程、組件化編程等等。關于復雜度的定義其實不1致,想要詳細了解的可以讀讀The Many Faces of Complexity in Software Design.
英文中Complex和Complicated有著奧妙的不同。但總結起來,軟件復雜度偏負面意義,包括兩個要點:
- 難以理解 (難以保護和擴大。)
- 沒法預測行動
復雜度是隨著軟件范圍不斷擴大而必定產生的。它本身又是1個相對的概念,同1個系統對設計者、開發者,和保護者而言,復雜度是不同的。不同時期,1個程序員所能掌握的復雜度也是不同的,這也是1個程序員不斷提升的目標。
既然業界已對抗復雜度幾10年了,我們就來整理1下。
以分解的方式進行的設計,主要特點是:
- 分離職責(Seperation of Concerns,參考單1職責原則)
- 關注接口(定義交互)
這是最常使用的技術了。將1個大問題,不斷的拆解為各個小問題進行分析研究,然后再組合到1起。在西方稱為Divide and Conquer Principle (分而治之原則)。
在結構化編程的時期,提倡模塊化(Modularization)。最早提出軟件復雜度的工程師提出了基于組件的軟件(Component Based Software)。不知道是否是從樂高積木上得到的啟發,將系統中拆分為不同的組件,各自實現,然后再組裝在1起。
在架構設計中,不管是C/S風格,分層,還是N-Tier,SOA,和前面組件式1樣,都是在進行分解,它們都更加強調組合交互。設計上,分分職責,定義好接口,就能夠各自開發了。然后將交互限定于接口層,就可以夠很好的控制全部系統的復雜度。
比如利用層使用1個語音庫(Speech Library,1個以庫的情勢的模塊化利用), 根本不用關心其內部實現,只要了解如何使用它的API就能夠了。
改進依賴關系的要點:
- 無環形依賴
- 穩定依賴原則(SDP)
分解可以下降系統層級的復雜度,但還有1種復雜度沒法解決,即依賴的問題。這在敏捷軟件開發:原則、模式與實踐中關于依賴性的討論很詳細。當參與者增加時,交互就會隨之變得復雜。而當前的軟件范圍,系統中的各類SDK的API, Framework的API, 各種第3方庫愈來愈多,模塊間的依賴就會愈來愈復雜。
明顯系統中的模塊或組件太多了,需要進1步整理。但真實的問題在于出現了雙向和環形的依賴。比如上圖中負責計算的Computing模塊也依賴到了UI模塊,也許是由于UI層持有1個計算所需的關鍵參數。如果UI層變更,便可能會影響到Computing,出現沒法預測的行動,給客戶以不穩定的印象。
所以模塊間的依賴關系必須簡化,絕對不能出現環形的依賴。以Chromium為例,它對各個模塊的依賴就有嚴格的定義,并且有DEPS在編譯期保證程序員不會出錯。下圖是Chromium Component依賴關系的定義,其中Component內部目錄的依賴關系也有定義:
當底層模塊需要依賴上層模塊的實現時,就要通過依賴顛倒(DIP)來處理。簡單而言就是由底層模塊定義1個接口,要求上層模塊實現并注入到底層模塊。
人的學習進程最有效的1種方式就是歸類,其中應用的就是抽象思惟。面對變幻無常的天氣,人類通過對云的形狀進行抽象,就能夠預測天氣變化。這里有1個抽象建模的進程。
抽象其實不是面向對象語言專屬,其實它和語言無關,本質上是1個思考的方式。它和分離的最大區分在于,抽象強調將細節隱藏,只關注核心的本質。而后者則重視于細節問題的分解和組合。
以求固定兩點的最快捷線路為例。從分離的角度來,可以分解為以下問題:
- 步行需要多少時間?
- 乘公共交通多少時間?
- 乘的士多少時間?
- 組合以上答案,再評估哪個最快捷的方式。
而從抽象的角度來看,解決的思路會是這樣的:
遍歷所有可能的交通工具,取耗時最小的:
1. 步行
2. 乘公共交通
3. 乘的士
先給出1個抽象的解決思路,至于細節,則是進1步的實現。抽象最大的威力在于它比實現要穩定,也最能用于固化核心設計。在開發進程中,常常圍繞著各種細節討論,仿佛抽象過于虛。但是如果沒有以抽象來建立系統的設計全景,有些討論將變得效力低下。
在敏捷軟件開發:原則、模式與實踐中,Martin大叔簡單的用抽象類在總類個數中的占比作為抽象性的度量,再結合穩定性的度量,用來評估設計。詳情可以參考組件設計原則之概念篇(3)。
設計和實現時引入沒必要要的抽象或分解,也是1種復雜度.斟酌擴大性也是肯定會產生的需求才要斟酌進來,否則就是引入沒必要要的復雜性.這也是敏捷設計所提倡的.
1些約定俗成的命名,常常隱含著設計.比如Observer, Client, Adapter等等.我們要學習這些模式,也要準確加以命名.否則很容易造成理解上的問題.
軟件設計是1個平衡的進程,軟件的復雜度決定著系統的可保護性、可擴大性和靈活性。我們再來回顧1下前人定義出軟件設計的3原則:模塊化、抽象和信息隱藏。McCabe也曾有論文專門討論將圈復雜度利用度量設計的復雜度,不過已歷史久遠?,F在來看以依賴關系來評估設計的復雜度會更加有效。有興趣可以了解1下CppDepend。另外Google的工程師則基于LLVM IR也實現了1個工具用于依賴關系分析(Generateing Precise Dependencies for Large Software)。
轉載請注明出處: http://blog.csdn.net/horkychen