對擴展性的思考

可擴展性(Extensibility): 構建靈活系統的思考
系統, 構建, 思考
從我理解,在軟件範疇上,是軟件系統本身的屬性,

或 者進一步說是設計的屬性,代碼的屬性。因爲我們經常說設計的可擴展性,代碼的可擴展性。那與之相對應的是什麼呢?是變化,軟件環境的 變化(可能是業務環境,運行環境)導致軟件要進行改動才能滿足人們對它的要求,這種系統本身適應變化的能力就是可擴展性。
      首先讓我們來看看目前系統被擴展的幾種形式:
     1)直接修改代碼。
     相信大家都有過這樣的經歷,當需求改變或者增加新需求的時候。我們可能會修改多個類文件,可能 還涉及配置文件,前臺頁面文件。這種改動,肯定要引起重新編譯,打包和部署,肯定是需要停機的。這種改動涉及的面積廣,需要預先經過 很細緻的分析,改完之後需要面積很大的迴歸測試以保證修改不會引入新的問題。
     2)直接修改代碼,但只侷限在一個類或方法中。
     這種雖然也是直接修改代碼,但改動的範圍受到了限制,對系統其它部分的影響也不是那麼大了,分析起來相對容易。需要進行迴歸測試的 範圍也比上面的做法小。依然需要重新編譯,打包和部署。
    3)利用繼承,編寫子類繼承以後的類,在子類裏添加新的業務邏輯。
     這種做法,沒有修改以前的任何業務邏輯代碼,而 是增加了新的類來容納新的業務邏輯。但是,在將新的類鏈接到代碼中,同樣需要改動部分代碼。比如對新類的實例化過程是需要靜態編譯鏈 接的。
    有人說用工廠方法,簡單工廠不行,FactoryMethod也不行,都達不到消除實例化新類的代碼。
    4)運行時對象裝配。 接下來,大家可能想到了,那就是將類的實例化邏輯移到運行時,通過反射,來進行裝配,這確實解決了第3)種問題。Spring 目前做的主要就是這些事情。到這個時候才真正滿足開閉原則。 Spring給我們提供了一個非常靈活擴展的基礎技術架構。關於這個, 可以看看Martin Fowler關於依賴注入 的文章。
    5)基於模塊的運行時動態擴展。 到現在爲止,我們討論的都是比較細粒度的在技術上的擴展。想象一下,如果增加一些功能,就去繼承各種 各樣的類,然後經過複雜的裝配過程,才能完成一個功能的添加和改進。即使你新增加了類,改動了Spring的配置文件,實 現新的裝配,但仍然有一點,你需要編譯整個項目。也就是說,前四種都沒有達到模塊級別的擴展。
      OSGi給出瞭解決方案,可以實現模塊級別的動態擴展,而且是運行時的。所謂運行時模塊的動態擴展,比如說你需要增加一些新的功能,你 可以將新開發的類和文件按照Bundle進行組織,然後直接扔到運行時環境下,這些功能就可以用了。
      Eclipse的插件體系結構就是以equinox(一個OSGi規範的實現)爲核心構建的。它裏面提到了擴展/擴展點 的概念,這是一個遠比前面四種解決方案更靈活的解決方案,而且與4)相比,實現了關注點的分離。舉個例子:
      比如說我開發了一個上傳文件的功能,上傳文件類型和上傳的地址可以動態進行擴展。
     Spring處理方式:在 bean配置裏靈活配置上傳類型和上傳地址,每增加一個地址或文件類型,都要對該配置文件進行修改。更可怕的是,張三開發了這個文件 上傳模塊,開發別的模塊的李四如果要用這個功能,需要和張三溝通,要麼自己去改配置文件,要麼要請求張三添加自己的文件上傳路徑。當 系統規模增大,改動次數增加,這種複雜性幾乎是不能管理的,需要非常大的成本。
     Eclipse的實現方式:張三開發了一個文件上傳插件,裏面暴露出兩個擴展點,一個是文件類型,一個是文件上傳地址。
李四 甚至不用和張三打招呼,自行開發兩個擴展,並註冊到擴展點上。張三在運行時收集擴展,進行處理。實現了功能使用和功能定義的關注點分 離。大家只要遵守擴展的契約就行了。
     6)基於中間語言。 框架通常定義了一些Hotspot(熱點),在這些點上,可 以進行擴展。平臺,可擴展性是最強的,比如window 平臺,你可以開發應用程序運行在上面。windows提供了幾千個API,你 可以使用他們來開發應用程序。我們在看看Firefox,他可以從主題,插件,擴展來擴充。我們常接觸的擴展,也叫 Extension可以通過XUL,XBL,Javascript,CSS來進行開發。從思路上看,他和 windows的做法是一樣的,都 是通過中間的某種特殊的語言來進行擴展,只不過Windows支持的語言更多一點罷了。由此推斷,從技術上來說,要獲得最大的可擴展 性,就要通過一種或多種中間語言來進行擴展。比如現在流行的OpenSocial API和Facebook都是這個思路。這樣說來,DSL的出現就是順理成章的了,它是爲了滿足在某個業務領域的擴展而設計的。思 路還是和前面說的一樣。說白了,就是順序,選擇和循環可以表達所有邏輯,這是證明過的,這是語言能夠帶來靈活性的本質。

     到目前爲止,從技術層面講,這應該是最靈活的方式了。但是,模塊如何劃分呢?大還是小?之間的依賴如何進行控制?爲 什麼要定義這個擴展點?
     這就引出另外一個問題,“我們爲什麼而擴展?”
     擴展是要有目的性的,我們不能盲目爲了擴展而擴展,把系統搞得極其複雜,來應對幾乎不可能發生的變化。說道這裏,又談到設計。傳統軟 件開發過程講究Big Front Design,就是大量的前期設計。XP的一個實踐是簡單設計,我比較推崇簡單設計,就是剛剛好的設計。不 多也不少,就像五花肉,肥而不膩。如何做到這些,只能依賴於設計者本身的經驗了。
     回答這個問題,重要的是我們看的多遠,能夠預測到多少可能的變化。這些都是基礎。還有一個就是你對上下文的瞭解程度,這個 需要知識的補充。上下文知識越豐富,對其中的聯繫就越清楚,那也就越能識別出系統可能的變化。而我們設計系統時,就可以爲 這些變化,準備一些Slot,設計一些擴展點。可擴展性是設計出來的。
     如何把握這個分寸,確切的說,我也不知道,Context-special。

     總結一下:
     1)爲了控制複雜性,系統必須在邏輯上進行劃分,各個邏輯塊之間應該是鬆散耦合,需要對領域的理解和仔細分析。
     2)可擴展性不是一蹴而就的,是需要隨着你對業務領域理解的深入而不斷重構獲得。一般三次可以達到比較理想的程度。
     3)在系統演化過程中,時刻準備着,保持對複雜性的關注。確保這些複雜性得到消化。
     4)要想獲得可擴展性,你需要看得遠一點,對上下文做充分的瞭解。

      人無遠慮,必有近憂。  系統也一樣。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章