優秀程序員和架構師之間還有一個明顯的鴻溝需要跨越,這個鴻溝就是“不確定性”;
對于編程來說,本質上是不能存在不確定的,而對于架構設計來說,本質上是不確定的,同樣的一個系統,A 公司和 B 公司做出來的架構可能差異很大,但最后都能正常運轉。
選擇
相比編程來說,架構設計并沒有像編程語言那樣的語法來進行約束,更多的時候是面對多種可能性時進行選擇
- 是要選擇業界最先進的技術,還是選擇團隊目前最熟悉的技術?如果選了最先進的技術后出了問題怎么辦?如果選了目前最熟悉的技術,后續技術演進怎么辦?
- 是要選擇 Google 的 Angular 的方案來做,還是選擇 Facebook 的 React 來做?Angular 看起來更強大,但 React 看起來更靈活?
- 是要選 MySQL 還是 MongoDB?團隊對 MySQL 很熟悉,但是 MongoDB 更加適合業務場景?
- 淘寶的電商網站架構很完善,我們新做一個電商網站,是否簡單地照搬淘寶就可以了?
架構設計領域并沒有一套通用的規范來指導架構師進行架構設計,更多是依賴架構師的經驗和直覺
- 架構設計時遵循這幾個原則,有助于你做出最好的選擇
- 合適原則
- 簡單原則
- 演化原則
合適原則
- 合適原則宣言:“合適優于業界領先”
再好的夢想,也需要腳踏實地實現!這里的“腳踏實地”主要體現在下面幾個方面
- 將軍難打無兵之仗
大公司的分工比較細,一個小系統可能就是一個小組負責,阿里的中間件團隊有幾十個人,而大部分公司,某個業務團隊可能就十幾個人。十幾個人的團隊,想做幾十個人的團隊的事情,而且還要做得更好,不能說絕對不可能,但難度是可想而知的
- 沒那么多人,卻想干那么多活,是失敗的第一個主要原因。
- 羅馬不是一天建成的
業界領先的很多方案,都是經過幾年時間的發展才逐步完善和初具規模的,經歷過的挑戰和踩坑,都是架構設計非常關鍵的促進因素,單純靠拍腦袋或者頭腦風暴,是不可能和真正實戰相比的
- 沒有那么多積累,卻想一步登天,是失敗的第二個主要原因。
- 冰山下面才是關鍵
大多的時候,業界領先的方案其實都是“逼”出來的,“業務”發展到一定階段,量變導致了質變,出現了新的問題,已有的方式已經不能應對這些問題,需要用一種新的方案來解決,通過創新和嘗試,才有了業界領先的方案
- 沒有那么卓越的業務場景,卻幻想靈光一閃成為天才,是失敗的第三個主要原因。
- 真正優秀的架構都是在企業當前人力、條件、業務等各種約束下設計出來的,能夠合理地將資源整合在一起并發揮出最大功效,并且能夠快速落地
簡單原則
- 簡單原則宣言:“簡單優于復雜”
- 軟件領域的復雜性體現在兩個方面:
- 結構的復雜性
- 結構復雜的系統幾乎毫無例外具備兩個特點:
- 組成復雜系統的組件數量更多;
- 同時這些組件之間的關系也更加復雜。
- 以圖形的方式來說明復雜性:
- 組件越多,就越有可能其中某個組件出現故障,從而導致系統故障
- 假設組件的故障率是 10%
- 有 3 個組件的系統可用性是(1-10%)×(1-10%)×(1-10%)= 72.9%
- 有 5 個組件的系統可用性是(1-10%)×(1-10%)×(1-10%)×(1-10%)×(1-10%)=59%
- 某個組件改動,會影響關聯的所有組件,這些被影響的組件同樣會繼續遞歸影響更多的組件
- 以上面圖中 5 個組件組成的系統為例,組件 A 修改或者異常時,會影響組件 B/C/E,D 又會影響 E
- 這個問題會影響整個系統的開發效率,因為一旦變更涉及外部系統,需要協調各方統一進行方案評估、資源協調、上線配合
- 定位一個復雜系統中的問題總是比簡單系統更加困難
- 首先是組件多,每個組件都有嫌疑,因此要逐一排查
- 其次組件間的關系復雜,有可能表現故障的組件并不是真正問題的根源
- 邏輯的復雜性
意識到結構的復雜性后,那我們是不是可以,用最簡單的結構,就是整個系統只有一個組件,即系統本身,所有的功能和邏輯都在這一個組件中實現
顯然這樣做是行不通的,原因在于除了結構的復雜性,還有邏輯的復雜性,即如果某個組件的邏輯太復雜,一樣會帶來各種問題
- 邏輯復雜幾乎會導致軟件工程的每個環節都有問題,假設現在淘寶將這些功能全部在單一的組件中實現,可以想象一下這個恐怖的場景
- 系統會很龐大,可能是上百萬、上千萬的代碼規模,“clone”一次代碼要 30 分鐘
- 幾十、上百人維護這一套代碼,某個“菜鳥”不小心改了一行代碼,導致整站崩潰
- 需求像雪片般飛來,為了應對,開幾十個代碼分支,然后各種分支合并、各種分支覆蓋
- 產品、研發、測試、項目管理不停地開會討論版本計劃,協調資源,解決沖突
- 版本太多,每天都要上線幾十個版本,系統每隔 1 個小時重啟一次
- 線上運行出現故障,幾十個人撲上去定位和處理,一間小黑屋都裝不下所有人,整個辦公區鬧翻天
- 誰都無法忍受這樣的場景...
- 復雜的電路就意味更強大的功能,而復雜的架構卻有很多問題
- 原因在于電路一旦設計好后進入生產,就不會再變,復雜性只是在設計時帶來影響
- 而一個軟件系統在投入使用后,后續還有源源不斷的需求要實現,因此要不斷地修改系統,復雜性在整個系統生命周期中都有很大影響
- 復雜算法導致的問題主要是難以理解,進而導致難以實現、難以修改,并且出了問題難以快速解決
- ZooKeeper 功能雖然相對簡單,但因使用ZAB協議,系統實現卻比較復雜
- etcd 采用的是 Raft 算法,相比 ZAB 協議,Raft 算法更加容易理解,更加容易實現
- 無論是結構的復雜性,還是邏輯的復雜性,都會存在各種問題,所以架構設計時如果簡單的方案和復雜的方案都可以滿足需求,最好選擇簡單的方案
演化原則
- 演化原則宣言:“演化優于一步到位”。
從和目的、主題、材料和結構的聯系上來說,軟件架構可以和建筑物的架構相比擬。
—— 維基百科
- 對于建筑來說,永恒是主題;而對于軟件來說,變化才是主題
- 架構設計的一個誤區:試圖一步到位設計一個軟件架構,期望不管業務如何變化,架構都穩如磐石
- 考慮到軟件架構需要根據業務發展不斷變化這個本質特點,軟件架構設計其實更加類似于大自然“設計”一個生物,通過演化讓生物適應環境,逐步變得更加強大:
- 首先,生物要適應當時的環境
- 其次,生物需要不斷地繁殖,將有利的基因傳遞下去,將不利的基因剔除或者修復
- 第三,當環境變化時,生物要能夠快速改變以適應環境變化;如果生物無法調整就被自然淘汰;新的生物會保留一部分原來被淘汰生物的基因
- 軟件架構設計同樣是類似的過程:
- 首先,設計出來的架構要滿足當時的業務需要
- 其次,架構要不斷地在實際應用過程中迭代,保留優秀的設計,修復有缺陷的設計,改正錯誤的設計,去掉無用的設計,使得架構逐漸完善
- 第三,當業務發生變化時,架構要擴展、重構,甚至重寫;代碼也許會重寫,但有價值的經驗、教訓、邏輯、設計等(類似生物體內的基因)卻可以在新架構中延續
- 實際架構設計時,應認真分析當前業務的特點,明確業務面臨的主要問題,設計合理的架構,快速落地以滿足業務需要,然后在運行過程中不斷完善架構,不斷隨著業務演化架構
小結
本文介紹了面對“不確定性”時架構設計的三原則,分別是合適優于業界領先、簡單優于復雜、演化優于一步到位