敏捷與結構性模塊化(一)
1 簡介
敏捷開發方法論日益流行,然而大多數“敏捷”專家和分析師都在孤立地討論敏捷,也就是說忽視了系統“結構”(Kirk Knoernschild是一個例外,他編寫了一本名為《Java Application Architecture》的圖書闡述這一理念)??紤]到“敏捷”是基礎實體的一個重要特性或屬性,那么,這種疏忽令人感到很驚訝。一個實體要具有“敏捷”的特性,它必須具有高度的結構性模塊化(structural modularity)特征(參見Scott Page的《Diversity & Complexity》)。
也許正因為這種疏忽,許多組織在敏捷開發流程方面進行投入但忽略了應用程序的結構。除了“如何實現一個敏捷的系統?”這個問題以外, 有人肯定還會問, “如何構建一個在結構上具備高度模塊化的系統?”
這個系列的文章將從探討結構性模塊化和敏捷之間的關系開始。
2 結構、模塊化與敏捷
業務主管和應用開發人員經常面臨相同的挑戰。無論是商業領域還是服務于商業的軟件,它都必須在成本范圍內構建和維護。如果要保持實體的持續運營,就必須能夠以低成本的方式快速響應難以預料的變化。
如果我們希望高效地管理一個系統,就必須先理解該系統。只有理解了系統,可控制的變更和定向升級才能成為可能。
當然,我們并不需要理解系統的每個組成部分的詳細情況和特性,只需要理解所負責的系統的相關參數以及相應等級層次的行為即可。
隱藏服務實現
從外部角度來看,我們僅僅關心系統暴露的行為、提供的服務類型以及該服務的屬性。例如,服務可靠嗎?與替代方案相比有競爭力嗎?
圖1:服務的使用者
作為服務的使用者,我們并不關心服務的特性是如何實現的,我們只關心所提供的功能(Capability)是否可以滿足我們的需求(Requirement)。
理解結構以便管理
不同于使用者,服務的實現方式對于服務的提供者而言,是極為重要的。為了更好的理解,我們為負責提供服務的系統建立概念模型,這是通過將系統分解成一組更小的相互關聯的單元實現的。如果這個實體是某個公司,這張組件圖就代表了“組織結構圖(Organization Chart’)”;如果這個實體是軟件應用程序,那么這張圖就是模塊間依賴關系的映射圖。
嘗試理解抽象系統的第一步如下圖所示。
圖2: 服務提供者和系統維護者
從上圖的例子,我們可以馬上知道:
- 系統由15個組件組成。
- 每個組件的名稱。
- 這些模塊間的依賴,盡管我們無法知道這些依賴為何存在。
- 盡管我們并不知道每個組件各自所承擔的責任,從關聯性出發,我們依然可以推斷出“Tom”模塊在系統中所占據的地位很有可能比“Dick”模塊更為重要。
需要注意的是,這些組件可能并不是我們所創建的,我們也不必理解這些組件之間的內在結構。就像作為服務的使用者,只需關心服務所提供的功能,我們作為組件的使用者,只是需要它們的功能。
需求和功能(Requirements & Capabilities)
到目前為止,我們僅僅知道組件之間存在依賴性,并不知道為什么會存在這些依賴性。另外目前的狀態是與時間無關的。如果隨著時間的推移,發生了變化又該怎樣呢?
最初我們可能會借助于實體的名字,再加上版本號(version)或者版本范圍(version range),結構的變化由版本的變化體現出來。然而,如圖3所示,版本名稱(versioned name)盡管表明了系統的改變,但卻無法解釋為什么Susan 2.0不能像Susan 1.0那樣與Tom 2.1一起協同工作。
這是為什么呢?
圖3:如何跟蹤結構隨時間的變化?系統以前能夠正確運行,后來由于一個組件的升級導致整個系統出錯。為什么呢?
只有當我們仔細研究系統的功能和需求后,才能了解問題的原因。Tom 2.1需要管理者(Manager)的功能,這個功能在Susan 1.0中提供。然而稍后的Susan 2.0,由于她的職業規劃,決定進行再培訓,這時的Susan 2.0被賦予了新的Plumber 1.0功能,也就意味著其不再擁有管理者的功能了。
這個簡單的例子向我們展示了模塊間的依賴關系需要由需求和功能來表達,而不是它們的名字(Apache Maven項目最近正在討論為制件的名字采用版本范圍。盡管這是一個進步,但依然有缺陷,因為依賴還是用實體的名字來進行描述。)。這些描述應當能顯示模塊的本質,即模塊應當能自我描述(需求、功能以及依賴應該進行文檔化,但是隨著時間的推移,這些描述會變得過時,如最初的文檔制定之后,系統又發生了變化,而文檔并沒有得到更新。)。
圖4:組織化結構:按照功能、需求的術語以及語義化的版本來進行定義
如圖所示,我們完全可以不引用具體實體的名字,而直接使用需求和功能來描述一個系統
系統演化和語義化版本的角色
目前,功能與需求是我們了解系統結構的主要途徑。然而,要理解時間推移所帶來的變化,我們依然還會遇到問題。
- 在組織結構圖中,如果某個員工晉升了,那么原有的關聯性是否依舊有效(功能增強)?
- 在一組互相關聯的軟件組件中,如果我們重構了其中的一個模塊(可能改變其公開接口),原有的依賴是否依然有效?
通過簡單的版本化,我們可以觀察到系統所發生的變化,卻無法了解這些變化所帶來的影響。然而,如果采用語義化版本命名方式(見http://www.osgi.org/wiki/uploads/Links/SemanticVersioning.pdf),我們就能夠傳達系統變化而帶來的潛在影響。
這可以通過以下的方式實現:
- 將功能根據major.minor.micro 的版本模式來進行版本化。同時我們達成共識,minor 或 micro這兩個版本域代表非破壞性的變化(non-breaking change)。例如,2.7.1?2.8.7。相反,major版本域的變化,例如,2.7.1?3.0.0表示有破壞性的變化(breaking change),組件的改變可能影響到它的使用者。
- 需求則使用可接受的功能的版本范圍來表示。方括號“[”和“]”表示包含此值,而圓括號“(”和“)”表示不含此值。因此,范圍[2.7.1,3.0.0) 表示任何版本高于或等于2.7.1并且低于3.0.0(不含3.0.0)的功能都是可接受的
使用這種方式,我們可以看到如果Helen代替了Joe,Tom的需求依然會得到滿足。然而,同樣有管理者功能的Harry卻因為其功能仍是1.7版本,不在Tom的[2,3)需求范圍內,所以無法進行替換。
通過使用語義化版本的命名方式可以表達系統變更所帶來的影響。再加上需求和功能,我們具備了足夠信息,能夠保證在滿足系統各部分依賴的前提下,進行模塊的替換。
我們的工作到此告一段落,這樣簡單的系統是敏捷且易維護的!
敏捷——從上至下貫穿各層
最后的挑戰與復雜性息息相關。試想如果下列情況出現時會發生什么:1)系統的規模和難度不斷增長?2)系統的模塊數量大幅增加,并且模塊間的互相依賴性也大幅增加?有些讀者在前面的例子中,可能已經注意到出現了某種程度的自相似性(self-similarity),你們或許已經從中猜到了答案。
服務的使用者選擇我們的服務是因為服務所宣稱的功能符合它們的需求(見圖1)。而提供服務的系統的實現方式,對服務的使用者而言是不可見的。向下的每一層都沿用這一模式。系統的結構自然而然地根據各組件的功能和需求進行描述。(見圖4)。這時組件的內部結構對于系統而言是不可見的。如圖5所示,許多邏輯層都可能使用這種模式。
圖5:敏捷的結構:每層只暴露必要的信息。每層都是由組件間的依賴所組成的,這些依賴通過需求和功能來進行表述。
所有真正敏捷的系統都是以分層的層級結構建立起來的。在每個結構化的層次中,各組件的自描述都遵循以下的規則:只描述當前層次的有關信息,關于更低層次的不必要細節是不會描述的。
這種模式不斷出現于自然系統和人造系統中。自然生態系統中所構建的大量結構都是由嵌套的模塊化組件所組成的。例如:
這項進程起源于20世紀90年代中后期,許多公司開始采用包括面向服務架構(Service Oriented Architecture,SOA)和企業服務總線(Enterprise Service Buses ,ESB’s)為代表的粗粒度模塊化技術。商業程序通過已知的服務接口或消息傳遞的方式,較為寬松地聯系在一起。SOA提倡更加“敏捷”的IT環境,即商業系統應該更加易于升級或替換。
然而在許多實際場景中,核心的應用程序一直沒有更改。很多現有的程序只是簡單地將接口暴露為SOA服務。從這一角度來看,SOA實質上并不能如其保證的那樣節省開支和使商業快速化:http://apsblog.burtongroup.com/2009/01/soa-is-dead-long-live-services.html。
這是因為內部缺乏模塊化,加入SOA之后的程序和沒加之前一樣難以修改
變得敏捷?
我們將在此章節,對目前為止的觀點進行小結。
為了“敏捷”,系統必須符合以下的特性:
- 層級化的結構(Hierarchical Structure):系統必須層級化,每一層由更低一層的組件構成。
- 隔離性(Isolation):對于每個結構化的層級,高度的隔離性確保參與運行的組件的內部結構將是不可見的。
- 抽象化(Abstraction):對于每一層,參與運行的組件的行為通過需求和功能加以表達。
- 自描述(Self-Describing):在每層之中,參與運行的模塊間的關系都必須是自描述的。也就是說,依賴性定義將通過需求和功能進行表達。
- 變化的影響(Impact of Change):通過語義化的版本命名,變化對依賴的影響可以進行表述。
系統按上述原則建立,將是:
- 易于理解的(Understandable):基于層級化的結構,系統在每一層的結構都易于理解。
- 高適應性的(Adaptable):在每一層中,結構性模塊化保證了變更的影響可以局限在那些相關的模塊內部,高度模塊化所建立起來的邊界能夠保護系統的其他部分不受影響。
- 可演化的(Evolvable):每層中的組件都可以被代替。因此,系統可以支持多樣化(diversity)并且是可演化的。
系統可以通過結構性模塊化來實現敏捷。
在這個系列的下一部分,我們將會討論OSGi?——Java?的模塊化框架——如何滿足結構性模塊化的需求,從而為流行的敏捷方法學奠定基礎,最終形成敏捷的企業。
原文英文地址:Agility and Structural Modularity – part I
作者簡介
Richard Nicholson是Paremus 的CEO和創始人,這是一個2001年成立的軟件公司,總部位于英國。
在意識到高度可維護以及高度敏捷的系統在本質上必須是高度模塊化的之后,Paremus在2004年開始研究下一代的軟件系統。這種持續的努力體現在了Paremus Service Fabric產品之中,這是一個高度可適應的、基于OSGi的自裝配運行時,可用于企業級和云環境。作為OSGi聯盟的主席(2010-2012),Richard開始推進OSGi Cloud并鼓勵OSGi聯盟參與到敏捷軟件社區中。
Richard在很多的研究領域都保持了濃厚的興趣,這支撐了Service Fabric的研發,他的研究領域包括復雜的適應性系統(Complex Adaptive System)以及敏捷(Agility)、模塊化組裝(Modular Assembly)、結構化多樣性(Structural Diversity)和適應性(Adaption)之間的關系。
成立Paremus之前,Richard在花旗集團/Salomon Smith Barney,領導著歐洲系統工程(European System Engineering)相關的工作。Richard獲得了曼切斯特大學的物理學榮譽學位,并在格林尼治皇家天文臺( Royal Greenwich Observatory)獲得天體學物理博士。
Richard的博客:http://adaptevolve.paremus.com。
Paremus的博客:http://blogs.paremus.com。
轉自:http://www.infoq.com/cn/articles/agile-and-structural-modularity-part1
- 目前還沒評論,等你發揮!