Categories
程式開發

架構拆分的代價之一二三


架構拆分可以用來節省人們執行事務生命週期活動所需的時間,這就是傳說中購買“寸光陰”的方式,也是傳說中的“銀彈”。不過要獲得這個“銀彈”,也不是沒有代價的。但既然節省的是時間,而時間又是無價的,因此人們也願意採用架構拆分,哪怕要因此而付出巨大的代價。因為相比“無價”而言,“巨大的代價”也是可以接受的。

可是架構也不是萬能的。那麼在採用架構拆分之前,了解這些“巨大的代價” 是非常有必要的,可以幫助我們認清架構的局限,釐清對作架構拆分的人的要求。因為不合理的架構拆分,反而會浪費更多的時間;哪怕是合理的架構拆分, 但是如果不能夠重新組裝回原有生命週期的話,也無法達到節省時間的目的, 最終也會導致浪費時間。

沒有上下文的同學看到這裡,可能會對“架構”和“架構拆分”這兩個詞有迷惑。一會兒說“架構”,一會兒說“架構拆分”,那麼架構和架構拆分究竟是什麼關係呢?架構拆分是實現架構的一個手段,是架構落地的方法,是架構的核心生命週期活動。

本文嘗試描述架構拆分所產生的代價。觀點不一定正確,也不一定適合所有人,僅供參考。如能引發讀者的哪怕一絲思考,那就幸甚至哉!

空間拆分的代價

架構拆分的本質就是空間拆分,這在之前的文章中已經探討過了。一個事物在進行空間拆分之後,必然會變成一個一個不同的個體。每個個體從原有事物中獨立出來之後,會形成各自一個一個的獨立生命週期。

既然是獨立生命週期,那麼就意味著對原有事物做架構拆分的人——也就是架構拆分主體,他必須要管理這些新出現的一個一個獨立生命週期。也可以看到,有了架構才會出現管理,做管理的人不懂架構是不行的。

但是大部分做架構拆分的人,都沒有意識到這一點。大多數人只注意獲得架構拆分的好處,而忽略了拆分出來的子生命週期也是需要管理的,只有管理好子生命週期才能夠得到架構拆分的好處。

比如做技術的人,在企業經過一段時間的鍛煉之後,掌握了某種技術。往往他們就會開始去思考如何把技術變現,以求自身利益最大化。比較流行的方式當然就是去創業。

而創業則等於形成一種新的社會分工,也就是對社會的一個架構拆分。拆分的結果,形成了一個新的公司,也就形成了一個新的生命週期。這個新的生命週期必須先要健康的運轉起來,技術才能夠派得上用場。而要推動運轉這個新生命週期,則需要先註冊公司,準備資金,需要和稅務、法務打交道,要招人,要社保…。這個時候,已經累的夠嗆了,但是離運用想要變現的技術還遠著呢。

公司成立好了,接下來為了要形成訂單,還需要先找到客戶。為此,還需要先把技術形成產品,以便形成商品進行銷售。為了形成產品,則需要巨大的投入。為了找到客戶,則需要巨大的營銷成本。而這些工作,光只是一個人是不夠的,還需要先做自身的架構拆分後,再招人來幫忙。如果沒有受過架構方面的訓練,這個架構拆分本身就很容易產生新的問題。即便成功的對自身工作 進行架構拆分之後,則又形成了新的生命週期,新招來的人則會負責推進這些生命週期。那麼這些新招來的人當然也是需要管理的,他們的生命週期也是需要推進的,需要與他們簽訂合同,發工資,交社保,等等等等。

回頭再看看,在企業內部掌握並運用這個技術,只需要關心這個技術本身的生命週期就足夠,事情簡單太多了。

很多技術創業者滿腔熱情,只看到了自己的技術的好處,沒有註意到架構拆分後,要管理子生命週期的成本,最後往往因此不堪重負,最終導致失敗。

