在單次的迭代開始階段,我們已經(jīng)收集好了單次迭代的需求。 架構(gòu)和分析設(shè)計是密不可分的,有時候很難說得清楚架構(gòu)的定義,但架構(gòu)應(yīng)該能夠描述軟件的整體。架構(gòu)包括了軟件的各個方面,但是每一個設(shè)計細節(jié)總是需要單獨考慮,這時候就會出現(xiàn)設(shè)計細節(jié)之間、以及設(shè)計細節(jié)和架構(gòu)之間的不一致。 架構(gòu)設(shè)計的各個部分之間的設(shè)計沖突是很容易發(fā)生的。發(fā)生的概率及頻率和團隊的規(guī)模成正比、和溝通的頻度及效果成反比。在很多次的項目開發(fā)過程中,我們發(fā)現(xiàn)了多處的相同功能的代碼,原因是代碼的作者并不知道別人已經(jīng)實現(xiàn)了這個功能了。這可能只是浪費了一點精力,可如果不同模塊間的設(shè)計沖突導(dǎo)致了軟件無法正常運行的時候,我們就需要坐下來好好的審視,究竟發(fā)生了什么。 我們需要建立一個架構(gòu)愿景。架構(gòu)愿景應(yīng)該能夠提供軟件全局視圖,包括所有的重要部分,定義了各個部分的責(zé)任和之間的關(guān)系,而且還定義了軟件設(shè)計需要滿足的原則。而這個架構(gòu)愿景的設(shè)計,應(yīng)該是滿足源自需求模式的,也就是說,部分的劃分和部分的設(shè)計,都是根據(jù)需求而進行的。同時,架構(gòu)愿景應(yīng)該要能夠滿足架構(gòu)的其它各種特點,例如簡單、可擴展性、抽象性。簡單來說,我們把架構(gòu)愿景當(dāng)作是一個mini的架構(gòu)設(shè)計。 由于我們是在單次的迭代中討論架構(gòu)愿景,因此從整體上考慮,架構(gòu)愿景是也是在不斷的變化的。這是很自然的,因為架構(gòu)愿景代表了架構(gòu)的設(shè)計,架構(gòu)愿景的演進代表了架構(gòu)設(shè)計的演進。 架構(gòu)的愿景是相對于一個范圍來說的,在一個特定的軟件功能范圍之內(nèi),談架構(gòu)愿景才有實際的意義,例如針對軟件的全局或某個子模塊。在這個特定的范圍中,訂立了架構(gòu)愿景之后,這個范圍內(nèi)的所有設(shè)計原則將不能違背架構(gòu)愿景。這是非常重要的,是架構(gòu)愿景的最大的用處。有了這樣的保證,我們就可以保證設(shè)計的一致性和有效性。任何一項設(shè)計的加入,都能夠融入到原先的架構(gòu)中,使得軟件更加的完善,而不是更加的危險。 當(dāng)然,要做到這一點并不是一件容易的事情。特別需要指出的是,架構(gòu)愿景模式僅僅是實現(xiàn)該目的的一條道路,并不是一個充分條件。如果在設(shè)計中愿景不能夠貫徹其意志,或是愿景制定本身就存在問題,那么要想達到上述的效果,幾乎是不可能的事情。此外,該模式僅僅只是達到該目的的第一步,我們在接下去的模式中會發(fā)現(xiàn)還需要很多方面的配合。 我們根據(jù)架構(gòu)適用范圍的不同,把架構(gòu)愿景分為幾個類別討論: 軟件全局 軟件全局的架構(gòu)是我們所最關(guān)心的,因此也會花費最多的筆墨。 軟件全局中的架構(gòu)愿景一般很難具體化到代碼級別,其實你會發(fā)現(xiàn),就算是具體化到了代碼級別,也會因為實際中存在的問題,導(dǎo)致代碼沒有太多的價值。因此,為軟件全局設(shè)置的架構(gòu)愿景可以以原則、或是模式名的方式體現(xiàn),并用自然語言或偽代碼描述。例如,可以為一個系統(tǒng)規(guī)定三層架構(gòu)作為其愿景,并指出三層的分類原則。注意,我們需要指出分類原則,否則規(guī)定三層架構(gòu)并沒有太大的意義,因為三層架構(gòu)隨著實現(xiàn)平臺的不同、開發(fā)人員的不同而有很大的差異,如果不能夠規(guī)定一個可操作的規(guī)范,那么愿景是沒有意義的。在Java環(huán)境下,我們可以這樣說: "客戶端采用前端瀏覽器界面,業(yè)務(wù)邏輯采用servlet,配合JSP編寫,瀏覽器到服務(wù)器的數(shù)據(jù)采用集中處理,具體的方法是在業(yè)務(wù)邏輯和前端瀏覽器之間采用Front Control模式,接受前端瀏覽器傳送過來的數(shù)據(jù),并指派給相應(yīng)的業(yè)務(wù)邏輯處理。數(shù)據(jù)的合法性檢驗分為兩個部分:和業(yè)務(wù)邏輯無關(guān)的基本合法性驗證在前端使用Java Script處理,和業(yè)務(wù)邏輯相關(guān)的合法性驗證在業(yè)務(wù)邏輯層處理,可以使用一個集中的servlet專門處理錯誤情況。" 而在Windows環(huán)境下,我們知道三層結(jié)構(gòu)的分界和Java中的并不相同(關(guān)于這一點,下一篇的文章中將會有詳細的描述),我們可以在業(yè)務(wù)邏輯層或顯示層直接操縱數(shù)據(jù),非常的方便,因此,在Windows中的架構(gòu)愿景的描述又不一樣。另外,在非面向?qū)ο蟮沫h(huán)境中,在分布式的環(huán)境中,在Lotus Notes的環(huán)境中,其架構(gòu)的描述都不一樣。 注意到,架構(gòu)愿景的制定是根據(jù)不同的應(yīng)用環(huán)境而變化的,這一點我們在文章的一開始就強調(diào)過,這里又出現(xiàn)了相同的問題。我們可以通過一個簡單的例子來加深對這個問題的理解。在Java的環(huán)境下,特別是J2EE的環(huán)境下面,經(jīng)典的設(shè)計思路是把數(shù)據(jù)庫的一張表視作一個類,表中的每一行都是這個類的一個具體的實例,表的每一個字段對應(yīng)了類的一個變量,類一般支持Find方法,來獲取數(shù)據(jù)不同的實例。這是一種很自然的設(shè)計思路,而且可以通過CMP等技術(shù)來簡化設(shè)計的繁瑣步驟??墒?,在Windows環(huán)境下,相信沒有多少人會這么做。常用的處理方法是使用記錄集(RecordSet)的方式,也就是說針對一組的記錄來進行操作,而不是單個的記錄。這些記錄可以是跨表的(使用SQL的連接),也可以是單表的。由于Windows環(huán)境下大多數(shù)的編程語言都能夠支持記錄集方式,因此編寫基于記錄集方式的程序是相當(dāng)簡單的。當(dāng)然,我們也可以采用J2EE平臺的編程方式,但是會導(dǎo)致編程量的激增,同時也難以達到預(yù)計的效果。這種平臺的差別導(dǎo)致了架構(gòu)愿景的差別。 此外,我們注意到我們對架構(gòu)的描述其實還是不夠仔細,這是非常正常的,因為隨著開發(fā)的深入,我們會不斷的完善架構(gòu)的描述。例如,我們可以寫出Front Controll的類框架,寫出主要的幾個Servlet,以及他們之間的關(guān)系。這個時候,使用UML類圖會是一個不錯的選擇,實際上,我非常推崇在架構(gòu)設(shè)計中大量的使用類圖。不過在實際的運作中,每個軟件團隊大多數(shù)都有自己熟悉的架構(gòu)設(shè)計思路,使用何種工具并不是主要的問題。 我們從源自需求模式中,學(xué)習(xí)到架構(gòu)的設(shè)計是來自于需求的,而應(yīng)用于軟件全局的架構(gòu)則來自于最重要的需求。還記得我們在那個模式中提到的網(wǎng)上寵物店的例子嗎?系統(tǒng)采用了MVC模式,sun的官方文檔一開始說明了為什么采用MVC模式,MVC模式解決了什么問題,然后開始分析MVC模式的幾個組成部分:Model、View、和Controll。其實,MVC中的每一個部分,在真正的代碼中,大都代表了一個子系統(tǒng),但是在目前,我們就非常的清楚系統(tǒng)大致上會是一個什么樣子,雖然這時候它還十分的朦朧。 不要視圖在全局的架構(gòu)愿景中就制定出非常細致的規(guī)劃,更不要視圖生成大量的實際代碼。因為,你的架構(gòu)愿景還沒有穩(wěn)定(我們在其后的穩(wěn)定化的模式中將會討論穩(wěn)定的問題),還沒有獲得大家的同意,也沒有經(jīng)過證明。因此,從整個的開發(fā)周期來看,全局架構(gòu)愿景是隨著迭代周期的進行不斷發(fā)展、修改、完善的。 我們?nèi)绾未_定全局架構(gòu)愿景工作的完成?一般來說,你的架構(gòu)設(shè)計團隊取得了一致的意見就可以結(jié)束了,如果問題域是團隊所熟悉的,一兩個小時就能夠解決問題。接下來設(shè)計團隊把架構(gòu)愿景傳播到整個的開發(fā)團隊,大家形成一致的認識,不同的意見將會被反饋會來,并在本次的迭代周期(如果時間比較緊迫)或下一次的迭代周期中(如果時間比較寬松)考慮。 子模塊級、或是子問題級的架構(gòu)愿景 這時候的架構(gòu)愿景已經(jīng)是比較明確的了,因為已經(jīng)存在明確的問題域。例如界面的設(shè)計、領(lǐng)域模型的設(shè)計、持久層的設(shè)計等。這里的愿景制定本質(zhì)上和全局的愿景制定差不多,具體的例子我們也不再舉了。但是要注意一點,你不能夠和全局愿景所違背。在操作上,全局愿景是設(shè)計團隊共同制定出來的,而子模塊級的架構(gòu)愿景就可以分給設(shè)計子團隊來負責(zé),而其審核則還是要設(shè)計團隊的共同參與。這有兩個好處,一是確保各個子模塊(子問題)間不至于相互沖突或出現(xiàn)空白地帶,二是每個子設(shè)計團隊可以從別人那里吸取設(shè)計經(jīng)驗。 在設(shè)計時,同樣我們可以參考其它的資料,例如相關(guān)的模式、或規(guī)范(界面設(shè)計指南)。在一個有開發(fā)經(jīng)驗的團隊,一般都會有開發(fā)技術(shù)的積累,這些也是可供參考的重要資料。 我們在這個層次的愿景中主要談一談子模塊(子問題)間的耦合問題。一般來說,各個子模塊間的耦合程度相對較小,例如一個MIS系統(tǒng)中,采購和銷售模塊的耦合度就比較小,而子問題間的耦合程度就比較大,例如權(quán)限設(shè)計、財務(wù),這些功能將會被每個模塊使用。那么,我們就需要為子模塊(子問題)制定出合同接口(Contact Interface)。合同的意思就是說這個接口是正式的,不能夠隨意的修改,因為這個結(jié)構(gòu)將會被其它的設(shè)計團隊使用,如果修改,將會對其它的團隊產(chǎn)生無法預(yù)計的影響。合同接口的制定、修改都需要設(shè)計團隊的通過。此外,系統(tǒng)中的一些全局性的子問題最好是提到全局愿景中考慮,例如在源自需求模式中提到的信貸帳務(wù)的例子中,我們就把一個利息計算方式的子問題提到了全局愿景中。 代碼級的愿景 嚴格的說這一層次的愿景已經(jīng)不是真正的愿景,而是具體設(shè)計了。但是我們?yōu)榱吮WC對架構(gòu)設(shè)計理解的完整性,還是簡單的討論一下。這一個層次的愿景一般可以使用類圖、接口來表示。但在類圖中,你不需要標記出具體的屬性、操作,你只需要規(guī)定出類的職責(zé)以及類之間的相互關(guān)系就可以了。該層次愿景的審核需要設(shè)計子團隊的通過。 而設(shè)計細分到這個粒度上,執(zhí)行愿景設(shè)計的開發(fā)人員可能就只有一兩個左右。但是比較重要的工作在于問題如何分解和如何歸并。分解主要是從兩個維度來考慮,一個是問題大小維,一個是時間長短維。也就是說,你(設(shè)計子團隊負責(zé)人)需要把問題按大小和解決時間的長短分解為更細的子問題,交給不同的開發(fā)人員。然后再把開發(fā)人員提出的解決方法組合起來。 架構(gòu)愿景的形成的源頭是需求,需要特別指出的是,這里的需求主要是那些針對系統(tǒng)基本面的需求。比如說,系統(tǒng)的特點是一個交互式系統(tǒng),還是一個分布式系統(tǒng)。這些需求將會影響到架構(gòu)愿景的設(shè)計。在收集影響架構(gòu)愿景的各項需求之后,按照需求的重要性來設(shè)計架構(gòu)愿景。 架構(gòu)愿景的設(shè)計并不需要很復(fù)雜的過程,也不需要花費很多的時間。我們已經(jīng)提過,架構(gòu)遠景的主要目的就是為了能夠在開發(fā)團隊中傳播設(shè)計思路,因此,架構(gòu)愿景包括基本的設(shè)計思路和基本的設(shè)計原則。 值得注意的是,架構(gòu)遠景可能會有多種的視角,下文討論了一種設(shè)計模式的視角。但是實際設(shè)計中還可能會基于數(shù)據(jù)庫來設(shè)計架構(gòu)愿景。但在企業(yè)信息系統(tǒng)的設(shè)計中,我推薦使用領(lǐng)域類的設(shè)計,也就是下文中討論的例子。 架構(gòu)愿景設(shè)計好之后,問題的焦點就轉(zhuǎn)到如何傳播架構(gòu)愿景上來,為了達到在開發(fā)團隊中取得統(tǒng)一設(shè)計意圖的效果,可以考慮援引團隊設(shè)計模式。除此之外,針對性的項目前期培訓(xùn)也會是一種有效的做法。 架構(gòu)模式也是一種很好的架構(gòu)愿景設(shè)計思路的來源。隨著對設(shè)計模式的研究的深入,人們發(fā)現(xiàn)其中的一些設(shè)計模式可以擴展、或變化為軟件設(shè)計的基礎(chǔ)。在這個基礎(chǔ)上再實現(xiàn)更多的設(shè)計,這些模式就形成了架構(gòu)模式。當(dāng)然,不同的軟件,它們的架構(gòu)模式也是不一樣的。在《Applying Pattern》一文中,有一個很典型的架構(gòu)愿景的例子: 假設(shè)我們需要設(shè)計分布式的交互式系統(tǒng)。分布式系統(tǒng)和交互式系統(tǒng)都有特定的架構(gòu)模式,前者為Broker模式,后者為MVC模式。首先我們先要根據(jù)系統(tǒng)的特點的重要程度來排列模式的順序。這里假設(shè)需求中分布式特性更重要一些。那么我們首先選擇Broker模式作為架構(gòu)的基本模式: ![]() 再考慮交互式的特點,根據(jù)MVC模式的特點,我們需要從目前的基本架構(gòu)中識別出Model、Controller、以及View。Model和View都很簡單,分別分布在上圖中的Server和Client中。而Controller則有兩種的選擇,假設(shè)這里的Controller部署在客戶端,上圖則演化為下圖: ![]() 這樣,基礎(chǔ)的架構(gòu)愿景就已經(jīng)出現(xiàn)了。如果我們還有更多的需求,還可以繼續(xù)改進。但是,記住一點,架構(gòu)愿景不要過于復(fù)雜。 正如我們在上一節(jié)中所討論的,這里我們雖然是基于設(shè)計模式來討論架構(gòu)愿景,但是實際中還有很多從其它的視角來看待架構(gòu)愿景的。至于要如何選擇架構(gòu)愿景的視角,關(guān)鍵的還是在于需求的理解。 林星,辰訊軟件工作室項目管理組資深項目經(jīng)理,有多年項目實施經(jīng)驗。辰訊軟件工作室致力于先進軟件思想、軟件技術(shù)的應(yīng)用,主要的研究方向在于軟件過程思想、Linux集群技術(shù)、OO技術(shù)和軟件工廠模式。您可以通過電子郵件 iamlinx@21cn.com和他聯(lián)系。 |
|
來自: just_person > 《敏捷思維》