1、OCP(開閉原則):設計良好的軟體應該易于擴充,同時抗拒修改。這是我們進行架構設計的主導原則,其他的原則都為這條原則服務。
2、SRP(單一職責原則):任何一個軟體子產品,都應該有且隻有一個被修改的原因,“被修改的原因“指系統的使用者或所有者,翻譯一下就是,任何子產品隻對一個使用者的價值負責,該原則指導我們如何拆分元件。
舉個例子,CTO 和 COO 都要統計員工的工時,目前他們要求的統計方式可能是相同的,我們複用一套代碼,這時 COO 說周末的工時統計要乘以二,按照這個需求修改完代碼,CTO 可能就要過來罵街了。當然這是個非常淺顯的例子,實際項目中也有很多代碼服務于多個價值主體,這帶來很大的探秘成本和修改風險,另外,當一份代碼有多個所有者時,就會産生代碼合并沖突的問題。
3、LSP(裡氏替換原則):當用同一接口的不同實作互相替換時,系統的行為應該保持不變。該原則指導的是接口與其實作方式。
你一定很疑惑,實作了同一個接口,他們的行為也肯定是一緻的呀,還真不一定。假設認為矩形的系統行為是:面積=寬*高,讓正方形實作矩形的接口,在調用 setW 和 setH 時,正方形做的其實是同一個事情,設定它的邊長。這時下邊的單元測試用矩形能通過,用正方形就不行,實作同樣的接口,但是系統行為變了,這是違反 LSP 的經典案例。
Rectangle r = ...
r.setW(5);
r.setH(2);
assert(r.area() == 10);
4、ISP(接口隔離原則):不依賴任何不需要的方法、類或元件。該原則指導我們的接口設計。當我們依賴一個接口但隻用到了其中的部分方法時,其實我們已經依賴了不需要的方法或類,當這些方法或類有變更時,會引起我們類的重新編譯,或者引起我們元件的重新部署,這些都是不必要的。是以我們最好定義個小接口,把用到的方法拆出來。
5、DIP(依賴反轉原則):指一種特定的解耦(傳統的依賴關系建立在高層次上,而具體的政策設定則應用在低層次的子產品上)形式,使得高層次的子產品不依賴于低層次的子產品的實作細節,依賴關系被颠倒(反轉),進而使得低層次子產品依賴于高層次子產品的需求抽象。
跨越組建邊界的依賴方向永遠與控制流的方向相反。該原則指導我們設計元件間依賴的方向。
依賴反轉原則是個可操作性非常強的原則,當你要修改元件間的依賴方向時,将需要進行元件間通信的類抽象為接口,接口放在邊界的哪邊,依賴就指向哪邊。
6、REP(複用、釋出等同原則):軟體複用的最小粒度應等同于其釋出的最小粒度。直白地說,就是要複用一段代碼就把它抽成元件,該原則指導我們元件拆分的粒度。
7、CCP(共同閉包原則):為了相同目的而同時修改的類,應該放在同一個元件中。CCP 原則是 SRP 原則在元件層面的描述。該原則指導我們元件拆分的粒度。
對大部分應用程式而言,可維護性的重要性遠遠大于可複用性,由同一個原因引起的代碼修改,最好在同一個元件中,如果分散在多個元件中,那麼開發、送出、部署的成本都會上升。
8、CRP(共同複用原則):不要強迫一個元件依賴它不需要的東西。CRP 原則是 ISP原則在元件層面的描述。該原則指導我們元件拆分的粒度。
相信你一定有這種經曆,內建了元件 A,但元件 A 依賴了元件 B、C。即使元件 B、C 你完全用不到,也不得不內建進來。這是因為你隻用到了元件 A 的部分能力,元件 A 中額外的能力帶來了額外的依賴。如果遵循共同複用原則,你需要把 A 拆分,隻保留你要用的部分。
REP、CCP、CRP 三個原則之間存在彼此競争的關系,REP 和 CCP 是黏合性原則,它們會讓元件變得更大,而 CRP 原則是排除性原則,它會讓元件變小。遵守REP、CCP 而忽略 CRP,就會依賴了太多沒有用到的元件和類,而這些元件或類的變動會導緻你自己的元件進行太多不必要的釋出;遵守 REP、CRP 而忽略 CCP,因為元件拆分的太細了,一個需求變更可能要改 n 個元件,帶來的成本也是巨大的。
指導原則
除了上述設計原則,還有一些重要的指導原則如下:
1、N+1設計:系統中的每個元件都應做到沒有單點故障;
2、復原設計:確定系統可以向前相容,在系統更新時應能有辦法復原版本;
3、禁用設計:應該提供控制具體功能是否可用的配置,在系統出現故障時能夠快速下線功能;
4、監控設計:在設計階段就要考慮監控的手段,便于有效的排查問題,比如引入traceId、業務身份 Id 便于排查監控問題;
5、多活資料中心設計:若系統需要極高的高可用,應考慮在多地實施資料中心進行多活,至少在一個機房斷電的情況下系統依然可用;
6、采用成熟的技術:剛開發的或開源的技術往往存在很多隐藏的 bug,出了問題沒有很好的商業支援可能會是一個災難;
7、資源隔離設計:應避免單一業務占用全部資源;
8、架構水準擴充設計:系統隻有做到能水準擴充,才能有效避免瓶頸問題;
9、非核心則購買的原則:非核心功能若需要占用大量的研發資源才能解決,則考慮購買成熟的産品;
10、使用商用硬體:商用硬體能有效降低硬體故障的機率;
11、快速疊代:系統應該快速開發小功能子產品,盡快上線進行驗證,早日發現問題大大降低系統傳遞的風險;
12、無狀态設計:服務接口應該做成無狀态的,目前接口的通路不依賴于接口上次通路的狀态。
架構師知道了職責,具備很好的架構思維,掌握了通用的架構架構和方法論,使用架構原則進行架構設計,不同的業務和系統要求不一樣,那麼有沒有針對不同場景的系統架構設計?下文就針對分布式架構演進、單元化架構、面向服務 SOA 架構、微服務架構、Serverless 架構進行介紹,以便于我們在實際運用中進行參考使用。
[](
)具備架構師的思維
架構師職責明确了,那麼有什麼架構思維可以指導架構設計呢?請看下述的架構思維。
1、自頂向下建構架構
要點主要如下:
1)首先定義問題,而定義問題中最重要的是定義客戶的問題。定義問題,特别是識别出關鍵問題,關鍵問題是對客戶有體感,能夠解決客戶痛點,通過一定的資料化來衡量識别出來,關鍵問題要優先給出解決方案。
2)問題定義務必加入時間次元,把手段/方案和問題定義區分開來。
3)問題定義中,需要對問題進行升層思考後再進行升維思考,進而真正抓到問題的本質,理清和挖掘清楚需求;要善用第一性原理思維進行分析思考問題。
4)問題解決原則:先解決客戶的問題(使命),然後才能解決自己的問題(願景);務必記住不是強調我們怎麼樣,而是我們能為客戶具體解決什麼問題,然後才是我們變成什麼,進而怎麼樣去更好得服務客戶。
5)善用多種方法對客戶問題進行分析,轉換成我們産品或者平台需要提供的能力,比如倉儲系統 WMS 可以提供哪些商業能力。
6)對我們的現有的流程和能力模型進行梳理,找到需要提升的地方,升層思考和升維思考真正明确提升部分。
7)定義名額,并能夠對名額進行拆解,然後進行數學模組化。
8)将抽象出來的能力訴求轉換成技術挑戰,此步對于技術人員來說相當于找到了靶子,可以進行方案的設計了,需要結合自底向上的架構推導方式。
9)創新可以是業務創新,也可以是産品創新,也可以是技術創新,也可以是營運創新,升層思考、升維思考,使用第一性原理思維、生物學(進化論–進化=變異+選擇+隔離、熵增定律、分形和湧現)思維等哲科思維可以幫助我們在業務,産品,技術上發現不同的創新可能。可以說哲科思維是架構師的靈魂思維。
2、自底向上推導應用架構
先根據業務流程,分解出系統時序圖,根據時序圖開始對子產品進行歸納,進而得到粒度更大的子產品,子產品的組合/聚合建構整個系統架構。
基本上應用邏輯架構的推導有4個子路徑,他們分别是:
- 業務概念架構:業務概念架構來自于業務概念模型和業務流程;
- 系統模型:來自于業務概念模型;
- 系統流程:來自業務流程;
- 非功能性的系統支撐:來自對性能、穩定性、成本的需要。
效率、穩定性、性能是最影響邏輯架構落地成實體架構的三大主要因素,是以從邏輯架構到實體架構,一定需要先對效率、穩定性和性能做出明确的量化要求。
自底向上重度依賴于演繹和歸納。
如果是産品方案已經明确,程式員需要了解這個業務需求,并根據産品方案推導出架構,此時一般使用自底向上的方法,而領域模組化就是這種自底向上的分析方法。
對于自底向上的分析方法,如果提煉一下關鍵詞,會得到如下兩個關鍵詞:
1)演繹:演繹就是邏輯推導,越是底層的,越需要演繹:
- 從用例到業務模型就屬于演繹;
寫在最後
學習技術是一條慢長而艱苦的道路,不能靠一時激情,也不是熬幾天幾夜就能學好的,必須養成平時努力學習的習慣。是以:貴在堅持!
最後再分享的一些BATJ等大廠20、21年的面試題,把這些技術點整理成了視訊和PDF(實際上比預期多花了不少精力),包含知識脈絡 + 諸多細節,由于篇幅有限,上面隻是以圖檔的形式給大家展示一部分。
CodeChina開源項目:【一線大廠Java面試題解析+核心總結學習筆記+最新講解視訊】
Mybatis面試專題