我們一起聊聊架構(gòu)復(fù)雜度來源高可用
可擴(kuò)展性是系統(tǒng)設(shè)計(jì)中一個(gè)關(guān)鍵概念,它指的是系統(tǒng)為了適應(yīng)未來需求的變化,具備的一種擴(kuò)展能力。這意味著當(dāng)新需求出現(xiàn)時(shí),系統(tǒng)可以通過最小的或沒有修改來支持這些需求,而無需進(jìn)行全面的重構(gòu)或重建。隨著軟件系統(tǒng)的固有多變性,不斷有新需求提出,這使得可擴(kuò)展性成為軟件開發(fā)中的一個(gè)重要考慮點(diǎn)。面向?qū)ο蟮木幊趟枷牒驮O(shè)計(jì)模式的發(fā)展,都是為了更好地應(yīng)對(duì)和解決可擴(kuò)展性的挑戰(zhàn)。設(shè)計(jì)模式的廣泛應(yīng)用顯示了對(duì)可擴(kuò)展性的高度重視,幾乎成為了每一位技術(shù)專家的共識(shí)。
為了構(gòu)建一個(gè)具有良好可擴(kuò)展性的系統(tǒng),主要需要滿足兩個(gè)前提條件:準(zhǔn)確預(yù)測(cè)未來的變化,以及有效封裝這些變化。然而,實(shí)現(xiàn)這兩個(gè)條件并非易事,下面我將詳細(xì)探討這個(gè)主題。
與硬件或建筑項(xiàng)目不同,軟件系統(tǒng)的一個(gè)顯著特點(diǎn)是其發(fā)布后仍然能夠持續(xù)進(jìn)行修改和更新。這一特性意味著軟件系統(tǒng)需要不斷地適應(yīng)和實(shí)現(xiàn)新的需求。理想情況下,如果能夠在不修改現(xiàn)有代碼或僅通過少量修改來滿足這些新需求,對(duì)所有相關(guān)方來說無疑是最佳場(chǎng)景。反之,如果每出現(xiàn)一個(gè)新需求就需要對(duì)系統(tǒng)進(jìn)行大規(guī)模改動(dòng),不僅成本高昂,而且開發(fā)人員、產(chǎn)品經(jīng)理、甚至老板都會(huì)感到不滿——這種頻繁的大幅度修改既耗時(shí)又耗力。因此,架構(gòu)設(shè)計(jì)的一個(gè)關(guān)鍵目標(biāo)是盡可能預(yù)見未來的變化,并設(shè)計(jì)出能夠靈活適應(yīng)這些變化的架構(gòu),使得當(dāng)新需求出現(xiàn)時(shí),可以輕松地說:“我們已經(jīng)考慮到了這一點(diǎn),現(xiàn)有架構(gòu)可以輕松支持這個(gè)新功能,僅需幾天的工作量?!?/span>
然而,現(xiàn)實(shí)往往遠(yuǎn)比理想復(fù)雜。正如一句古老的諺語所言:“唯一不變的是變化本身”。這意味著在架構(gòu)設(shè)計(jì)時(shí),考慮到可擴(kuò)展性變得尤為重要。比如,在設(shè)計(jì)一個(gè)后臺(tái)管理系統(tǒng)時(shí),如果選擇使用MySQL作為數(shù)據(jù)庫,是否需要預(yù)留空間以便將來可能切換到Oracle?在決定使用HTTP作為接口協(xié)議時(shí),是否需要考慮未來可能支持ProtocolBuffer?甚至更進(jìn)一步,是否需要考慮VR技術(shù)可能帶來的影響,以確保架構(gòu)的長(zhǎng)期可擴(kuò)展性?如果嘗試預(yù)測(cè)和準(zhǔn)備每一個(gè)可能的變化,架構(gòu)師可能會(huì)感到不堪重負(fù),導(dǎo)致設(shè)計(jì)過于龐大而難以實(shí)施。但另一方面,如果完全不進(jìn)行未來規(guī)劃,新需求的到來可能會(huì)迫使系統(tǒng)進(jìn)行重構(gòu),這同樣意味著前期的投入和努力可能會(huì)付之東流。
應(yīng)對(duì)變化
第一種應(yīng)對(duì)變化的常見方案是將“變化”封裝在一個(gè)“變化層”,將不變的部分封裝在一個(gè)獨(dú)立的“穩(wěn)定層”
圖片
無論采取哪種形式,通過剝離變化層和穩(wěn)定層的方式應(yīng)對(duì)變化,都會(huì)帶來兩個(gè)主要的復(fù)雜性相關(guān)的問題。
區(qū)分變化與穩(wěn)定層
在系統(tǒng)架構(gòu)設(shè)計(jì)中,識(shí)別哪些部分容易發(fā)生變化(變化層)與哪些部分相對(duì)穩(wěn)定(穩(wěn)定層)是關(guān)鍵的第一步。然而,區(qū)分這兩層并非總是直接明了的,比如不同的數(shù)據(jù)庫選擇或接口協(xié)議可能容易識(shí)別,但在實(shí)際情況中,不同設(shè)計(jì)者可能對(duì)哪些層次屬于變化層,哪些屬于穩(wěn)定層有不同的見解。這種差異可能會(huì)在架構(gòu)審查過程中引發(fā)激烈的討論。
設(shè)計(jì)變化層與穩(wěn)定層間的接口
接口的設(shè)計(jì)是連接變化層與穩(wěn)定層的橋梁,對(duì)于確保系統(tǒng)的整體穩(wěn)定性和可擴(kuò)展性至關(guān)重要。穩(wěn)定層的接口應(yīng)當(dāng)盡可能的穩(wěn)定,而對(duì)于變化層,設(shè)計(jì)一個(gè)能夠適應(yīng)不同實(shí)現(xiàn)方式并在引入新功能時(shí)仍保持兼容性的接口則更加復(fù)雜。以數(shù)據(jù)庫為例,不同數(shù)據(jù)庫(如MySQL、Oracle、DB2)之間在某些操作(如數(shù)據(jù)插入或更新)的實(shí)現(xiàn)上可能存在差異,這就需要在設(shè)計(jì)存儲(chǔ)層訪問接口時(shí)做出選擇:是采用特定數(shù)據(jù)庫的實(shí)現(xiàn)方式,還是設(shè)計(jì)一個(gè)能夠自適應(yīng)不同數(shù)據(jù)庫特性的通用接口?這個(gè)例子揭示了設(shè)計(jì)接口時(shí)需要面對(duì)的挑戰(zhàn)。
另一種常用的方法來應(yīng)對(duì)系統(tǒng)變化是區(qū)分“抽象層”與“實(shí)現(xiàn)層”。在這種架構(gòu)策略中,抽象層保持穩(wěn)定,為系統(tǒng)的核心和通用功能提供定義,而實(shí)現(xiàn)層則具有可變性,可以根據(jù)不同的業(yè)務(wù)需求進(jìn)行定制化開發(fā)。當(dāng)需要引入新功能時(shí),僅需添加新的實(shí)現(xiàn)即可,而不需要對(duì)抽象層進(jìn)行修改。設(shè)計(jì)模式和規(guī)則引擎就是這種策略的經(jīng)典實(shí)踐案例。鑒于大多數(shù)技術(shù)專業(yè)人士對(duì)設(shè)計(jì)模式已相當(dāng)熟悉,我將以設(shè)計(jì)模式為例進(jìn)一步闡述這種方法的復(fù)雜之處。
裝飾者模式提供了一種相較于傳統(tǒng)繼承更為靈活的方式來擴(kuò)展功能。以《設(shè)計(jì)模式》一書中的“TextView”類示例為例,通過使用裝飾者模式,可以非常靈活地為TextView添加各種額外功能,如邊框、滾動(dòng)條、背景圖片等,而這些功能的組合并不會(huì)影響到基本的實(shí)現(xiàn)規(guī)則,只需遵循裝飾者模式的設(shè)計(jì)即可實(shí)現(xiàn)。然而,與傳統(tǒng)的類實(shí)現(xiàn)相比,裝飾者模式的確引入了更多的復(fù)雜性。原本可能通過單個(gè)函數(shù)或類就能完成的任務(wù),現(xiàn)在需要分解成多個(gè)類,并且這些類之間的關(guān)系和調(diào)用方式都必須遵循裝飾者模式的設(shè)計(jì)原則。
同樣,規(guī)則引擎的設(shè)計(jì)理念與設(shè)計(jì)模式持有相同的目標(biāo)——通過靈活的設(shè)計(jì)達(dá)到系統(tǒng)的可擴(kuò)展性。然而,這種“靈活性”本身就帶來了設(shè)計(jì)上的復(fù)雜性。不僅如此,僅僅是要徹底理解并掌握23種設(shè)計(jì)模式本身就是一個(gè)挑戰(zhàn)。