作者簡介: 常柱,微信公眾號【架構未來】作者,十多年一線互聯網研發從業經驗;擅長大型業務系統架構和技術團隊管理工作;對會員體系、技術中台、業務中台、物聯網平台等建設有豐富的經驗;前五八同城商業會員技術負責人,寶駕租車技術負責人等,現在58到家負責業務中台技術團隊。
編寫計算機軟件是人類歷史上最純粹的創造性活動之一。程序員不受物理定律等實際限制的約束;我們可以用在現實世界中不可能存在的行為來創造令人興奮的虛擬世界。編程不需要像芭蕾舞或籃球那樣的身體技能或協調能力。所有的編程需要的是一個創造性的頭腦和能組織你的想法的能力。如果你能把一個系統形象化,你也許就能在計算機程序中實現它。
這意味着,在編寫軟件的過程中,最大的限制是我們理解自己正在創建的系統的能力。隨着程序的完善和功能的疊加,系統會變得更加復雜,其組件之間依賴關系會變得極其微妙。隨着時間的推移,復雜性不斷增加,當程序員修改系統時,他們越來越難以記住所有相關的因素。這會降低開發速度並導致bug,從而進一步降低開發速度並增加開發成本。在任何程序的生命周期中,復雜性都會不可避免地增加。程序越大,參與其中的人員越多,管理復雜性就越困難。
好的開發工具可以幫助我們處理復雜性,在過去的幾十年里,已經創建了許多偉大的工具。但是,我們單獨使用工具的能力是有限的。如果我們想讓編寫軟件變得更容易,這樣我們就可以以更低的成本,構建更強大的系統,我們必須找到使軟件更簡單的方法。盡管我們盡了最大的努力,復雜性仍然會隨着時間的推移而增加,但是更簡單的設計允許我們在復雜性變得不可抗拒之前構建更大、更強大的系統。
有兩種對付復雜性的一般方法,這兩種方法都將在本書中討論。第一種方法是通過使代碼更簡單、更明顯來消除復雜性。 例如,可以通過消除特殊情況或以一致的方式使用標識符來降低復雜性。
處理復雜性的第二種方法是封裝它,這樣程序員就可以在一個系統上工作,而不必一次暴露系統的所有復雜性。這種方法稱為模塊化設計。 在模塊化設計中,軟件系統被分成模塊,如面向對象語言中的類。這些模塊被設計成相對獨立的,這樣程序員就可以在一個模塊上工作,而不必了解其他模塊的細節。
由於軟件的可塑性很強,軟件設計是一個持續的過程,它跨越了軟件系統的整個生命周期;這使得軟件設計不同於建築物、船只或橋梁等物理系統的設計。然而,人們並不總是這樣看待軟件設計。在編程的大部分歷史中,設計集中在項目的開始階段,就像在其他工程學科中一樣。這種方法的最極端被稱為瀑布模型,在該模型中,項目被划分為離散的階段,如需求定義、設計、編碼、測試和維護。在瀑布模型中,每個階段在下一個階段開始之前完成;在許多情況下,每個階段由不同的人負責。在設計階段,整個系統同時被設計。設計在此階段的末尾被凍結,隨后階段的作用是充實和實現該設計。
不幸的是,瀑布模型很少適用於軟件。軟件系統本質上比物理系統更復雜;在構建任何東西之前,不可能很好地可視化大型軟件系統的設計以理解它的所有含義。因此,最初的設計將會有很多問題。在實施順利進行之前,問題不會變得明顯。然而,瀑布模型的結構並不能適應此時的主要設計更改(例如,設計人員可能已經轉移到其他項目)。因此,開發人員試圖在不改變整體設計的情況下修補問題。這導致了復雜性的爆炸。
由於這些問題,現在大多數軟件開發項目都使用增量的方法,比如敏捷開發,在這種方法中,最初的設計集中在整體功能的一個小子集上。設計、實現並評估這個子集。發現並糾正原始設計中的問題,然后再設計、實現和評估其他一些特性。每次迭代都暴露了現有設計的問題,這些問題在設計下一組特性之前得到了修復。通過以這種方式展開設計,可以在系統仍然很小的時候解決初始設計的問題;后期的特性受益於在早期特性實現過程中獲得的經驗,因此它們的問題更少。
增量方法適用於軟件,因為軟件具有足夠的延展性,允許在實現過程中進行重大的設計更改。相比之下,對於物理系統來說,主要的設計變化更具挑戰性:例如,在建造過程中改變支撐一座橋的塔的數量是不現實的。
增量開發意味着軟件設計永遠不會完成。設計在系統的生命周期中不斷發生:開發人員應該始終考慮設計問題。增量式開發還意味着持續的重新設計。 一個系統或組件的最初設計幾乎從來都不是最好的;經驗不可避免地顯示出更好的做事方法。作為一名軟件開發人員,您應該始終尋找機會來改進您正在處理的系統的設計,並且您應該計划將一部分時間花在設計改進上。
如果軟件開發人員應該始終考慮設計問題,並且減少復雜性是軟件設計中最重要的元素,那么軟件開發人員應該始終考慮復雜性。 這本書是關於如何使用復雜性來指導整個軟件生命周期的設計。
這本書有兩個總體目標。首先是描述軟件復雜性的本質:“復雜性”是什么意思,為什么它很重要,以及如何識別一個程序何時具有不必要的復雜性?本書的第二個,也是更具挑戰性的目標是介紹你可以在軟件開發過程中使用的技術,以最小化復雜性。不幸的是,沒有一個簡單的方法可以保證優秀的軟件設計。相反,我將展示一組與哲學相關的高級概念,比如“類應該是深度的”或“定義不存在的錯誤”。這些概念可能不能立即確定最佳的設計,但是您可以使用它們來比較設計方案並指導您對設計空間的探索。
1.1 如何使用這本書
這里描述的許多設計原則有些抽象,因此如果不查看實際代碼,可能很難理解它們。要找到足夠小到可以包含在書中,但又足夠大到可以用實際系統說明問題的示例是一個挑戰(如果您遇到好的示例,請將它們發送給我)。因此,這本書本身可能不足以讓你學會如何應用這些原則。
使用這本書的最佳方法是結合代碼評審。 當您閱讀其他人的代碼時,請考慮它是否符合這里討論的概念,以及它如何與代碼的復雜性相關。別人的代碼比你自己的代碼更容易發現設計問題。您可以使用這里描述的危險信號來識別問題並提出改進建議。審查代碼還將使您了解新的設計方法和編程技術。
提高您的設計技能的最佳方法之一是學會識別危險信號:一段代碼可能比它需要的更復雜的信號。 在這本書的過程中,我將指出與每個主要設計問題相關的問題的危險信號;最重要的在書的后面有總結。然后您可以在編碼時使用它們:當您看到一個危險信號時,停止並尋找一個可以消除問題的替代設計。 當你第一次嘗試這種方法時,您可能必須嘗試幾個設計備選方案,然后才能找到消除危險信號的方案。不要輕易放棄:你在解決問題之前嘗試的選擇越多,你學到的就越多。隨着時間的推移,你會發現你的代碼越來越少的危險信號,你的設計也越來越干凈。您的經驗還將向您展示其他可以用來識別設計問題的危險信號(我很高興聽到這些)。
在應用本書的觀點時,重要的是要適度和謹慎。任何規則都有例外,任何原則都有限度。如果你把任何設計理念發揮到極致,你可能會陷入一個糟糕的境地。漂亮的設計反映了相互競爭的思想和方法之間的平衡。有幾個章節的標題是“做得太過了”,描述了當你做了一件好事時如何識別它。
這本書中幾乎所有的例子都是用Java或C++編寫的,大部分討論都是關於用面向對象的語言設計類。然而,這些想法也適用於其他領域。幾乎所有與方法相關的思想都可以應用於沒有面向對象特性的語言中的函數,如c。設計思想也適用於類以外的模塊,如子系統或網絡服務。
在此背景下,讓我們更詳細地討論導致復雜性的原因,以及如何簡化軟件系統。
免責聲明:本翻譯內容僅供學習使用,版權歸英文原作者或出版方所有,若有侵權,請聯系刪除。