架構(gòu)與設(shè)計
架構(gòu)是什么?我個人想得很簡單,其實就是架子的結(jié)構(gòu)桃犬,譬如動物都有屬于自己的骨架,房子也有自己的結(jié)構(gòu)框架等行楞,這些都屬于現(xiàn)實物體的架構(gòu)攒暇;從這些看來其實架構(gòu)會影響最終物品的形態(tài)和質(zhì)量(人的骨架那出來的肯定是人形)。這個對于程序來說也是一樣子房,在這個二進制的世界中形用,程序員扮演著上帝的角色,為這個世界創(chuàng)造不同的東西证杭。那么田度,這就需要我們思考如何合理地進行設(shè)計物體,其中架構(gòu)作為物體的根本顯得特別重要解愤。
很多人都認為架構(gòu)設(shè)計必須是一位經(jīng)驗老道的程序員才能做好的事情镇饺。這只能算是說對了一半,經(jīng)驗豐富的程序員能肩負設(shè)計重任送讲,最主要是他對計算機技術(shù)相對了解奸笤,更能把握一些實現(xiàn)細節(jié),讓設(shè)計更加合理李茫。但不是所有經(jīng)驗豐富的程序員揭保,都能設(shè)計出一個出色的架構(gòu)。對于架構(gòu)設(shè)計來說魄宏,豐富的計算機知識只是要求的一部分秸侣,更多的要求是需要你是一位業(yè)務(wù)專家。
都說不懂業(yè)務(wù)的程序員不是一名好程序員宠互。確實是這樣味榛,如果僅僅追求代碼和算法上的極致,在業(yè)務(wù)上不假思索予跌,任人擺布的話搏色,對于程序設(shè)計是很不利的,至少對于程序架構(gòu)的可預(yù)見性就會變得很低券册。甚至在業(yè)務(wù)需求與程序設(shè)計發(fā)生沖突時频轿,往往會偏側(cè)于當(dāng)前的設(shè)計垂涯,缺乏對業(yè)務(wù)的思考。所以很多時候我們會看到程序員跟產(chǎn)品經(jīng)理開撕航邢,這個需求不能做耕赘,那個需求調(diào)整需要很長時間。其中有一部分問題就是因為架構(gòu)設(shè)計不合理導(dǎo)致的膳殷。
在架構(gòu)設(shè)計范疇中個人覺得對于業(yè)務(wù)的理解和經(jīng)驗積累操骡,相對于技術(shù)的積累而言是更加重要的。如果要提升設(shè)計的能力赚窃,我們就應(yīng)該要爭取成為各種業(yè)務(wù)專家册招。
沒有最好,只有最適合
有個朋友經(jīng)常會發(fā)一些代碼過來勒极,然后問我:“阿杰是掰,幫我看看這樣的設(shè)計好不好?” 面對這個問題河质,我真的是一臉懵逼冀惭,同時也有點尷尬。一來我不知道需求是什么掀鹅,沒有辦法評估這樣的設(shè)計好壞散休,二來其實架構(gòu)設(shè)計的核心還是方法論,不同的人所思考的側(cè)重點不一樣乐尊;因此戚丸,設(shè)計出來的框架也會不一樣,所以扔嵌,并沒有好不好的說法限府,只有符不符合你的需求。
然而很多人都會崇尚技術(shù)大牛所談到的架構(gòu)設(shè)計痢缎,希望在自己設(shè)計時模擬大牛們的做法胁勺。但這需要投入精力去研究和了解,每種設(shè)計下必定會有屬于自己的設(shè)計理念和側(cè)重點独旷,這個時候就需要我們深入分析它的使用場景以及該模式下的一些特定和不足署穗。如果做不到這樣,那么你的模擬純屬生搬硬套嵌洼,不僅沒有發(fā)揮架構(gòu)的效果案疲,反而影響程序的性能和質(zhì)量。
架構(gòu)設(shè)計 != 設(shè)計模式
設(shè)計模式是對某一類問題提出的具體解決方案麻养,例如MVC主要是降低視圖與業(yè)務(wù)邏輯的依賴褐啡,觀察者模式則主要是解決消息投遞問題等等。在架構(gòu)設(shè)計的框架設(shè)計階段對于一些重點功能模塊會根據(jù)實際需求來考慮使用的設(shè)計模式鳖昌。例如:一個帶有即時通訊功能的App备畦,用戶消息接收可能會發(fā)生在App的各個界面中低飒,那么就要考慮使用觀察者模式,讓每個界面監(jiān)聽接收消息的通知萍恕,然后進行提示處理逸嘀。
學(xué)好設(shè)計模式就一定能做好架構(gòu)設(shè)計车要?其實這是兩個不對等的概念允粤,它們雖然都是一種思維方式,但是設(shè)計模式指具體問題的解決方式翼岁,而架構(gòu)設(shè)計則更偏向于多種問題的分析整合类垫,其中包括解決方式和規(guī)范約束。
設(shè)計思維的養(yǎng)成
首先我覺得要戒掉一個壞習(xí)慣琅坡,就是一接到任務(wù)就急著開始編碼悉患。不管你是不是這個項目的技術(shù)負責(zé)人、主程榆俺、還是團隊中的一名開發(fā)人員售躁,首要做的事情就是思考如何實現(xiàn)需求。對負責(zé)的內(nèi)容進行前期的設(shè)計茴晋,并且產(chǎn)出一定的設(shè)計文檔陪捷,規(guī)范標準等。如果已有架構(gòu)設(shè)計文檔诺擅,則要通讀文檔市袖,了解其中的思想以及要注意的地方(例如文檔中提到的約束),然后在其基礎(chǔ)上和理念上設(shè)計自己的內(nèi)容烁涌。
同時苍碟,還需要培養(yǎng)自己的思維不僅僅是聚焦在開發(fā)層面上,要考慮在需求變更時撮执、后續(xù)維護時乃至重構(gòu)時該框架的一些措施微峰。然后配合軟件設(shè)計中的高內(nèi)聚低耦合原則來優(yōu)化一些設(shè)計細節(jié)。
當(dāng)前期的設(shè)計完成后抒钱,則開始要進行概要設(shè)計了蜓肆,例如模塊核心類型結(jié)構(gòu)。我個人比較習(xí)慣使用類型聲明的方式來對程序整體進行構(gòu)造继效,這過程中不帶有任何邏輯的實現(xiàn)症杏,但是能體現(xiàn)類型與類型之間的關(guān)系,用于快速調(diào)整一些不合理的地方或者在設(shè)計階段沒有考慮到問題瑞信,然后在對架構(gòu)設(shè)計進行修訂厉颤。
設(shè)計思維的養(yǎng)成是循序漸進的,它需要我們在每一次的工作中培養(yǎng)起來自己對設(shè)計過程的感覺凡简。而這種感覺需要大量的經(jīng)驗和知識去把它支撐起來逼友,并且在這個過程中不斷地進行完善精肃。所以并不是死記硬背或者按照套路就能夠做好架構(gòu)設(shè)計的工作,平時一定要有意識地去培養(yǎng)帜乞。
事例實踐
下面我想以《網(wǎng)易新聞》的iOS客戶端作為例來展開說明一下我是怎樣進行一個架構(gòu)的設(shè)計(這里要說明一下:我并不知道網(wǎng)易新聞客戶端的實際設(shè)計是怎么樣的司抱,下面只是借助它來說明架構(gòu)設(shè)計的一些主要元素,不會具體到一些很詳細的設(shè)計內(nèi)容)黎烈,我總結(jié)了幾個步驟:
1. 需求分析
首要任務(wù)就是清楚自己需要實現(xiàn)什么习柠,未來的業(yè)務(wù)方向又是怎么樣的?對于新聞客戶端來說照棋,重點功能毋庸置疑就是提供用戶閱讀新聞的途徑资溃,了解或者關(guān)注一些前沿資訊。至于《網(wǎng)易新聞》未來會發(fā)展成怎么樣我無從得知烈炭,也許會有內(nèi)容變現(xiàn)的可能(畢竟最近又聊起來了這話題)溶锭。那么基于這些需求,可以從中提取一些關(guān)鍵詞符隙,如下面腦圖所示:
關(guān)鍵字的提取有利于需求的分析趴捅,方便日后在劃分功能模塊和設(shè)計時可以起到指導(dǎo)作用。
2. 規(guī)范與約束
很多人一旦接到需求霹疫,第一個想法就是開干拱绑,盡早把代碼碼出來。我能體會想從編碼中獲取快感的感受更米,但是在編碼前一定要為自己的設(shè)計進行一些限定和說明欺栗,否則往后的編碼可以說是混亂的。這個時候就需要借助結(jié)構(gòu)框圖來描述我們的設(shè)計和組成征峦,下面是我為新聞客戶端設(shè)計的一個框圖:
因為是客戶端的設(shè)計迟几,所以這里采用的是流行的MVC設(shè)計模式來對程序進行了分層。同時也基于需求的關(guān)鍵字對系統(tǒng)模塊進行了劃分栏笆,如資訊系統(tǒng)类腮、用戶系統(tǒng)、錢包系統(tǒng)等蛉加⊙潦啵基于這個圖我們可以清楚知道什么東西需要以視圖形式展示,需要定義什么實體针饥,以及那些功能屬于那個系統(tǒng)模塊等等厂抽。
除了設(shè)計圖表,我們應(yīng)該還要為圖表進行一些文字說明丁眼。主要說明是基于什么原則或者以什么基礎(chǔ)設(shè)計的筷凤,并且要說明其中的一些約束。例如上圖的設(shè)計是對需求分析得出重點功能在于資訊和用戶,然后基于App的傳統(tǒng)三層設(shè)計得出來的藐守。在這個設(shè)計基礎(chǔ)上需要遵循下面約定:
- 不能跨層訪問和操作
- 功能模塊之間的數(shù)據(jù)實體不能帶有業(yè)務(wù)功能挪丢。
- 業(yè)務(wù)管理器不能直接對接數(shù)據(jù)模型,必須通過數(shù)據(jù)管理來進行操作卢厂。
我個人覺得這個步驟是體現(xiàn)整個架構(gòu)靈魂的一個重要步驟乾蓬,它定義了架構(gòu)的形態(tài)和內(nèi)部機制,是一個架構(gòu)往后能否進入良性發(fā)展的基礎(chǔ)慎恒。
3. 細化與評估
框架整體設(shè)計完成后任内,接下來的工作就是對框架進行細化和評估。例如上圖的資訊系統(tǒng)需要為它整理核心流程巧号。其中用戶瀏覽資訊流程如下:
補充核心流程的作用在于貫穿整個架構(gòu)族奢,讓各個模塊串起來形成一個真正整體。至于要用時序圖還是流程圖描述丹鸿,視具體情況而定。如果需要體驗多端協(xié)作的流程可以使用時序圖或者多泳道流程圖棚品,如果重點體現(xiàn)內(nèi)部流程則使用流程圖靠欢。例如用戶對資訊的評論流程則主要體現(xiàn)內(nèi)部處理,則使用流程圖:
接下來結(jié)合核心流程來對資訊系統(tǒng)進行細化:
最后對細化的架構(gòu)進行一個評估铜跑,這個評估會從擴展性门怪、靈活性、兼容性以及可移植性方面進行锅纺。那上面的細化后的資訊系統(tǒng)來看掷空,用戶系統(tǒng)直接是對接資訊的視圖層,從設(shè)計上來看是降低了對用戶系統(tǒng)的依賴囤锉。然后各個層次間的界限也相對分明坦弟,不存在跨層訪問的現(xiàn)象,使系統(tǒng)有更強的可擴展性和靈活性官地。
4. 技術(shù)選型
前期設(shè)計完成后酿傍,就需要對框架進行技術(shù)選型。如架構(gòu)中采用MVC分層驱入,那具體是要使用傳統(tǒng)的MVC模式赤炒,還是MVVM,還是MVP等等亏较。在這里我個人覺得傳統(tǒng)的MVC模式就可以勝任莺褒,主要是考慮控制器層次已經(jīng)做了進一步的業(yè)務(wù)細化,因此在C這一層中的代碼量會減少很多雪情。
然后還有數(shù)據(jù)存儲需要使用什么方式遵岩,由于客戶端的數(shù)據(jù)存儲只用于簡單的緩存記錄,不設(shè)計復(fù)雜的查詢功能旺罢。因此可以考慮使用文件方式進行存儲旷余。
類似上述的技術(shù)選型工作绢记,往往要根據(jù)實際的需求來確定所選的技術(shù)。如果有多套解決方案正卧,則需要評估其性能蠢熄、穩(wěn)定性還有易用程度方面的因素。有時候還需要結(jié)合工期來考慮是否使用第三方解決方案還是自主研發(fā)炉旷。
5. 框架搭建
終于到了編碼前的最后一個階段签孔。在這里我們就需要對前面做的設(shè)計工作做一個轉(zhuǎn)換,將其使用程序的語言來進行描述窘行。這個時候我們需要借助類圖來完成這個過程饥追。如下圖所示:
從類圖來看,基本跟之前的設(shè)計圖一致罐盔。這個很重要但绕,如果設(shè)計出來的類圖跟其他層次圖、框圖出入很大惶看,那很有可能在轉(zhuǎn)換類圖的過程中出現(xiàn)了一些新的設(shè)計思路捏顺,這個時候要審閱轉(zhuǎn)換前后究竟是那部分出現(xiàn)問題,然后再進行修訂和同步纬黎。
6. 推進與支持
架構(gòu)設(shè)計其實是一個持續(xù)的工作幅骄,在進行前期設(shè)計工作完成后,就要進入到后期的推進和支持工作本今。具體的操作是在團隊內(nèi)部講解你的架構(gòu)設(shè)計相關(guān)的東西拆座,讓所有人了解你的設(shè)計思路,然后沿著你的思想指導(dǎo)進行后面的開發(fā)工作冠息。同時挪凑,在推進的過程中會難免遇到實際的問題,這個時候就需要作為架構(gòu)設(shè)計的你去進行分析和評估铐达,然后選擇比較可靠的解決方案來完善之前的設(shè)計岖赋。
架構(gòu)設(shè)計對我的影響
貌似架構(gòu)設(shè)計已經(jīng)成為了我工作乃至生活中不可缺少的一部分,我覺得它并不只屬于程序設(shè)計瓮孙,更像是一種藝術(shù)創(chuàng)作的思維唐断。平時的我喜歡將一些天馬行空的想法具像化到某個程序當(dāng)中,這個過程就涉及架構(gòu)的設(shè)計杭抠。而每次都讓我都感到興奮脸甘,因為在這個過程里面,我總能發(fā)現(xiàn)一些之前從未了解過的東西偏灿,也能讓自己覺得在不斷地進步丹诀。