架構與設計
架構是什么?我個人想得很簡單,其實就是架子的結構,譬如動物都有屬于自己的骨架,房子也有自己的結構框架等,這些都屬于現實物體的架構;從這些看來其實架構會影響最終物品的形態和質量(人的骨架那出來的肯定是人形)。這個對于程序來說也是一樣,在這個二進制的世界中,程序員扮演著上帝的角色,為這個世界創造不同的東西。那么,這就需要我們思考如何合理地進行設計物體,其中架構作為物體的根本顯得特別重要。
很多人都認為架構設計必須是一位經驗老道的程序員才能做好的事情。這只能算是說對了一半,經驗豐富的程序員能肩負設計重任,最主要是他對計算機技術相對了解,更能把握一些實現細節,讓設計更加合理。但不是所有經驗豐富的程序員,都能設計出一個出色的架構。對于架構設計來說,豐富的計算機知識只是要求的一部分,更多的要求是需要你是一位業務專家。
都說不懂業務的程序員不是一名好程序員。確實是這樣,如果僅僅追求代碼和算法上的極致,在業務上不假思索,任人擺布的話,對于程序設計是很不利的,至少對于程序架構的可預見性就會變得很低。甚至在業務需求與程序設計發生沖突時,往往會偏側于當前的設計,缺乏對業務的思考。所以很多時候我們會看到程序員跟產品經理開撕,這個需求不能做,那個需求調整需要很長時間。其中有一部分問題就是因為架構設計不合理導致的。
在架構設計范疇中個人覺得對于業務的理解和經驗積累,相對于技術的積累而言是更加重要的。如果要提升設計的能力,我們就應該要爭取成為各種業務專家。
沒有最好,只有最適合
有個朋友經常會發一些代碼過來,然后問我:“阿杰,幫我看看這樣的設計好不好?” 面對這個問題,我真的是一臉懵逼,同時也有點尷尬。一來我不知道需求是什么,沒有辦法評估這樣的設計好壞,二來其實架構設計的核心還是方法論,不同的人所思考的側重點不一樣;因此,設計出來的框架也會不一樣,所以,并沒有好不好的說法,只有符不符合你的需求。
然而很多人都會崇尚技術大牛所談到的架構設計,希望在自己設計時模擬大牛們的做法。但這需要投入精力去研究和了解,每種設計下必定會有屬于自己的設計理念和側重點,這個時候就需要我們深入分析它的使用場景以及該模式下的一些特定和不足。如果做不到這樣,那么你的模擬純屬生搬硬套,不僅沒有發揮架構的效果,反而影響程序的性能和質量。
架構設計 != 設計模式
設計模式是對某一類問題提出的具體解決方案,例如MVC主要是降低視圖與業務邏輯的依賴,觀察者模式則主要是解決消息投遞問題等等。在架構設計的框架設計階段對于一些重點功能模塊會根據實際需求來考慮使用的設計模式。例如:一個帶有即時通訊功能的App,用戶消息接收可能會發生在App的各個界面中,那么就要考慮使用觀察者模式,讓每個界面監聽接收消息的通知,然后進行提示處理。
學好設計模式就一定能做好架構設計?其實這是兩個不對等的概念,它們雖然都是一種思維方式,但是設計模式指具體問題的解決方式,而架構設計則更偏向于多種問題的分析整合,其中包括解決方式和規范約束。
設計思維的養成
首先我覺得要戒掉一個壞習慣,就是一接到任務就急著開始編碼。不管你是不是這個項目的技術負責人、主程、還是團隊中的一名開發人員,首要做的事情就是思考如何實現需求。對負責的內容進行前期的設計,并且產出一定的設計文檔,規范標準等。如果已有架構設計文檔,則要通讀文檔,了解其中的思想以及要注意的地方(例如文檔中提到的約束),然后在其基礎上和理念上設計自己的內容。
同時,還需要培養自己的思維不僅僅是聚焦在開發層面上,要考慮在需求變更時、后續維護時乃至重構時該框架的一些措施。然后配合軟件設計中的高內聚低耦合原則來優化一些設計細節。
當前期的設計完成后,則開始要進行概要設計了,例如模塊核心類型結構。我個人比較習慣使用類型聲明的方式來對程序整體進行構造,這過程中不帶有任何邏輯的實現,但是能體現類型與類型之間的關系,用于快速調整一些不合理的地方或者在設計階段沒有考慮到問題,然后在對架構設計進行修訂。
設計思維的養成是循序漸進的,它需要我們在每一次的工作中培養起來自己對設計過程的感覺。而這種感覺需要大量的經驗和知識去把它支撐起來,并且在這個過程中不斷地進行完善。所以并不是死記硬背或者按照套路就能夠做好架構設計的工作,平時一定要有意識地去培養。
事例實踐
下面我想以《網易新聞》的iOS客戶端作為例來展開說明一下我是怎樣進行一個架構的設計(這里要說明一下:我并不知道網易新聞客戶端的實際設計是怎么樣的,下面只是借助它來說明架構設計的一些主要元素,不會具體到一些很詳細的設計內容),我總結了幾個步驟:
1. 需求分析
首要任務就是清楚自己需要實現什么,未來的業務方向又是怎么樣的?對于新聞客戶端來說,重點功能毋庸置疑就是提供用戶閱讀新聞的途徑,了解或者關注一些前沿資訊。至于《網易新聞》未來會發展成怎么樣我無從得知,也許會有內容變現的可能(畢竟最近又聊起來了這話題)。那么基于這些需求,可以從中提取一些關鍵詞,如下面腦圖所示:
關鍵字的提取有利于需求的分析,方便日后在劃分功能模塊和設計時可以起到指導作用。
2. 規范與約束
很多人一旦接到需求,第一個想法就是開干,盡早把代碼碼出來。我能體會想從編碼中獲取快感的感受,但是在編碼前一定要為自己的設計進行一些限定和說明,否則往后的編碼可以說是混亂的。這個時候就需要借助結構框圖來描述我們的設計和組成,下面是我為新聞客戶端設計的一個框圖:
因為是客戶端的設計,所以這里采用的是流行的MVC設計模式來對程序進行了分層。同時也基于需求的關鍵字對系統模塊進行了劃分,如資訊系統、用戶系統、錢包系統等。基于這個圖我們可以清楚知道什么東西需要以視圖形式展示,需要定義什么實體,以及那些功能屬于那個系統模塊等等。
除了設計圖表,我們應該還要為圖表進行一些文字說明。主要說明是基于什么原則或者以什么基礎設計的,并且要說明其中的一些約束。例如上圖的設計是對需求分析得出重點功能在于資訊和用戶,然后基于App的傳統三層設計得出來的。在這個設計基礎上需要遵循下面約定:
- 不能跨層訪問和操作
- 功能模塊之間的數據實體不能帶有業務功能。
- 業務管理器不能直接對接數據模型,必須通過數據管理來進行操作。
我個人覺得這個步驟是體現整個架構靈魂的一個重要步驟,它定義了架構的形態和內部機制,是一個架構往后能否進入良性發展的基礎。
3. 細化與評估
框架整體設計完成后,接下來的工作就是對框架進行細化和評估。例如上圖的資訊系統需要為它整理核心流程。其中用戶瀏覽資訊流程如下:
補充核心流程的作用在于貫穿整個架構,讓各個模塊串起來形成一個真正整體。至于要用時序圖還是流程圖描述,視具體情況而定。如果需要體驗多端協作的流程可以使用時序圖或者多泳道流程圖,如果重點體現內部流程則使用流程圖。例如用戶對資訊的評論流程則主要體現內部處理,則使用流程圖:
接下來結合核心流程來對資訊系統進行細化:
最后對細化的架構進行一個評估,這個評估會從擴展性、靈活性、兼容性以及可移植性方面進行。那上面的細化后的資訊系統來看,用戶系統直接是對接資訊的視圖層,從設計上來看是降低了對用戶系統的依賴。然后各個層次間的界限也相對分明,不存在跨層訪問的現象,使系統有更強的可擴展性和靈活性。
4. 技術選型
前期設計完成后,就需要對框架進行技術選型。如架構中采用MVC分層,那具體是要使用傳統的MVC模式,還是MVVM,還是MVP等等。在這里我個人覺得傳統的MVC模式就可以勝任,主要是考慮控制器層次已經做了進一步的業務細化,因此在C這一層中的代碼量會減少很多。
然后還有數據存儲需要使用什么方式,由于客戶端的數據存儲只用于簡單的緩存記錄,不設計復雜的查詢功能。因此可以考慮使用文件方式進行存儲。
類似上述的技術選型工作,往往要根據實際的需求來確定所選的技術。如果有多套解決方案,則需要評估其性能、穩定性還有易用程度方面的因素。有時候還需要結合工期來考慮是否使用第三方解決方案還是自主研發。
5. 框架搭建
終于到了編碼前的最后一個階段。在這里我們就需要對前面做的設計工作做一個轉換,將其使用程序的語言來進行描述。這個時候我們需要借助類圖來完成這個過程。如下圖所示:
從類圖來看,基本跟之前的設計圖一致。這個很重要,如果設計出來的類圖跟其他層次圖、框圖出入很大,那很有可能在轉換類圖的過程中出現了一些新的設計思路,這個時候要審閱轉換前后究竟是那部分出現問題,然后再進行修訂和同步。
6. 推進與支持
架構設計其實是一個持續的工作,在進行前期設計工作完成后,就要進入到后期的推進和支持工作。具體的操作是在團隊內部講解你的架構設計相關的東西,讓所有人了解你的設計思路,然后沿著你的思想指導進行后面的開發工作。同時,在推進的過程中會難免遇到實際的問題,這個時候就需要作為架構設計的你去進行分析和評估,然后選擇比較可靠的解決方案來完善之前的設計。
架構設計對我的影響
貌似架構設計已經成為了我工作乃至生活中不可缺少的一部分,我覺得它并不只屬于程序設計,更像是一種藝術創作的思維。平時的我喜歡將一些天馬行空的想法具像化到某個程序當中,這個過程就涉及架構的設計。而每次都讓我都感到興奮,因為在這個過程里面,我總能發現一些之前從未了解過的東西,也能讓自己覺得在不斷地進步。