所以做架構拆分的人,他必須要管理拆分之後子生命週期的全生命週期,才能夠享受到架構拆分的好處,大家對此要有清醒的認識。他必須要了解拆分後子生命週期的全生命週期活動,而不是僅僅關心自己想要的其中那一個活動。所以做架構拆分時,要謀定而後動:只有管理好每個獨立子生命週期的成本自 己可以承受,並且有應對的辦法,才可以做架構拆分。

當然還可以進一步做架構拆分,請一個人來開車,讓他來執行並推進這些生命週期。這又意味著進一步的成本的付出,因為還要新增負擔管理司機的生命週期,需要支付工資等等。

不清楚這些新出現的子生命週期的代價,貿然的去買車,那麼也只會給自己帶來麻煩。這種情況之下,坐地鐵反而是經濟實惠的。

對於軟件開發工作者而言,在對代碼做架構拆分時,同樣也必須管理好架構拆分後所形成新組件的全生命週期。比如把一個應用拆分為兩個子應用後,那麼兩個子應用的全生命週期都要管理起來,哪怕只是需要子應用的某一個服務。

當然,人們常用“非功能性需求”來說明這一點,但是往往得不到重視,也 不夠全面。或許是因為“非功能”這一概念仍然僅僅是附帶在“功能”上,沒脫離“功能”的陰影。因此我也很少用“非功能性需求”這個詞彙,因為無法用“功能”去定義它。

只有回歸到軟件自身的生命週期上,才能夠正確理解所謂的“非功能性需求”:其關注點並不在於“功能”,而是在於保障功能自身的健康,並保證功能可以被正常訪問到。因為想要得到子應用的某一個功能——這只是充分條件,只是決定了該子應用具備獨立生存的資格;但是這還遠遠不夠,先必須得讓這個子應用能夠正常生存下去——這是必要條件,因為只有健康活著才能夠被訪問。只有充分條件和必要條件同時都滿足,這個子應用的生命週期才算是完整了, 該子應用的功能才能夠正常運轉並接受訪問。

因此,所謂的“非功能性需求”,指的就是軟件得以正常生存並對外提供服務的必要條件。詳細展開來,該必要條件主要體現在以下兩個方面。

首先,承載所需功能的軟件自身必須要健康才行。

達到這一點,需要從計算機硬件的邊界完整考慮其生命週期,如機房、電源、計算機資源、網絡資源等硬件資源的生命週期;還需要從計算機軟件的邊界完整考慮其生命週期,如啟動、到服務、到關閉等。二者都需要完整考慮,也都需要進行監控。這是軟件功能得以正常運行的必要條件——軟件先要能夠健康的活著,並且能夠被用戶訪問到。

其次,軟件是提供給用戶訪問的,要保證合法用戶的合法訪問可以正常到達軟件。

要滿足這一點,需要解決以下兩方面的問題:

一、識別合法的訪問。 比如哪些是合法用戶的訪問,哪些是非法用戶的訪問?合法用戶的訪問哪些是 合法的,哪些是非法的?合法的訪問中,哪些是正常的訪問,哪些是非正常的訪問?等等。只有屏蔽了不合法用戶的訪問,也排除了合法用戶的非正常訪問, 那麼合法用戶的合法訪問才會不受影響。這些問題往往被稱作安全需求。

二、 滿足訪問量要求。該軟件所在機器可接受的訪問量範圍是多少?該軟件在該機 器上可接受的訪問量是多少?訪問量超過正常的範圍怎麼處理?承載用戶對軟件訪問的網絡設備帶寬是多少,能承受多大的訪問量?超過這個範圍怎麼處理?等等。當超過流量範圍時,是否要優先確保已經在正常訪問的那些用戶訪問?如何確保或者根據業務的需求,優先保證高價值用戶的訪問?等等。這些問題往往被稱作容量需求。這是軟件功能能夠被正常訪問的必要條件——對訪問 安全問題和訪問容量問題的合適處理,保障了軟件訪問的健康。

保障軟件自身的健康,基本上是技術問題居多,容易被技術人員識別出來。但是保障軟件訪問的健康,基本上都是業務問題,也難怪容易被技術人員忽略, 其優先級也容易被排的很低。因此,提陞技術人員的業務意識至關重要。

