健客,架構(gòu)師崗位二面,你覺得軟件設計的原則是什么?(架構(gòu)設計的方法論)

前言

大家有沒有發(fā)現(xiàn),高職位的崗位,八股文的技術(shù)題面試就越少,反而更多的是考察面試者工作上的心得及經(jīng)驗總結(jié)。一位前同事分享了他面試健客的經(jīng)歷,當時他面試的崗位是架構(gòu)師,面試官問他:作為架構(gòu)師,架構(gòu)設計的方法論或者設計的原則是什么?當時這位同事回答的不是很好,因為在平常的工作中,很少會總結(jié)這方面的知識,面試結(jié)果也可想而知。應前同事的要求,有必要總結(jié)一下那些業(yè)界知名,給我留下深刻印象的軟件架構(gòu)設計原則及一些經(jīng)驗總結(jié),和大家一起分享。


一. 架構(gòu)到底是什么

我們可能經(jīng)常會聽到有人說架構(gòu)一詞,但是到底什么是架構(gòu),卻很少有人說的清楚。

其實架構(gòu)無處不在,它不只在計算機中存在,它在我們生活當中也很常見,比如我們著手解決一些問題,首先要計劃一套方案,一套流程,這些方案和流程其實就是一種架構(gòu)。

在軟件系統(tǒng)中,架構(gòu)是非常重要的一部分,它統(tǒng)領(lǐng)各個模塊的開發(fā)和合作,項目從研發(fā)到上線運營,我們要在不同的方案中選擇合適的架構(gòu),比如,我們服務器使用什么操作系統(tǒng)?使用什么語言開發(fā)?數(shù)據(jù)如何獲取和存儲?客戶端使用什么框架開發(fā)?

軟件架構(gòu)指軟件系統(tǒng)的“基礎(chǔ)結(jié)構(gòu)”,創(chuàng)造這些基礎(chǔ)結(jié)構(gòu)的準則,以及對這些結(jié)構(gòu)的描述。參考維基百科的定義,我將架構(gòu)重新定義為:軟件架構(gòu)指軟件系統(tǒng)的頂層結(jié)構(gòu)

通俗一點的說法就是,可以把軟件架構(gòu)理解成一棟房子的框架,與現(xiàn)實生活中的房子有異曲同工之處,這個框架有很多個大大小小的房間,每個房間可以放各種類型的東西。

二. 架構(gòu)設計的目的

通過熟悉和理解需求,識別系統(tǒng)復雜性所在的地方,然后針對這些復雜點進行架構(gòu)設計。架構(gòu)設計并不是要面面俱到,不需要每個架構(gòu)都具備高性能、高可用、高擴展等特點,而是要識別出復雜點然后有針對性地解決問題。

即架構(gòu)設計的主要目的是為了解決軟件系統(tǒng)復雜度帶來的問題。


三. 架構(gòu)設計的六大基本原則

1. 單一職責原則(Single Responsibility Principle - SRP)

譯文:永遠不應該有多于一個原因來改變某個類。

理解:對于一個類而言,應該僅有一個引起它變化的原因。說白了就是,不同的類具備不同的職責,各施其責。這就好比一個團隊,大家分工協(xié)作,互不影響,各做各的事情。

應用:當我們做系統(tǒng)設計時,如果發(fā)現(xiàn)有一個類擁有了兩種的職責,那就問自己一個問題:可以將這個類分成兩個類嗎?如果真的有必要,那就分吧。千萬不要讓一個類干的事情太多!

2. 開放封閉原則(Open Closed Principle - OCP)

譯文:軟件實體,如:類、模塊與函數(shù),對于擴展應該是開放的,但對于修改應該是封閉的。

理解:簡言之,對擴展開放,對修改封閉。換句話說,可以加擴展類,但不要去修改類。

應用:當需求有改動,要修改代碼了,此時您要做的是,盡量用繼承或組合的方式來擴展類的功能,而不是直接修改類的代碼。當然,如果能夠確保對整體架構(gòu)不會產(chǎn)生任何影響,那么也沒必要搞得那么復雜了,直接改這個類吧。

3. 里氏替換原則(Liskov Substitution Principle - LSP)

譯文:使用基類的指針或引用的函數(shù),必須是在不知情的情況下,能夠使用派生類的對象。

理解:父類能夠替換子類,但子類不一定能替換父類。也就是說,在代碼中可以將父類全部替換為子類,程序不會報錯,也不會在運行時出現(xiàn)任何異常,但反過來卻不一定成立。

