軟體設計的複雜度
什麼是軟體設計的複雜度
軟體技術發展的使命之一就是控制複雜度(Complexity)。從高階語言的產生,到結構化程式設計,再到物件導向程式設計、元件化程式設計等等。關於複雜度的定義並不一致,想要詳細瞭解的可以讀讀The Many Faces of Complexity in Software Design.
英文中Complex和Complicated有著微妙的不同。但總結起來,軟體複雜度偏負面意義,包括兩個要點:
- 難以理解 (難以維護和擴充套件。)
- 無法預測行為
複雜度是隨著軟體規模不斷擴大而必然產生的。它本身又是一個相對的概念,同一個系統對於設計者、開發者,以及維護者而言,複雜度是不同的。不同時期,一個程式設計師所能掌握的複雜度也是不同的,這也是一個程式設計師不斷提升的目標。
既然業界已經對抗複雜度幾十年了,我們就來整理一下。
以分解降低複雜度
以分解的方式進行的設計,主要特點是:
- 分離職責(Seperation of Concerns,參考單一職責原則)
- 關注介面(定義互動)
這是最常使用的技術了。將一個大問題,不斷的拆解為各個小問題進行分析研究,然後再組合到一起。在西方稱為Divide and Conquer Principle (分而治之原則)。
在結構化程式設計的時代,提倡模組化(Modularization)。最早提出軟體複雜度的工程師提出了基於元件的軟體(Component Based Software)。不知道是不是從樂高積木上得到的啟發,將系統中拆分為不同的元件,各自實現,然後再組裝在一起。
在架構設計中,無論是C/S風格,分層,還是N-Tier,SOA,和前面元件式一樣,都是在進行分解,它們都更加強調組合互動。設計上,分分職責,定義好介面,就可以各自開發了。然後將互動限定於介面層,就能夠很好的控制整個系統的複雜度。
比如應用層使用一個語音庫(Speech Library,一個以庫的形式的模組化應用), 根本不用關心其內部實現,只要瞭解如何使用它的API就可以了。
改善低賴降低複雜度
改進依賴關係的要點:
- 無環形依賴
- 穩定依賴原則(SDP)
分解可以降低系統層級的複雜度,但還有一種複雜度無法解決,即依賴的問題。這在敏捷軟體開發:原則、模式與實踐中關於依賴性的討論很詳細。當參與者增加時,互動就會隨之變得複雜。而當前的軟體規模,系統中的各類SDK的API, Framework的API, 各種第三方庫越來越多,模組間的依賴就會越來越複雜。
顯然系統中的模組或者元件太多了,需要進一步整理。但真正的問題在於出現了雙向和環形的依賴。比如上圖中負責計算的Computing模組也依賴到了UI模組,或許是因為UI層持有一個計算所需的關鍵引數。如果UI層變更,就可能會影響到Computing,出現無法預測的行為,給客戶以不穩定的印象。
所以模組間的依賴關係必須簡化,絕對不能出現環形的依賴。以Chromium為例,它對各個模組的依賴就有嚴格的定義,並且有DEPS在編譯期保證程式設計師不會犯錯。下圖是Chromium Component依賴關係的定義,其中Component內部目錄的依賴關係也有定義:
當底層模組需要依賴上層模組的實現時,就要通過依賴倒置(DIP)來處理。簡單而言就是由底層模組定義一個介面,要求上層模組實現並注入到底層模組。
使用抽象降低複雜度
人的學習過程最有效的一種方式就是歸類,其中運用的就是抽象思維。面對變幻無常的天氣,人類通過對雲的形狀進行抽象,就可以預測天氣變化。這裡有一個抽象建模的過程。
抽象並不是面嚮物件語言專屬,其實它和語言無關,本質上是一個思考的方式。它和分離的最大區別在於,抽象強調將細節隱藏,只關注核心的本質。而後者則重視於細節問題的分解和組合。
以求固定兩點的最快捷路線為例。從分離的角度來,可以分解為以下問題:
- 步行需要多少時間?
- 乘公共交通多少時間?
- 乘的士多少時間?
- 組合以上答案,再評估哪一個最快捷的方式。
而從抽象的角度來看,解決的思路會是這樣的:
遍歷所有可能的交通工具,取耗時最小的:
1. 步行
2. 乘公共交通
3. 乘的士
先給出一個抽象的解決思路,至於細節,則是進一步的實現。抽象最大的威力在於它比實現要穩定,也最能用於固化核心設計。在開發過程中,常常圍繞著各種細節討論,似乎抽象過於虛。但是如果沒有以抽象來建立系統的設計全景,有些討論將變得效率低下。
在敏捷軟體開發:原則、模式與實踐中,Martin大叔簡單的用抽象類在總類個數中的佔比作為抽象性的度量,再結合穩定性的度量,用來評估設計。詳情可以參考元件設計原則之概念篇(三)。
以通俗原則降低複雜度
設計和實現時引入不必要的抽象或分解,也是一種複雜度.考慮擴充套件性也是確定會發生的需求才要考慮進來,否則就是引入不必要的複雜性.這也是敏捷設計所倡導的.
一些約定俗成的命名,常常隱含著設計.比如Observer, Client, Adapter等等.我們要學習這些模式,也要準確加以命名.否則很容易造成理解上的問題.
小結
軟體設計是一個平衡的過程,軟體的複雜度決定著系統的可維護性、可擴充套件性和靈活性。我們再來回顧一下前人定義出軟體設計的三原則:模組化、抽象和資訊隱藏。McCabe也曾有論文專門討論將圈複雜度應用度量設計的複雜度,不過已經歷史久遠。現在來看以依賴關係來評估設計的複雜度會更為有效。有興趣可以瞭解一下CppDepend。另外Google的工程師則基於LLVM IR也實現了一個工具用於依賴關係分析(Generateing Precise Dependencies for Large Software)。
轉載請註明出處: http://blog.csdn.net/horkychen
相關文章
- 領域驅動設計對軟體複雜度的應對複雜度
- 阿里研究員:警惕軟體複雜度困局阿里複雜度
- 在複雜領域中設計軟體:領域驅動設計 - levelup
- 阿里研究員谷樸:警惕軟體複雜度困局阿里複雜度
- 時間複雜度的計算時間複雜度
- 架構設計複雜度的6個來源架構複雜度
- 關於計算時間複雜度和空間複雜度時間複雜度
- 系統困境與軟體複雜度,為什麼我們的系統會如此複雜複雜度
- 複雜度分析的套路及常見的複雜度複雜度
- 時間複雜度怎麼算?如何計算時間複雜度?時間複雜度
- 如何降低軟體的複雜性?
- 時間複雜度跟空間複雜度時間複雜度
- 時間複雜度和空間複雜度時間複雜度
- 時間複雜度與空間複雜度時間複雜度
- 軟體設計雜談(二)--軟體設計與設計人員的個人素質 (轉)
- 越做越複雜的軟體工程專案軟體工程
- 複雜度分析複雜度
- DDD函式程式設計案例:戰勝軟體開發的複雜性! 戰勝方式本身有點複雜哦!函式程式設計
- 時間複雜度O(n)和空間複雜度時間複雜度
- 時間複雜度和空間複雜度 順序時間複雜度
- 軟體的複雜性:命名的藝術
- 說說你對演算法中時間複雜度,空間複雜度的理解?如何計算?演算法時間複雜度
- 密碼複雜度設定函式密碼複雜度函式
- 網路模型複雜度計算方法模型複雜度
- 淺析程式碼圈複雜度及認知複雜度複雜度
- 害怕軟體的複雜嗎?其實複雜性是必須存在的 - ferd
- 軟體開發到底是業務複雜還是UI複雜UI
- 面試中的複雜度分析面試複雜度
- 討厭演算法的程式設計師 4 - 時間複雜度演算法程式設計師時間複雜度
- 【資料結構】-時間複雜度和空間複雜度資料結構時間複雜度
- Linux 如何設定密碼複雜度?Linux密碼複雜度
- 一文講透演算法中的時間複雜度和空間複雜度計算方式演算法時間複雜度
- 複雜性正在殺死軟體開發者
- 軟體的複雜性正在殺死我們
- 透鏡設計和萬智牌的簡化(上):三種複雜度複雜度
- 那些年忽略的知識:時間複雜度和空間複雜度詳解時間複雜度
- 演算法--複雜度演算法複雜度
- 演算法複雜度演算法複雜度