所以,軟件架構分拆並不是簡單的把代碼拆分出來。架構師不考慮清楚分拆出來軟件的完整生命週期,僅關注所需的功能,那麼架構拆分只會帶來無盡的麻煩,浪費更多的時間,而得不到任何好處。

連續的流程所產⽣生的單點

架構拆分之後,會在空間上形成不同的個體。原本只是在一個個體上完成的事情,則變成了需要通過多個不同的個體組合來完成。為了組合這些個體完成原有的事務,則需要按一定的順序組合併遍歷這些個體,這就形成了一個流程。這也意味著需要在空間上按照時間順序一個一個地訪問這些個體,才能夠得到與原有事務相同的結果。

這麼做是有代價的。當流程中的任何一個個體出現問題,這個事務就會整體出現問題,這就是單點故障。比方說工廠中的流水線,其中一個節點失效或者堵塞,整個流程都會受到影響而停止下來。因此,所拆分出來的個體越多,所形成的流程則越長,那麼單個點失敗出現的可能性就越大。

在數學上,這種情況稱之為串聯。串聯的穩定性是這麼計算的,如果每個個體穩定性為 N%,那麼整個鏈條的穩定性是該鏈條上所有個體穩定性的乘積。這個怎麼來理解呢?

架構拆分的代價之一二三 1

比如上圖,一個事務本身的穩定性是 90%,在拆分為兩個個體組合來完成之後,形成了一個鏈條,這個鏈條上有兩個個體。假設拆分後,每個個體的穩定性保持不變,每個個體的穩定性仍然是90%,那麼拆分之後,整體穩定性變成了90%×90%=81%,穩定性反而下降了9 個百分點。拆出來的個體越多,流程越長,穩定性下降得就越明顯。

這就是架構拆分後,單點的代價。所有做架構拆分的人 —- 人們稱他們為架構師,都必須要意識到這個代價。

同時,如果沒有註意管理好代價 1 所帶來的代價,那麼在把原有事務拆分成為串聯的子節點後,每個子節點的穩定性反而會下降。結合代價 2 導致的串聯引入,其架構拆分的最終結果,也就可想而知了。

但是單點既是代價,也是一個機會。比如在現實生活中,一個城市只有一家餐館,那麼沒有哪個人願意只依賴這家餐館,而放棄在家做飯,因為這一個餐館就是一個單點。如果這個餐館過忙了,或者歇業,大家就沒處吃飯了。但是如果大家都很忙,沒空自己做飯的時候,那麼這個單點就成了一個商機,餐館也會變得越來越多。一旦有了多個可備份的選擇,找餐館吃飯也就變得容易了,那麼越來越多的人也就敢於放棄在家做飯,在餐館就餐。這就是所謂的並聯。

架構拆分的代價之一二三 2

這一特性,也可以在數學上表示出來。如上例,如果把相同的組件並聯起 來,只有在兩個並聯組件同時都失敗後,才會導致整體失敗,因此其失敗的可能性為 (1-90%)×(1-90%)。其穩定性則為 1-(1-90%)×(1-90%)=99.99%,提升了近 10 個百分點。由此可見,並聯可以提升整個系統的穩定性。因此,人們常用這個辦法來改善架構拆分後系統穩定性會降低這一弱點。

再比如古人遠行,莊子云:“適莽蒼者,三湌而反,腹猶果然;適百里者宿舂糧;適千里者三月聚糧”。走的越遠,所需儲備的糧食就越多。這是一個人獨立完成的事務,在沒有作架構拆分的情況下,只需要提升個體的穩定性即可。有了馬匹等代步工具的豐富,有了沿路餐館的豐富,交易的發達,人們不再依靠自己儲備的糧食就可以出門,且在相同時間內可以行更遠的路,節省了時間。行步通過採用代步工具,形成了架構拆分,飲食也形成了架構拆分,且這些拆 分都有並聯來保障其穩定性。這就是社會的架構拆分所帶來的好處,節省了每一個人的時間,且利用了並聯,避免了拆分後形成串聯所帶來穩定性下降這一壞處。

