走在架構師的大道上 Jack.Wang's home

          Java, C++, linux c, C#.net 技術,軟件架構,領域建模,IT 項目管理 Dict.CN 在線詞典, 英語學習, 在線翻譯

          BlogJava 首頁 新隨筆 聯系 聚合 管理
            195 Posts :: 3 Stories :: 728 Comments :: 0 Trackbacks
          聲明原文地址不詳,分享。

           

          當架構模型進行迭代的過程中,必然伴隨著對模型進行修改和改進。我們如何防止對模型的修改,又如何保證對模型進行正確的改進?

          Context

          架構模型通過精化、合并等活動之后,將會直接用于指導代碼。而這個時候,往往就會暴露出一些問題出來,通常在實際編碼中,發現架構存在或大或小的問題和錯誤,導致編碼活動無法繼續。這時候我們就需要對架構模型進行修改了。而架構設計的過程本身是一個迭代的過程,這就意味著在每一次的迭代周期中,都需要對架構進行改進。

          Problem

          我們如何避免對架構模型進行修改?又如何保證架構進行正確的改進?

          Solution

          我們從XP中借用了一個詞來形容架構模型的修改過程――Refactoring,中文可以譯作重構。這個詞原本是形容對代碼進行修改的。它指的是在不改變代碼外部行為(可觀察行為)的情況下對代碼進行修改。我們把這個詞用在架構模型上,因為經過精化和合并之后的架構模型往往由很多個粗粒度組件構成。這些組件之間存在一定的耦合度(雖然我們可以令耦合度盡可能的低,但是耦合度一定是存在的),任何一個組件的重構行為都會使變化擴散到系統中的其它組件。這取決于被重構的組件和其它組件之間的相對關系。如果被重構的組件屬于層次較低的工具層上,那么這次的修改就可以引起模型很大的變動。

          在精化和合并模式中,我們提到了改變和改進的區別,因此,我們的對策主要分為兩種:如何防止改變的發生,以及,使用重構來改進軟件架構。

          防止改變的發生

          在任何時候,需求的變更總是對架構及軟件有著最大的傷害。而需求變更中最大問題是需求蔓延。很多人都有這樣的感覺,項目完成之后,發現初期的計劃顯得那么陌生。在項目早期對需求進行控制是重要的,但并不是該模式談論的重點。我們更關注在項目中期的需求蔓延問題和晚期的需求控制問題。關于這方面的詳細討論,請參見穩定化模式。在項目中期,尤其是編碼工作已經開始之后,要盡可能避免出現需求蔓延的情況。需求蔓延是經常發生的,可能是因為用戶希望加入額外的功能,或是隨著用戶對軟件了解的加深,發現原有的需求存在一定的不足。完全防止需求蔓延是無法做到的,但是需要對其進行必要的控制。例如,有效的估計變更對開發、測試、文檔、管理、組織等各個方面帶來的影響。

          避免發生改變的另一個有效的辦法是從軟件過程著手。迭代法或漸進交付法都是可用的方法。一個軟件的架構設計往往是相對復雜的,其中涉及到整體結構、具體技術等問題。一次性考慮全部的要素,就很容易發生考慮不周詳的情況。人的腦容量并沒有我們想象的那么大。將架構設計分為多個迭代周期來進展,可以減少單次迭代周期中需要建模的架構數量,因此可以減少錯誤的發生。另一方面,迭代次數的增多的直接結果是時間的延長,此外還有一個潛在的問題,如果由于設計師的失誤,在后期的迭代中出現問題,必然會導致大量的返工。因為之前的模型已經實現了。在得與失之間,我們如何找到適當的平衡點呢?

          迭代次數應該根據不同軟件組織的特點來制定,對于初期的迭代周期而言,它的主要任務應該是制定總原則(使用架構愿景模式)、定義層結構和各層的職責(使用分層模式)、解決主要的技術問題上。在這個過程中,可以列出設計中可能會遇到的風險,并根據風險發生的可能性和危害性來排定優先級,指定專人按次序解決這些問題。除此之外,在初期參考前一個項目的經驗,讓團隊進行設計(參見團隊設計模式),這些組織保證也是很重要。初期的迭代過程是防止改變的最重要的活動。

          請注意需求中的非功能需求。如果說功能需求定義了架構設計的目標的話,非功能需求就對如何到達這個目標做出了限制。例如,對于實現一個報表有著多種的操作方法,但是如果用戶希望新系統和舊系統進行有效的融合,那么實現的方式就需要好好的規劃了。請從初期的迭代過程就開始注意非功能需求,因為如果忽略它們,在后期需要花費很大的精力來調整架構模型。試想一下,如果在項目晚期的壓力測試中,發現現有的數據庫訪問方法無法滿足用戶基本的速度要求,那對項目進行將會造成多么大的影響。

          注意架構的穩定性。在精化和合并模式中,我們提到了一些模式,能夠降低不同組件之間的耦合度。并向調用者隱藏具體的實現。接口和實現分離是設計模式最大的特點,請善用這一點。

          盡可能的推延正式文檔的編寫。在設計的初期,修飾模型和編寫文檔通常都沒有太大的意義。因為此時的模型還不穩定,需要不斷的修改。如果這時候開始投入精力開發文檔,這就意味著后續的迭代周期中將會增加一項維護文檔一致性的工作了。而這時候的文檔卻無法發揮出它真正的作用。但是,延遲文檔的編寫并不等于什么都不做,無論什么時候進行設計,都需要隨手記錄設計的思路。這樣在需要的時候,我們就能夠有充分的資料對設計進行文檔化的工作。

          對軟件架構進行重構

          Martin Fowler的Refactoring一書為我們列舉了一系列的對代碼進行重構方法。架構也是類似的。

          重構到模式

          Joshua Kerievsky在《Refactoring to Patterns》一書中這樣描述重構和模式的關系:

          Patterns are a cornerstone of object-oriented design, while test-first programming and merciless refactoring are cornerstones of evolutionary design

          (模式是面向對象設計的基石,而測試優先編程和無情的重構則是設計演進的基石)。作者在文中著重強調了保持適度設計的重要性。

          在作者看來,模式常常扮演著過度設計的角色。而在解決這個問題的同時又利用模式的優點的解決方法是避免在一開始使用模式,而是在設計演進中重構到模式。這種做法非常的有效,因為在初始設計中使用模式的話,你的注意力將會集中到如何使用模式上,而不是集中在如何滿足需求上。這樣就會導致不恰當的設計(過度設計或是設計不充分)。因此,在初始設計中,除非非常有把握(之前有類似的經驗),否則我們應當把精力放在如何滿足需求上。在初始模型完成后(參見精化和合并模式中的例子),我們會對架構進行重構,而隨著迭代的演進,需求的演進,架構也需要演進,這時候也需要重構行為。在這些過程中,如果發現某些部分的設計需要額外的靈活性來滿足需求,那么這時候就需要引入模式了。

          在軟件開發過程中,我們更常的是遇見設計不充分的情況,例如組件之間耦合度過高,業務層向客戶端暴露了過多的方法等等。很多的時候,產生這種現象是由于不切實際的計劃而導致的。開發人員不得不為了最終期限而趕工,所有的時間都花費在新功能上,而完成的軟件則被仍在一邊。這樣產出的軟件是無法保證其質量的。對于這種情況,我們也需要對設計進行重構,當然,合理的計劃是大前提所在。團隊的領導者必須向高層的管理者說明,現在的這種做法只會導致未來的返工,目前的高速開發是以犧牲未來的速度為代價的。因為低劣的設計需要的高成本的維護,這將抵消前期節省的成本。如果軟件團隊需要可持續的發展,那么請避免這種殺雞取卵的行為。

          因此,使用模式來幫助重構行為,以實現恰當的設計。

          測試行為

          重構的前提是測試優先,測試優先是XP中很重要的一項實踐。對于編碼來說,測試優先的過程是先寫測試用例,再編寫代碼來完成通過測試用例(過程細節不只如此,請參看XP的相關書籍)。但是對于架構設計來說,測試行為是發生在設計之后的,即在設計模型完成后,產出相應的測試用例,然后再編碼實現。這時候,測試用例就成為聯系架構設計和編碼活動的紐帶。

          另一方面,在設計進行重構時,相應的測試用例也由很大的可能性發生改變。此時往往會發生需要改變的測試代碼超出普通代碼的情況。避免這種情況一種做法是令你的設計模型的接口和實現相分離,并使測試用例針對接口,而不是實現。在精化和合并模式中,我們提到了一些模式,能夠有助于穩定設計和測試用例。Martin Fowler在他的Application Facade一文中,提到使用Facade模式來分離不同的設計部分,而測試則應當針對facade來進行,其思路也是如此。

          考慮一個用戶轉帳的用例。銀行需要先對用戶進行權限的審核,在審核通過之后才允許進行轉帳(處于簡便起見,圖中忽略了對象的創建過程和調用參數):

          需要分別針對三個類編寫測試用例,設計模型一旦發生變化,測試用例也將需要重新編寫。再考慮下面的一種情況:

          現在的設計引入了TransferFacade對象,這樣我們的測試用例就可以針對TransferFacade來編寫了,而轉帳的業務邏輯是相對比較穩定的。使用這種測試思路的時候,要注意兩點:首先,這并不是說其它的類就不需要測試用例了,這種測試思路僅僅是把測試的重點放在外觀類上,因為任何時候充分的測試都是不可能的。但其它類的測試也是必要的,對于外觀類來說,任何一個業務方法的錯誤都會導致最終的測試失敗。其次,當外觀類的測試無法達到穩定測試用例的效果時,就沒有必要使用外觀類了。

          只針對有需要的設計進行重構。

          任何時候,請確保重構行為僅僅對那些有重構需要的設計。重構需要花費時間和精力,而無用的重構除了增大設計者的虛榮心之外,并不能夠為軟件增加價值。重構的需要來源于兩點:一是需求的變更。目前的設計可能無法滿足新的需求,因此需要重構。二是對設計進行改進,以得到優秀簡潔的設計。除了這兩種情況,我們不應該對設計模型進行重構。

          使用文檔記錄重構的模式。

          應該承認,模式為設計提供了充分的靈活性。而這些設計部分往往都是模型的關鍵之處和難點所在,因此需要對模式進行文檔化的工作,甚至在必要的時候,對這部分的設計進行培訓和指導。確保你的團隊能夠正確的使用文檔來設計、理解、擴展模式。我們在解決方案的前一個部分提到了盡可能延遲文檔的創建。而在設計重構為模式的時候,我們就需要進行文檔化的工作了。因為模式具有靈活性,能夠抵抗一定的變更風險。

          重構并保持模式的一致性

          正如上一節所說的那樣,模式并不是一個很容易理解的東西,雖然它保持了設計的靈活性和穩定性。對于面向對象的新手而言,模式簡直就像是飛碟一樣,由于缺少面向對象的設計經驗,他們無法理解模式的處理思路,在實踐中,我們不只一次的碰到這種情況。我們不得不重頭開始教授關于模式的課程。因此,最后我們在軟件設計采用一定數量的模式,并確保在處理相同問題的時候使用相同的模式。這樣,應用的模式就成為解決某一類的問題的標準做法,從而在一定程度上降低了學習的曲線。

          保持模式的一致性的另一個方面的含義是將模式作為溝通的橋梁。軟件開發是一種團隊的行為。因此溝通在軟件開發中扮演著很重要的角色。試想一下,開發人員在討論軟件設計的時候,只需要說"使用工廠模式",大家就都能夠明白,而不是費勁口舌的說明幾個類之間的關系。這將大大提高溝通的效率。此外,模式的使用和設計的重構對于提高團隊的編程水平,培養后備的設計人員等方面都是很有意義的。





          本博客為學習交流用,凡未注明引用的均為本人作品,轉載請注明出處,如有版權問題請及時通知。由于博客時間倉促,錯誤之處敬請諒解,有任何意見可給我留言,愿共同學習進步。
          posted on 2008-11-16 12:09 Jack.Wang 閱讀(3484) 評論(0)  編輯  收藏 所屬分類: 架構師篇
          主站蜘蛛池模板: 夏津县| 临朐县| 社会| 韩城市| 沅陵县| 温宿县| 固安县| 怀仁县| 静海县| 修水县| 尼木县| 临泉县| 汨罗市| 周至县| 金塔县| 江口县| 普定县| 察雅县| 江达县| 永宁县| 巴中市| 上蔡县| 油尖旺区| 广安市| 光泽县| 吴江市| 馆陶县| 麟游县| 沙洋县| 通化县| 剑河县| 图们市| 枞阳县| 板桥市| 郁南县| 集安市| 祁东县| 河北省| 响水县| 会东县| 安多县|