應用:在繼承類時,務必重寫(Override)父類中所有的方法,尤其需要注意父類的 protected 方法(它們往往是讓您重寫的),子類盡量不要暴露自己的 public 方法供外界調(diào)用。

4. 迪米特法則(Least Knowledge Principle - LKP)

譯文:只與你最直接的朋友交流。

理解:盡量減少對象之間的交互,從而減小類之間的耦合。簡言之,一定要做到:低耦合,高內(nèi)聚。

應用:在做系統(tǒng)設計時,不要讓一個類依賴于太多的其他類,需盡量減小依賴關(guān)系,否則,您死都不知道自己怎么死的。

5. 接口隔離原則(Interface Segregation Principle - ISP)

譯文:一個類與另一個類之間的依賴性,應該依賴于盡可能小的接口。

理解:不要對外暴露沒有實際意義的接口。也就是說,接口是給別人調(diào)用的,那就不要去為難別人了,盡可能保證接口的實用性吧。她好,我也好。

應用:當需要對外暴露接口時,需要再三斟酌,如果真的沒有必要對外提供的,就刪了吧。一旦您提供了,就意味著,您將來要多做一件事情,何苦要給自己找事做呢。

6. 依賴倒置原則(Dependence Inversion Principle - DIP)

譯文:高層模塊不應該依賴于低層模塊,它們應該依賴于抽象。抽象不應該依賴于細節(jié),細節(jié)應該依賴于抽象。

理解:應該面向接口編程,不應該面向?qū)崿F(xiàn)類編程。面向?qū)崿F(xiàn)類編程,相當于就是論事,那是正向依賴(正常人思維);面向接口編程,相當于通過事物表象來看本質(zhì),那是反向依賴,即依賴倒置(程序員思維)。

應用:并不是說,所有的類都要有一個對應的接口,而是說,如果有接口,那就盡量使用接口來編程吧。

將以上六大原則的英文首字母拼在一起就是 SOLID(穩(wěn)定的),所以也稱之為 SOLID 原則。只有滿足了這六大原則,才能設計出穩(wěn)定的軟件架構(gòu)!但它們畢竟只是原則,有些時候我們還是要學會靈活應變,千萬不要生搬硬套,否則只會把簡單問題復雜化。

四. 架構(gòu)設計心得

前幾年一直擔任架構(gòu)師的崗位,對軟件架構(gòu)設計有一定的心得,小編認為架構(gòu)設計時遵循以下三個原則,有助于你做出最好的選擇:合適原則、簡單原則、演化原則

1、合適原則

合適原則宣言:“合適優(yōu)于業(yè)界領(lǐng)先”。

再好的夢想,也需要腳踏實地實現(xiàn)!這里的“腳踏實地”主要體現(xiàn)在下面幾個方面。

1. 將軍難打無兵之仗

沒那么多人,卻想干那么多活,是失敗的第一個主要原因。

2. 羅馬不是一天建成的

沒有那么多積累,卻想一步登天,是失敗的第二個主要原因。

3. 冰山下面才是關(guān)鍵

沒有那么卓越的業(yè)務場景,卻幻想靈光一閃成為天才,是失敗的第三個主要原因。

所以,真正優(yōu)秀的架構(gòu)都是在企業(yè)當前人力、條件、業(yè)務等各種約束下設計出來的,能夠合理地將資源整合在一起并發(fā)揮出最大功效,并且能夠快速落地。這也是很多 BAT 出來的架構(gòu)師到了小公司或者創(chuàng)業(yè)團隊反而做不出成績的原因,因為沒有了大公司的平臺、資源、積累,只是生搬硬套大公司的做法,失敗的概率非常高。

2、簡單原則

簡單原則宣言:“簡單優(yōu)于復雜”。

剛才我聊的這些原因,會在潛意識層面促使初出茅廬的架構(gòu)師,不自覺地追求架構(gòu)的復雜性。然而,“復雜”在制造領(lǐng)域代表先進,在建筑領(lǐng)域代表領(lǐng)先,但在軟件領(lǐng)域,卻恰恰相反,代表的是“問題”。

軟件領(lǐng)域的復雜性體現(xiàn)在兩個方面:

1. 結(jié)構(gòu)的復雜性

結(jié)構(gòu)復雜的系統(tǒng)幾乎毫無例外具備兩個特點:

組成復雜系統(tǒng)的組件數(shù)量更多;

同時這些組件之間的關(guān)系也更加復雜。

