原文:https://herbertograca.com/2017/07/05/software-architecture-premises/
這篇文章是軟件架構(gòu)編年史(譯)的一部分,這部編年史由一系列關(guān)于軟件架構(gòu)的文章組成。在這一系列文章中,我將寫下我對軟件架構(gòu)的學(xué)習(xí)和思考,以及我是如何運用這些知識的。如果你閱讀了這個系列中之前的文章,本篇文章的的內(nèi)容將更有意義。
在這篇文章中,我將總結(jié)一些關(guān)于軟件架構(gòu)的最基本的概念,了解它們才能更好地理解后續(xù)的文章。
沒有銀彈
無論你如何理解我在軟件架構(gòu)編年史(譯)中談到的內(nèi)容,首先要理解的是沒有銀彈,沒有“普適性”的解決方案。盡可能地了解不同的方法,理解每一種方法的優(yōu)劣,和它們解決的特定技術(shù)問題。
然后,當(dāng)接受新的挑戰(zhàn)時,先從理解業(yè)務(wù)和最終用戶的需求開始。在搞清楚這些需求之后,你才能思考應(yīng)該采用哪些架構(gòu)風(fēng)格和模式來更好地解決這些問題。
最后,自己做出選擇,是實現(xiàn)一種已知的解決方案,還是創(chuàng)造適合自己的特定問題的獨特設(shè)計。
有些架構(gòu)風(fēng)格號稱是所有形式的軟件的“銀彈”。然而,優(yōu)秀的設(shè)計這應(yīng)該選擇最符合解決特定問題需要的風(fēng)格?!猂oy Fielding, 2000 [1]
術(shù)語
在軟件開發(fā)的世界中使用的術(shù)語很多都模棱兩可,因此,我必須澄清一些我使用的術(shù)語的含義,然后繼續(xù)。
功能性(Functional)
在應(yīng)用中純粹發(fā)揮技術(shù)作用的代碼片段、方法、類、類的組合。它們和(業(yè)務(wù))領(lǐng)域無關(guān),僅僅代表應(yīng)用中的一種技術(shù)能力。例如:
- 層次(Layer)
- 工廠(Factory)
- 資源庫(Repository)
- 值對象(Value Object)
- 視圖(View)
- 視圖模型(ViewModel)
概念性(Conceptual)
在應(yīng)用中標(biāo)識一個(業(yè)務(wù))領(lǐng)域概念的代碼片段、方法、類、類的組合。它們和領(lǐng)域相關(guān),代表應(yīng)用中的一種業(yè)務(wù)能力。例如:
- 用戶
- 產(chǎn)品
- 庫存管理
- 產(chǎn)品變體
- 結(jié)帳
- 銷售
這種劃分并不是說一個代碼單元不能同時具備兩種能力(功能性和概念性)。例如,“Money”對象可以表示一個領(lǐng)域概念,同時也被設(shè)計成一個值對象。如果我把它當(dāng)成領(lǐng)域概念,我指的就是領(lǐng)域內(nèi)的金錢概念,但如果我涉及的是這個類中的功能性方面時,我指的就是值對象的技術(shù)特性(沒有ID、可以是不變的等等)。
包(Package)
劃分在一起的類組成的集合,理想情況下遵循一組規(guī)則進(jìn)行劃分。
模塊(Module)
我使用Software Architecture in Practice[7]給出的定義,模塊就是一個功能性包,它體現(xiàn)了應(yīng)用中的一種技術(shù)能力。它是解耦的并且能夠被其他的實現(xiàn)替換。我的理解是,模塊即存在與較低的粒度級別,比如,“安全模塊”或者“ORM”,也可以存在于像客戶端和服務(wù)器這樣的應(yīng)用塊。模塊提供的是功能性內(nèi)聚。
組件(Component)
我使用Software Architecture in Practice[7]給出的定義,作者將組件定義為一個代表業(yè)務(wù)能力的概念性包。理想情況下,它也是和其他組件和模塊解耦的。例如“用戶”、“產(chǎn)品”或“結(jié)帳”。
然而,最重要的是要記住,理想情況下,它代表了一個限界上下文(Bounded Context)。組件提供了概念性內(nèi)聚。
應(yīng)用(Application)
我將面向用戶的代碼即 UI 視為應(yīng)用,它建立在組件之上。例如,我們可以基于一組組件構(gòu)建網(wǎng)絡(luò)商店。不管怎樣,這個網(wǎng)絡(luò)商店會提供一個(店面) UI 讓用戶瀏覽和購買商品和另一個(管理) UI 讓商店管理員管理商品、庫存、支付供應(yīng)商,等等。這是在同樣的業(yè)務(wù)組件之上構(gòu)建的兩個獨立的應(yīng)用。
系統(tǒng)(System)
我認(rèn)為系統(tǒng)是一組以某種方式在一起工作,為各種企業(yè)必需品提供功能,形成一個企業(yè)范圍內(nèi)的系統(tǒng),即企業(yè)應(yīng)用。這些應(yīng)用可能構(gòu)建在相同或不同的組件上。在之前網(wǎng)絡(luò)商店的例子中,系統(tǒng)就是作為一個整體的網(wǎng)絡(luò)商店,包括兩個基于同樣業(yè)務(wù)組件構(gòu)建的兩個應(yīng)用(店面和管理),還有其他像支付供應(yīng)商或貨運供應(yīng)商這樣的第三方應(yīng)用。
架構(gòu)(Architecture)
軟件架構(gòu)的簡單定義有很多,我覺得都不錯,但我認(rèn)為理解它是什么很簡單,而更重要的是,定義架構(gòu)的產(chǎn)出,它應(yīng)該給項目帶來什么。
軟件架構(gòu)[…]是系統(tǒng)需要考慮的一組結(jié)構(gòu),它們包括軟件元素和它們之間的關(guān)系,以及這些元素和關(guān)系的屬性?!?Clements et al, 2010 [6]
下面是我考慮架構(gòu)的方面:
- 橫跨所有特性開發(fā)的技術(shù)決策,例如,框架、代碼標(biāo)準(zhǔn)、文檔、流程,...;
- 這是存在于項目中的一組很難在后期改變的技術(shù)決策 [3];
- 它是系統(tǒng)的全景圖[5]:pp.2,粗略的描繪,結(jié)構(gòu),組件及其關(guān)系[4] [6];
- 它使項目做好變化的準(zhǔn)備[5]:pp.30,常常是將決策推遲到最后允許的時刻[5]:pp.32;
- 它讓項目做好重用組件和模塊的準(zhǔn)備[7]:pp.29–35;
- 它制定出結(jié)果的一致性標(biāo)準(zhǔn)并建立輕量的流程,比如編碼規(guī)范、開發(fā)階段、持續(xù)交付和持續(xù)部署;
- 它不是某一個人的職責(zé),而是由來自項目中不同特性團(tuán)隊的開發(fā)者組成的行會的職責(zé)。
如果你不熟悉行會的概念,可以觀看下面關(guān)于Spotify 工程師文化的視頻:
架構(gòu)師(Architect)
他是由行會討論和決定的架構(gòu)的發(fā)起人和守護(hù)者。他是部門/團(tuán)隊中經(jīng)驗最豐富的開發(fā)者之一,恰好承擔(dān)著分析高層次問題和解決方案的額外職責(zé)。在做出架構(gòu)決策時,他還擁有“質(zhì)量票”(He also benefits from a “quality vote” when making an architectural decision.)。
可是,有一點值得注意,所有開發(fā)者某種程度上都是架構(gòu)師,因為他們都要了解架構(gòu),他們都會議某種形式參與架構(gòu),他們都適當(dāng)?shù)爻袚?dān)著維護(hù)架構(gòu)的職責(zé)。
象牙塔架構(gòu)師(Ivory Tower Architect)
有一種架構(gòu)師會做出和架構(gòu)有關(guān)的所有決定,這種萬能的象牙塔架構(gòu)師是一種架構(gòu)師的反模式。他對其他干系人對架構(gòu)的貢獻(xiàn)既不開放,也不輕易接收,而是閹割了這些貢獻(xiàn)。
Smells of a bad Architecture (and bad code) [8]
僵化(Rigidity)
如果軟件難以修改是因為修改會導(dǎo)致更多關(guān)聯(lián)修改,軟件就是僵化的。它就會變成兔子洞:當(dāng)我們以為修改快要完成時,突然發(fā)現(xiàn)還有更多的代碼需要修改,把我們拉進(jìn)無止盡的輪回之中。
脆弱(Fragility)
脆弱的軟件在修改時,總會出現(xiàn)意料之外的、毫無關(guān)聯(lián)的、無法預(yù)測的錯誤。
牢固(Immobility)
如果設(shè)計包含一些可以在其它系統(tǒng)中使用的部分,但將這些部分從原系統(tǒng)中分離出來需要大量工作甚至帶來許多風(fēng)險,我們就說設(shè)計是牢固的。
粘滯(Viscosity)
在一個粘滯的系統(tǒng)中,要做對困難重重,要做錯卻輕而易舉。這意味著通過正常開發(fā)實現(xiàn)變更不如用非常手段來得容易。
如果執(zhí)行單元測試和/或編譯需要耗費很長時間,開發(fā)很可能導(dǎo)跳過這些過程,不跑任何自動化測試就實現(xiàn)非常規(guī)的修改,這就是系統(tǒng)范圍的粘滯。
不必要的重復(fù)(Needless repetition)
當(dāng)時間不夠或經(jīng)驗不足導(dǎo)致必要的抽象缺失時,就會產(chǎn)生不必要的重復(fù)。這些代碼也許并不是直接復(fù)制粘貼造成的重復(fù),而是由在不同地方重復(fù)定義的相同業(yè)務(wù)規(guī)則帶來的。
晦澀(Opacity)
代碼寫得混亂,難以理解,我們需要深人方法實現(xiàn)的細(xì)節(jié)才能搞清楚代碼要干什么。
不必要的復(fù)雜(Needless complexity)
開發(fā)者采用了多種不同的抽象和未來潛在變化的應(yīng)對措施,來積極地避免其他六種壞味道。良好的軟件設(shè)計是輕量靈活的,理解起來更容易,最重要的是修改更容易,因此不必預(yù)判所有未來的潛在變化。
引用來源
[1] 2000 – Roy Fielding – Architectural Styles and the Design of Network-based Software Architectures
[2] 2000 – Robert C. Martin – Design Principles and Design Patterns
[3] 2006 – Booch, in [5 pg.2]
[4] 2007 – IEEE1471 in [5 pg.2]
[5] 2010 – James Coplien, Gertrud Bjornvig – Lean Architecture
[6] 2010 – Paul Clements, Felix Bachmann, Len Bass – Documenting Software Architectures
[7] 2012 – Len Bass, Paul Clements, Rick Kazman – Software Architecture in Practice
[8] 2014 – M. H. Jongerius – THE SEVEN DESIGN SMELLS OF ROTTING SOFTWARE
[9] 2017* – Wikipedia – Software Architecture