移動(dòng)端架構(gòu)與網(wǎng)站架構(gòu)的區(qū)別是什么?網(wǎng)易新聞客戶端的架構(gòu)演進(jìn)歷程是怎樣的?為什么要選擇 DDD 思想來(lái)指導(dǎo)重構(gòu)?DDD 落地中應(yīng)當(dāng)關(guān)注哪些方面?帶著這些問(wèn)題我們來(lái)看下文。(節(jié)選自網(wǎng)易新聞App架構(gòu)重構(gòu)實(shí)踐)
當(dāng)前,大多數(shù)移動(dòng)開發(fā)團(tuán)隊(duì)選擇以 MVP 作為業(yè)務(wù)層的核心架構(gòu)模型,在此基礎(chǔ)上實(shí)現(xiàn)了客戶端的組件化、插件化、容器化等,但作為業(yè)務(wù)層核心的 MVP 架構(gòu)模式至今仍有諸多弊端。網(wǎng)易新聞 App 在領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(DDD)思想指導(dǎo)下,對(duì)其架構(gòu)做了整體重構(gòu),得到了不錯(cuò)的重構(gòu)質(zhì)量與項(xiàng)目收益。
1移動(dòng)端架構(gòu)與網(wǎng)站架構(gòu)的區(qū)別
傳統(tǒng)意義上的網(wǎng)站架構(gòu),通過(guò)超文本傳輸協(xié)議,瀏覽器可以快捷方便地將我們想要訪問(wèn)的頁(yè)面呈現(xiàn)在眼前。每個(gè)網(wǎng)站由多個(gè)頁(yè)面組成,這些頁(yè)面也都屬于 Web Server 的一部分,如圖 1 所示。
圖 1 Website 與 Server 抽象模型
網(wǎng)站大多數(shù)時(shí)候不需要關(guān)注離線化,而主要關(guān)注負(fù)載均衡、高并發(fā)和多級(jí)緩存等場(chǎng)景,以實(shí)時(shí)響應(yīng)大規(guī)模流量。
而移動(dòng)端 App 需要用戶先進(jìn)行安裝操作,然后再進(jìn)行頁(yè)面訪問(wèn),其中的高并發(fā)網(wǎng)絡(luò)請(qǐng)求等場(chǎng)景通常交由 Server 端處理,移動(dòng)端則更關(guān)注處理用戶交互與界面變化,如圖 2 所示。
圖 2 Application 與 Server 抽象模型
所以移動(dòng)端和網(wǎng)站端的核心關(guān)注點(diǎn)不同,也就造成了二者在架構(gòu)上的歷史演進(jìn)的不同。舉一個(gè)簡(jiǎn)單的例子,最初起源于 .NET Framework 3.0 的模型 / 視圖 / 視圖模型(MVVM)思想,從 WPF 應(yīng)用過(guò)渡到 ASP.NET,用于網(wǎng)頁(yè)的開發(fā),后來(lái)卻在移動(dòng)端成為最流行的架構(gòu)模式之一。
隨著網(wǎng)站端的歷史演進(jìn),網(wǎng)頁(yè)的工作量和跨平臺(tái)的需求增長(zhǎng)迅速,使得網(wǎng)站前端開發(fā)的重要性日趨明顯,網(wǎng)站端已經(jīng)抽象為了前端和后端,網(wǎng)站前端通過(guò)瀏覽器實(shí)現(xiàn)跨平臺(tái),與移動(dòng)端共同組成了大前端。
目前常見的移動(dòng)端架構(gòu)設(shè)計(jì)模式主要包括關(guān)注面向接口編程的 MVP(Model-View-Presenter)、關(guān)注數(shù)據(jù)驅(qū)動(dòng)與雙向綁定的 MVVM(Model-View-ViewModel)、關(guān)注表現(xiàn)層分離的 MVC(Mode-View-Controller)和符合領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)思想(DDD)的 The Clean Architecture 等。
2 網(wǎng)易新聞客戶端的架構(gòu)演進(jìn)歷程
網(wǎng)易新聞客戶端的架構(gòu)演進(jìn)主要經(jīng)歷了四個(gè)階段:Static Method、MVP、MVPs 和 VIPER。
為擺脫沉重晦澀的架構(gòu)模型束縛,網(wǎng)易新聞客戶端團(tuán)隊(duì)將一些軟件設(shè)計(jì)中的元素抽象為輕松的食品加工中的元素,用蛋糕模型來(lái)做示例。
第一階段:Static Method
從最初的設(shè)計(jì)階段開始,為了簡(jiǎn)單地達(dá)到代碼的可復(fù)用性,新聞客戶端采用了一種 Static Method 的設(shè)計(jì)方式,將業(yè)務(wù)邏輯按照業(yè)務(wù)模塊轉(zhuǎn)移到一些工具類中,使得開發(fā)人員可以用最小成本復(fù)用這些業(yè)務(wù)邏輯。
在 Static Method 的模式中,技術(shù)團(tuán)隊(duì)將 View 抽象為一塊蛋糕,蛋糕上面需要奶油,檸檬,櫻桃(Model)等食材,所有負(fù)責(zé)輸送材料的加工廠(Static Method)派工人(而不是廚師)將材料直接運(yùn)送并擺放在蛋糕上面,如圖 3 所示。這使得蛋糕最后擁有了所有他該有的食材成分。但這些食材存在隨意擺放,使蛋糕變得混亂的情況,如果再繼續(xù)這樣堆砌食材,它就不再像是一塊蛋糕了。
圖 3 Static Method 蛋糕加工模型
所以,隨著時(shí)間的推進(jìn)和業(yè)務(wù)迭代的不斷加速,這種喪失了封裝、多態(tài)和繼承的面向?qū)ο筇匦缘墓ぞ哳愒O(shè)計(jì),難以應(yīng)對(duì)業(yè)務(wù)的變化,過(guò)渡到流行的 MVP 模式已成必然趨勢(shì)。
第二階段:MVP
傳統(tǒng)的 MVP 模式中,一個(gè) View 由一個(gè) Presenter 管理,在這種模式下產(chǎn)生了代碼復(fù)用的難題。
由于 Presenter 與 View 通過(guò)接口協(xié)議綁定,通常一個(gè) Presenter 里的業(yè)務(wù)邏輯只能為一個(gè) View 服務(wù),代碼復(fù)用性的喪失會(huì)導(dǎo)致大量冗余代碼的產(chǎn)生。
Presenter 與 View 為一對(duì)一的方式,就像一塊蛋糕(View),指派給一個(gè)廚師(Presenter)去制作,但是廚師一個(gè)人需要做的事情太多,他需要親自加工食材(Model),再將這些材料一一裝飾在蛋糕上面,如圖 4 所示。如果這時(shí)候再告訴他我們的蛋糕還需要添加一些突然增加的裝飾和點(diǎn)綴,他可能會(huì)面臨崩潰。
圖 4 MVP 蛋糕加工模型
第三階段:MVPs
為了解決 MVP 代碼復(fù)用的問(wèn)題,大多數(shù)的設(shè)計(jì)方式都是將 View 與 Presenter 改為多對(duì)一的模式,使得一個(gè) Presenter 可以為多個(gè) View 服務(wù),而一個(gè) View 也被多個(gè) Presenter 控制。更多的 Presenter 介入也意味著這些 Presenter 為了適應(yīng)不同的 View 將產(chǎn)生更多的接口。
Presenter 與 View 為多對(duì)一的方式,就像一塊蛋糕(View),指派給多個(gè)廚師(Presenters)在共同加工。而每個(gè)廚師可能會(huì)處理多塊蛋糕,他們同時(shí)還要做好手上的裝飾品(Model),再親自將其放在每個(gè)蛋糕上。在這期間,廚師們直接接觸每塊蛋糕時(shí),還加入了很多他們擅長(zhǎng)的但是蛋糕不需要的手藝。多個(gè)廚師圍著一塊蛋糕轉(zhuǎn),蛋糕有了很多他原本不想擁有的東西,而這些廚師們也難以管理,他們直接操控蛋糕,沒(méi)人能夠合理控制他們,如圖 5 所示。所以,新聞客戶端過(guò)渡到了符合 DDD 的 VIPER 模式下。
圖 5 MVPs 蛋糕加工模型
第四階段:符合 DDD 的 VIPER
在符合領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的 VIPER 架構(gòu)設(shè)計(jì)模式下,一塊蛋糕(View)只由一個(gè)主廚(Presenter)進(jìn)行裝飾擺放,但是蛋糕上所有的飾品食材,都由這位主廚指派給多個(gè)不同的廚師(Interactor)進(jìn)行加工(Entity)。當(dāng)這些廚師加工完畢后,再把材料送過(guò)來(lái),通知主廚,由主廚親自進(jìn)行擺放。
那些負(fù)責(zé)加工的廚師沒(méi)有機(jī)會(huì)再直接接觸到蛋糕,蛋糕只有它原本應(yīng)有的樣子,變得更加利于加工制作。更美好的是,以往蛋糕需要每個(gè)廚師親自配送到它需要被送達(dá)的地方,現(xiàn)在廚師只需要打個(gè)電話,一切配送工作都將由快遞員(Router)去完成,如圖 6 所示。
圖 6 VIPER 蛋糕加工模型
3基于 DDD 的短視頻架構(gòu)優(yōu)化
以網(wǎng)易新聞客戶端的視頻詳情頁(yè)為例,新聞客戶端的視頻詳情頁(yè)結(jié)構(gòu)可以抽象為圖 7。初期設(shè)計(jì)的視頻詳情頁(yè),所承載的業(yè)務(wù)并不多,界面也較為簡(jiǎn)單,Holder、子頁(yè)面和適配器等都在 Fragment 類中定義實(shí)現(xiàn)。但是隨著短視頻風(fēng)口的到來(lái),業(yè)務(wù)加速迭代,視頻的業(yè)務(wù)需求急劇增加,視頻詳情頁(yè)所需要承載的業(yè)務(wù)也越來(lái)越多,F(xiàn)ragment 類從最初的幾百行,急速擴(kuò)張到兩千多行?;谂f有的視頻詳情頁(yè)設(shè)計(jì),加入新的業(yè)務(wù),使得維護(hù)成本變得越來(lái)越高,類也變得越來(lái)越大,臃腫膨脹的類已經(jīng)變?yōu)榱恕懊鏃l代碼”。
圖 7 視頻詳情頁(yè)抽象結(jié)構(gòu)
基于 DDD 的思想,新聞客戶端實(shí)現(xiàn)了一套包含 UseCase 的基礎(chǔ)框架,劃分出了領(lǐng)域模型,由于視頻詳情頁(yè)由多 Fragment 組成,技術(shù)團(tuán)隊(duì)還加入了共享變量層,使擁有統(tǒng)一生命周期的組件之間能解耦傳遞數(shù)據(jù),重構(gòu)后的視頻詳情頁(yè)整體架構(gòu)如圖 8 所示。
圖 8 視頻詳情頁(yè)重構(gòu)后的架構(gòu)設(shè)計(jì)圖
4 DDD 的選型與實(shí)踐
選型背景
新聞客戶端的多數(shù)業(yè)務(wù)模塊在設(shè)計(jì)初期的時(shí)候,承載的業(yè)務(wù)都不是很多。當(dāng)某些業(yè)務(wù)模塊的需求逐漸增加,開發(fā)人員為了快速完成迭代工作,代碼經(jīng)常會(huì)沖刺堆積在一起,久而久之,業(yè)務(wù)模塊之間的邊界變得越來(lái)越不清晰,耦合也變得越來(lái)越嚴(yán)重。
DDD 的限界上下文可以幫助技術(shù)團(tuán)隊(duì)定義出清晰的領(lǐng)域模型邊界,以達(dá)到解耦的目的。VIPER 是符合 DDD 理念的架構(gòu)模型,VIPER 曾一直流行于 iOS 端,在 Android 端的應(yīng)用案例非常少,但其實(shí) VIPER 的核心思想是 The Clean Architecture,所以它同樣適用于 Android 端,是一個(gè)通用的解決方案。
落地難題
在將 DDD 落地的過(guò)程中,團(tuán)隊(duì)遇到的比較困難的問(wèn)題大致是兩方面,一方面在于優(yōu)化工作流程,另一方面在于轉(zhuǎn)變編碼思想。
在工作流程方面,大多數(shù)互聯(lián)網(wǎng)公司都會(huì)有需求評(píng)審會(huì),其中會(huì)有產(chǎn)品經(jīng)理、項(xiàng)目經(jīng)理、軟件工程師、UI 交互設(shè)計(jì)師等參與。但傳統(tǒng)形式的需求評(píng)審主要關(guān)注點(diǎn)還是在整體的業(yè)務(wù)本身,在事件劃分上是非常模糊的,這與確定限界上下文的事件風(fēng)暴相差一段距離,推動(dòng)多個(gè)團(tuán)隊(duì)變更評(píng)審方式的難度比較大。所以,開發(fā)團(tuán)隊(duì)內(nèi)部在編碼階段開始前,還會(huì)進(jìn)行一次技術(shù)評(píng)審,由準(zhǔn)領(lǐng)域?qū)<覀儏⑴c到其中,與開發(fā)人員共同分析討論界限上下文。
在編碼思想方面,需要團(tuán)隊(duì)成員接受 DDD 的思想,轉(zhuǎn)變?yōu)轭I(lǐng)域驅(qū)動(dòng)思維,技術(shù)團(tuán)隊(duì)在內(nèi)部進(jìn)行了一系列相關(guān)的分享,通過(guò)編程中的“隱喻”,讓大家循序漸進(jìn)地建立對(duì) DDD 的認(rèn)知,逐步加深了解。
重構(gòu)效果
在基于 DDD 的架構(gòu)重構(gòu)初期,新聞客戶端選取了視頻詳情、視頻列表和圖集三個(gè)業(yè)務(wù)模塊使用 VIPER 重構(gòu),對(duì) DDD 進(jìn)行嘗試性探索。
在重構(gòu)質(zhì)量上,由于先確定了領(lǐng)域模型,代碼整體解耦符合預(yù)期,三個(gè)模塊重構(gòu)后上線均未產(chǎn)生嚴(yán)重線上問(wèn)題。
在項(xiàng)目收益上,一方面,DDD 幫助團(tuán)隊(duì)加速了迭代的開發(fā)效率,另一方面,代碼的可維護(hù)性也有了比較大的提高,同時(shí),模塊錯(cuò)誤率也約降低了約 50%。
新聞客戶端以半年為一個(gè)維度,統(tǒng)計(jì)出模塊重構(gòu)前半年和重構(gòu)后半年的系統(tǒng)故障率(主要指程序開發(fā)期間產(chǎn)生的問(wèn)題),得出了如圖 9 所示的信息。數(shù)據(jù)發(fā)現(xiàn),越是業(yè)務(wù)變化很頻繁的模塊(如視頻),通過(guò) DDD 獲得的模塊穩(wěn)定性收益就越大。
圖 9 DDD 重構(gòu)前后系統(tǒng)故障率統(tǒng)計(jì)圖
5 DDD 落地面面觀
DDD 從 2003 年被提出來(lái)以后,得到了軟件學(xué)術(shù)界的高度認(rèn)可,但由于國(guó)內(nèi)外開發(fā)環(huán)境和開發(fā)人員思想理念不同等多種影響,導(dǎo)致 DDD 在國(guó)內(nèi)的實(shí)踐并不是很理想。從 2013 年開始,微服務(wù)架構(gòu)和中臺(tái)化在國(guó)內(nèi)逐漸盛行,而 DDD 可以作為其指導(dǎo)思想,幫助微服務(wù)架構(gòu)進(jìn)行清晰的領(lǐng)域和子域劃分,DDD 逐漸在企業(yè)應(yīng)用實(shí)踐上獲得理想的成果,這正是 DDD 在國(guó)內(nèi)突然變得流行的最主要原因之一。
對(duì)于開發(fā)團(tuán)隊(duì)來(lái)說(shuō),實(shí)踐 DDD 最重要的一步就是通過(guò)事件風(fēng)暴來(lái)進(jìn)行領(lǐng)域分析建模,但這對(duì)于帶頭發(fā)起人的領(lǐng)域素養(yǎng)要求較高,需要團(tuán)隊(duì)內(nèi)有一位布道師開路,擔(dān)任領(lǐng)域?qū)<业穆氊?zé)。
針對(duì)移動(dòng)端來(lái)說(shuō),目前最合適的、符合 DDD 的架構(gòu)模型就是 The Clean Architecture,Google 官方推出的安卓藍(lán)圖項(xiàng)目也針對(duì) MVP 提供了一套符合 The Clean Architecture 的 MVP-Clean 項(xiàng)目,開發(fā)者可以由此為起點(diǎn)進(jìn)行逐步探索和嘗試。
由于國(guó)內(nèi)外軟件工程師職業(yè)環(huán)境和所承受的壓力有所不同,在很多突發(fā)性的業(yè)務(wù)需求的沖擊下,使得開發(fā)者只能對(duì)代碼做瘋狂堆疊,導(dǎo)致開發(fā)者不得已放棄 DDD 的設(shè)計(jì),而期間發(fā)生需求變更就很容易導(dǎo)致風(fēng)險(xiǎn)。
當(dāng)風(fēng)險(xiǎn)變?yōu)槲kU(xiǎn)后,發(fā)生各種互相推諉的現(xiàn)象,其問(wèn)題本質(zhì)歸結(jié)起來(lái)無(wú)非是兩方面,一方面是組織結(jié)構(gòu)和環(huán)境所影響,另一方面是邊界劃分不明確。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-409763.html
對(duì)于組織和團(tuán)隊(duì)方面,前期無(wú)需變動(dòng),也可以滿足向 DDD 轉(zhuǎn)型的條件,也為后期再建設(shè)微服務(wù)和中臺(tái)化提供了便利。但需要注意的是,改變團(tuán)隊(duì)成員的固有開發(fā)思維也是十分重要的一個(gè)環(huán)節(jié),團(tuán)隊(duì)內(nèi)應(yīng)該定期組織關(guān)于 DDD 的分享,有利于使大家對(duì) DDD 的觀念潛移默化。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-409763.html
到了這里,關(guān)于Android 下一代架構(gòu)指南:DDD的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!