結(jié)構(gòu)上的復雜性存在的第二個問題是,某個組件改動,會影響關(guān)聯(lián)的所有組件,這些被影響的組件同樣會繼續(xù)遞歸影響更多的組件。這個問題會影響整個系統(tǒng)的開發(fā)效率,因為一旦變更涉及外部系統(tǒng),需要協(xié)調(diào)各方統(tǒng)一進行方案評估、資源協(xié)調(diào)、上線配合。

結(jié)構(gòu)上的復雜性存在的第三個問題是,定位一個復雜系統(tǒng)中的問題總是比簡單系統(tǒng)更加困難。首先是組件多,每個組件都有嫌疑,因此要逐一排查;其次組件間的關(guān)系復雜,有可能表現(xiàn)故障的組件并不是真正問題的根源。

2. 邏輯的復雜性

邏輯復雜的組件,一個典型特征就是單個組件承擔了太多的功能。以電商業(yè)務為例,常見的功能有:商品管理、商品搜索、商品展示、訂單管理、用戶管理、支付、發(fā)貨、客服……把這些功能全部在一個組件中實現(xiàn),就是典型的邏輯復雜性。

邏輯復雜幾乎會導致軟件工程的每個環(huán)節(jié)都有問題,假設現(xiàn)在淘寶將這些功能全部在單一的組件中實現(xiàn),可以想象一下這個恐怖的場景:

系統(tǒng)會很龐大,可能是上百萬、上千萬的代碼規(guī)模,“clone”一次代碼要 30 分鐘。

幾十、上百人維護這一套代碼,某個“菜鳥”不小心改了一行代碼,導致整站崩潰。

需求像雪片般飛來,為了應對,開幾十個代碼分支,然后各種分支合并、各種分支覆蓋。

產(chǎn)品、研發(fā)、測試、項目管理不停地開會討論版本計劃,協(xié)調(diào)資源,解決沖突。

版本太多,每天都要上線幾十個版本,系統(tǒng)每隔 1 個小時重啟一次。

線上運行出現(xiàn)故障,幾十個人撲上去定位和處理,一間小黑屋都裝不下所有人,整個辦公區(qū)鬧翻天。

綜合前面的分析,我們可以看到,無論是結(jié)構(gòu)的復雜性,還是邏輯的復雜性,都會存在各種問題,所以架構(gòu)設計時如果簡單的方案和復雜的方案都可以滿足需求,最好選擇簡單的方案。

但是,事實上,當軟件系統(tǒng)變得太復雜后,就會有人換一個思路進行重構(gòu)、升級,將它重新變得簡單,這也是軟件開發(fā)的大趨勢。 簡單原則是一個樸素且偉大的原則,Google的MapReduce系統(tǒng)就采用了分而治之的思想,而背后就是將復雜問題轉(zhuǎn)化為簡單問題的典型案例。

3、演化原則

演化原則宣言:“演化優(yōu)于一步到位”。

如果沒有把握“軟件架構(gòu)需要根據(jù)業(yè)務發(fā)展不斷變化”這個本質(zhì),在做架構(gòu)設計的時候就很容易陷入一個誤區(qū):試圖一步到位設計一個軟件架構(gòu),期望不管業(yè)務如何變化,架構(gòu)都穩(wěn)如磐石。為了實現(xiàn)這樣的目標,要么照搬業(yè)界大公司公開發(fā)表的方案;要么投入龐大的資源和時間來做各種各樣的預測、分析、設計。無論哪種做法,后果都很明顯:投入巨大,落地遙遙無期。更讓人沮喪的是,就算跌跌撞撞拼死拼活終于落地,卻發(fā)現(xiàn)很多預測和分析都是不靠譜的。

軟件架構(gòu)設計其實更加類似于大自然“設計”一個生物,通過演化讓生物適應環(huán)境,逐步變得更加強大。

大到人類社會、自然生物,小到一個細胞,似乎都遵循這一普世原則,軟件架構(gòu)也不例外。業(yè)務在發(fā)展、技術(shù)在創(chuàng)新、外部環(huán)境在變化,這一切都是在告誡架構(gòu)師不要貪大求全,或者盲目照搬大公司的做法。應該認真分析當前業(yè)務的特點,明確業(yè)務面臨的主要問題,設計合理的架構(gòu),快速落地以滿足業(yè)務需要,然后在運行過程中不斷完善架構(gòu),不斷隨著業(yè)務演化架構(gòu)。懷胎需要十月,早一月或晚一月都很危險。

架構(gòu)即決策。架構(gòu)需要面向業(yè)務需求,并在各種資源(人、財、物、時、事)約束條件下去做權(quán)衡、取舍。而決策就會存在不確定性。采用一些高屋建瓴的設計原則有助于去消除不確定,去逼近解決問題的最優(yōu)解。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容