再比如代步工具已經進化到現代的汽車,從人的油門一踩,到輪子前行,其中經歷了非常多的串行機構。整個鏈條上的任何一個機構失效,都會導致傳動的失敗。方向盤一轉、剎車一踩,也是一樣的。這些是屬於沒有可能並聯的地方,因此必須要把傳動鏈條上的每一個機構都做的非常的穩定、健壯,所以這些機構都非常的粗壯,用的都是非常好的材料,這也是避免串行缺點的一個處理方法。通過把串行節點上的每一個節點都做的異常的健壯、可靠,也可以提升整體穩定性,以降低架構拆分所帶來的負面影響。反觀自行車,類似的串聯機構則沒那麼粗壯,一方面速度慢、自重輕,另一方面串聯的機構數量也更少。

對於軟件的架構拆分,每個拆分出來的子軟件也要形成並聯來保障整體的穩定性,也就是集群的方式,這是同樣的道理。如果架構師在拆分時不了解這一限制,也是會付出極大的代價的。可是為何不通過提升每個節點的健壯性來提升呢?這個問題留給大家思考。

組合的代價

一個事務拆分成為多個子生命週期之後,最終還是需要把這些子生命週期整合成為原事務的,這樣才算完成了架構拆分。

許多人作架構拆分時,只考慮拆分之後的好處,卻在組合回原事務時,忘記了拆分的初衷。輕則導致完成原事務變得更加困難,重則導致原事務無法完成,導致原事務的失敗。比如代價 1 和代價 2 的處理不當,都能夠使得原事務無法得到正確還原。

而且每當一個新個體拆分出來之後,這個新的個體就有了它自身的生命週期。負責這個新個體的人,就會有自己的訴求,有他自己的利益。作架構拆分 的人,必須在作架構拆分時就充分考慮好拆分出來的每個個體的利益。用通俗的話說,在做架構拆分時就要對這些拆分出來的子個體設定好KPI,明確這些子個體的目標,使得這些子個體不得違反整個架構目標,要能夠順利組合為原有事務,共同為完成原有事務作出貢獻。

對於軟件也是同樣的,拆分時就要想好怎麼把拆分出來的軟件組合成原有的系統。這些軟件在拆分前處在同一個應用的時候,它們共享計算機的內存、 CPU、網絡、磁盤等硬件,操作系統等軟件。一旦分離開來,每個應用就有了自己的計算機資源,有了自己的對外訪問,有了自己的利益,有了自己的計算機硬件和軟件的邊界。雖然這些剛分離出來的軟件暫時僅僅服務於原來的業務, 但是隨著時間的變化,這些軟件一定會有自己獨立的業務出現,這些軟件的擁 有者一定會有自己的訴求。因為一個事物只要出生,它必然要長大,這是不可避免的。

所以在組合這些軟件時要明白,這是針對不同個體的訪問,需要考慮跨越網絡,需要考慮這些個體自身利益,比如它們的流量分配、訪問邊界、安全與隔離等等。如果僅僅是簡單粗暴的組合,忽視不同應用各自的利益,一定會帶來極大的溝通成本,甚至會導致組合的失敗。

總結一下,也就是說架構拆分是有成本的,哪怕它能夠節省時間。如果不合適的架構拆分,或者架構拆分時考慮不周,則會導致人們整體花費更多的時間成本,那麼這個架構拆分則是不值得的。只有能夠管理好架構拆分的時間成本,並能夠讓架構拆分後的時間成本低於原有的時間成本,這個拆分才是值得的。所以架構拆分也不是想怎麼拆就怎麼拆,也不是拆完了就結束了,架構拆分有其自身的規律。架構師必須要先考慮好架構拆分的代價再進行拆分,這樣就不容易掉進坑里。

以上略略談了一下架構拆分的代價,僅僅算是拋磚引玉。對於這個問題,每個人都應該好好思考一下,或許不僅僅只是以上三點。