天天看點

軟體開發架構模式淺談:一些思考和實踐記錄零、背景和問題一、從表現層的MVC談起三、寫在最後,回到問題

零、背景和問題

我個人平時會比較慎用“架構”這個詞,

  • 一方面是覺得業界有很多架構大師和架構模式,而我的認知和實踐有限;
  • 另一方面是因為這個詞看着挺高大上、有點務虛,如果不結合實際場景的具體問題來讨論,容易陷入“PHP是最好的語言”這樣的辯論賽中。而不同場景中又有各自的問題,程式員們通過自己的了解和思考、針對實際場景對一些架構模式進行了擴充實踐,以此來解決遇到的問題,也會基于同一個模式延伸出一些派生概念。
兵無常勢,水無常形。

是以,我個人的觀點是:以要解決的問題為出發點,去讨論我們要采用的架構模式(技術方案)。

另外,由于我們是站在很多巨人肩膀上的,讨論時可以站在一些如SOLID等

軟體設計/開發原則

的基礎上。

寫這篇文章,我也是從解決一些問題的目的出發的:

  1. 最近和團隊同學讨論了相關話題,雖然大多數同學在實踐上基本一緻,但具體到話術、名詞概念和具體使用的了解和實踐上有些差異(這是很正常的,因為業界對同一個模式的了解和實踐也不同)。我結合一些實際編碼場景做了一番陳述,為了避免後續重複大費口舌,是以打算寫下來,以後有需要直接發文章連結。
  2. 由于我個人的認知和實踐有限,是以也希望能抛(huan)磚(ying)引(lai)玉(pen),讓我學到更多。
  3. 雖然同一個架構模式在不同業務/技術領域的實施會有差別,但同一個團隊内應該保持一緻性,因為這樣有助于日常的code review、功能子產品的交接backup等活動,尤其是有利于使用統一的單測建設方案來保障我們的産品品質。
    1. 實際問題:我最近在開發商家合并發貨的功能,但由于之前基礎發貨功能的界面和邏輯并不是我開發的,是以我在修改原有代碼、支援有非常多細節邏輯的合并發貨能力時,就在擔心對原有發(zhong)貨(yao)能力的影響。而這時候,如果有單測的保障,我就可以更放心地進行功能更新改造了 —— 别說更複雜的合并發貨能力了,而這類訴求在複雜的交易場景裡很普遍。

提煉一下我遇到的具體問題:

在由不同開發人員持續疊代、進行功能更新的軟體開發活動中,如何保障具有複雜邏輯的商家經營工具的産品品質。

軟體開發架構模式淺談:一些思考和實踐記錄零、背景和問題一、從表現層的MVC談起三、寫在最後,回到問題

軟體開發活動是整個流程的核心環節:接收産品和視覺設計需求/變更作為輸入,然後輸出客戶可用的終端産品。

而統一的軟體開發架構模式,則是我們保障軟體開發品質的基礎。(這裡就不具體展開WHY了)

由于讨論的是具體面向客戶使用的業務場景,少不了客戶操作互動的視圖層(View),是以我從

MVC

開始談起。

一、從表現層的MVC談起

軟體開發架構模式淺談:一些思考和實踐記錄零、背景和問題一、從表現層的MVC談起三、寫在最後,回到問題

雖然我平時比較慎用“架構”這個詞,但我平時喜歡随手拍一些建築物。

因為建築之美,會讓我聯想到軟體的架構也應該有美感,畢竟Software Architecture這個概念也是起源于Architecture。

這時候,架構這個詞就會給我一種接地氣的感覺:有多少塊磚,每塊磚做什麼用、放到哪裡去,這塊磚 和 那塊磚怎麼黏在一起或互相支撐。

當然,由于軟體的可移植性、可複用性,從某些角度來講,軟體架構相比建築架構有其更複雜的地方。

MVC誕生至今已經超過40年了(Since 1979)

,10多年前就得到過很廣泛的讨論和實踐,穿越時空到今天肯定有其反脆弱性和内在核心價值。

雖然如今乍看起來好像已經過氣、被讨論過千百遍了,但仍然有很多程式員會有不同了解和看法,或多或少。

這是很正常的,上面也提到了部分原因,這裡具體再展開下。

1. MVC在經典 三層架構 裡的位置

MVC是一種通用架構模式,

  • 早期PC時代應用在桌面用戶端,
  • 後來在Web時代變得流行(我以前寫PHP也用過相關MVC架構),
  • 如今在移動網際網路時代也得到廣泛應用。

上面這三個場景的應用,都是面向客戶的,需要互動表現的。

從MVC命名中的View(視圖)也可以看出,MVC模式應用在軟體系統架構裡的表現層。

在業界某知名公司的官方文檔裡,也明确把MVC放在

Web Presentation Patterns

下。

軟體開發架構模式淺談:一些思考和實踐記錄零、背景和問題一、從表現層的MVC談起三、寫在最後,回到問題
我之是以沒有在上圖中對M-V-C添加箭頭線條,是因為在這一點上, 不同程式員也有不同了解和實踐 。( 2

這是第一個需要明确的點:MVC架構模式在多層系統架構裡的應用範圍。

左側 業務表現層-業務服務層-基礎服務層 是移動端三層架構模式,未涉及到 C/S 互動;右側是Web B/S場景的三層架構模式。

因為有些應用會比較簡單,根本不需要業務服務或基礎服務層,純粹靠一個MVC(或者VC)就能傳遞出一個Mobile/Web App;

而且在一些業務系統裡,Web前端/桌面用戶端/移動App 也可能會被簡化為 大前端/大終端表現層;

是以可能基于不同資訊,不同程式員對此會有不同認知。

但随着使用者終端應用的重要性和複雜度的提升,已經從簡單應用發展到複雜多團隊協同的平台型或航母級應用,僅靠一個MVC來完成傳遞是不合适的。

我們也可以反過來想,程式員會把以下代碼放在用戶端代碼的哪一層:

  • 對Web引擎的擴充邏輯。
  • 通信協定的結構定義,以及相應的socket連接配接和通信代碼。
  • 一個業務相關且UI無關的平台開放能力。
  • Crash捕獲、卡頓監控、日志埋點等功能實作,比如Android在做APM相關事情時會采用AOP方式,利用 ASM、AspectJ 等方案來做位元組碼插樁。
  • ……

2. 業界基于MVC模式的不同實踐

前面提到不同程式員對MVC模式的了解和實踐存在差異,

業界大廠亦然,以下會結合業界一些知名且有影響力的公司在MVC模式上的實踐,做進一步的展開讨論。

2.1 知名公司A

知名公司A在指導開發者使用MVC時,推薦下圖方式:

軟體開發架構模式淺談:一些思考和實踐記錄零、背景和問題一、從表現層的MVC談起三、寫在最後,回到問題

可以看出在他們的實踐上:

  1. Controller可以引用View和Model。
  2. View可以引用Model。
  3. 這裡的Model傾向于是Passive。

同時,他們建議:

  • 在強類型視圖場景,控制器從模型建立并填充ViewModel執行個體,該ViewModel 執行個體包含要在該視圖上顯示的資料。
  • 當控制器由于責任過多而變得過于複雜時,也就是業界戲稱的“MVC means Massive View Controller ”,需要将業務邏輯從控制器移出并推入域模型中。

2.2 知名公司B

說到Massive View Controller,知名公司B在移動網際網路方興未艾的時候,推薦下圖所示的MVC實踐方案:

軟體開發架構模式淺談:一些思考和實踐記錄零、背景和問題一、從表現層的MVC談起三、寫在最後,回到問題

上圖呈現出:

  1. Controller引用View和Model。
  2. Model通過一些松耦合方式來觸達Controller,如廣播通知、callback等,驅動Controller做出響應。
  3. View通過代理模式等方案弱依賴Controller,由Controller對各種使用者操作、UI渲染訴求做出響應。
  4. 而View和Model之間是隔離的,Model變化後對View的更新操作全部由Controller負責。

不過相應的官方文檔已經被聲明是過期文檔了,并備注不一定是目前的最佳實踐。

是的,随着移動網際網路蓬勃發展,十年前的“最佳實踐”被一路多種挑戰 —— 在采用這種方案的開發領域中,如何重構Massive View Controller為

Lighter View Controller

已經成為了一個專題。

2.3 對比和思考

A和B的異同點

  • 相同點:Model包含 所需的資料結構封裝,以及相應資料操作的方法定義。即Data + 本地或遠端的CURD。
  • 差異點:在知名公司A給的圖中,View可以引用Model,而在知名公司B給的圖中則不行。

一些問題和思考

  • View有箭頭指向Model,這裡的引用關系是指什麼?是View持有Model.Data資料對象,還是View調用Model.CURD方法。
  • Controller的本意是Controing Logic,那除了ViewController外,是否還可以有其它的XxController,比如DataSourceController、NotificationController?
  • 從命名上看,既然ViewController 既有View 又有Controller,那為什麼把它放在 C裡面,而不放在V裡面呢?比如當我們在iOS/Android開發中引入MVVM模式後,ViewController或Activity屬于M-VM-V的哪部分呢,代碼放在哪個目錄下呢?
  • 我有類名使用ViewModel字尾就代表我使用MVVM模式了嗎?

2.4 Martin Fowler

作為

  1. 重構 : 改善既有代碼的設計 》、《 企業應用架構模式 》等著作的作者,
  2. 靈活軟體開發宣言創作者之一,
  3. MVVM模式誕生時 參考引用 的技術專家,

Martin Fowler給的MVC模式圖如下:

軟體開發架構模式淺談:一些思考和實踐記錄零、背景和問題一、從表現層的MVC談起三、寫在最後,回到問題

和上面知名公司A和B的圖,又不一樣了 *_*

不過他這裡也是認為View可以引用Model的。

2.5 MVC和DDD

Martin Fowler和《

領域驅動設計

》作者

Eric Evans

也讨論過MVC中Model的設計理念:

  • 貧血模型:将Model分為簡(pin)單(xue)的Model資料對象,和處理操作資料對象的Service/Manager/BizLogic等。
    • 示例:為aPerson修改name,則由 CitizenService.changeNameOfPerson( aPerson ) 這種方式來實作。
  • 充血模型:将對應領域的處理邏輯放到領域模型中,使得這個領域模型更飽(chong)滿(xue)。
    • 示例:aPerson要刷牙,則由 aPerson.brushTeeth() 來實作。
    • 補充:充血模型更有面向對象程式設計的味道,尤其是搭配交易領域等業務場景,更有體感。不過稍微細想一下,可能就會發現DDD對設計的要求會更高,進而對研發周期和品質保障提出了新的要求,并且可能引起對現有系統的大規模重構。( 盒馬的DDD實踐

也就是說,大到MVC各個子產品的依賴引用關系,細到Model中的代碼設計方式,業界都有不同的理念和實踐。

Java Web開發領域也對Model的設計産生過非常激烈的讨論。

2.6 小結

先抛開具體子產品的代碼設計方案,基于以上幾種業界大廠或專家的描述,我小結了以下這張圖并标注了待解問題:

軟體開發架構模式淺談:一些思考和實踐記錄零、背景和問題一、從表現層的MVC談起三、寫在最後,回到問題

問題一:如何解決MVC中Controller的膨脹臃腫問題?

要回答如何解決,需要先思考為什麼膨脹。

問題二:View能否引用Model?

  • 要回答能否引用,需要先定義引用關系是什麼。
    • 是持有對象,還是調用CURD接口操作對象。
    • 又或者這兩者沒有必要區分,因為持有的對象本身就可能帶CURD接口。
  • 參考上面相關資料,目前業界有的支援、有的反對。

問題三:存在View -> Model,那麼是否可以反過來存在

Model -> View

和問題二在描述上相反但又有關聯,如果對問題再進一步提問的話:

  • 使用 -> 引用關系,是為了解決什麼問題?
  • 使用 -> 引用關系,會産生什麼問題?

如同文章開頭所說,以上問題需要結合具體場景來展開(見 實際案例結合),盡量從務虛到務實。

3. Redux-like Architecture and Framework

随着前後端分離得更徹底,終端裝置性能和使用者體驗重要性的提升,前端領域也得到了蓬勃發展,開發方式也有了比較大的變化,MVC-like方式不再是主流:

  • UI開發方面從早期的指令式到現在的聲明式。
  • 整體應用和業務邏輯實作方面,從早期的OOP寫法,轉向基于FP的響應式程式設計。比如 Redux的資料流 React的Hook 特性等。
  • 各種架構蓬勃發展,一些概念和模式的提出、實踐應用方面,我個人認為是領先并影響用戶端的。
    • 其中Redux是一個經典案例,并且我覺得Redux官方也挺開放包容的,比如Dan Abramov寫的《 You Might Not Need Redux 》。

和MVC延伸派生出的MVC Family一樣,Redux提出或重新帶火了資料流、狀态管理等概念,開始影響其它平台領域,并誕生了一些架構。

比如

ReSwift swift-composable-architecture

,以及

SwiftUI

裡的

State and Data Flow

軟體開發架構模式淺談:一些思考和實踐記錄零、背景和問題一、從表現層的MVC談起三、寫在最後,回到問題

雖然我也寫過點React,但并沒有怎麼實踐過Redux。

不過這些變化和影響,是我們在解決問題的過程中需要結合考慮的。

二、實際案例結合

1. 常見的資料結構定義和使用

程式 = 資料結構 + 算法。

—— Nicklaus Wirth,Pascal之父,圖靈獎獲得者

這句話乍看起來可能會有點面向過程設計的感覺,但OOP中的對象其實也是由資料+方法組成,而FP則更不用說了。

軟體開發架構模式淺談:一些思考和實踐記錄零、背景和問題一、從表現層的MVC談起三、寫在最後,回到問題

在編碼開發活動中,會存在以上3種資料結構定義和使用方式:

  1. 原生資料結構,比如list/array、map/dictionary、tuple等。
  2. 類似MyContact的資料結構定義,由服務端傳回的資料進行轉化,并可能根據業務邏輯按需加上一些标志位給Controller消費。
  3. 類似ContactViewModel這樣的純粹為視圖View服務的資料結構定義。

補充:

(1)MyContact 和 ContactViewModel 隻是特意區分的命名,實際上 MyContact 也可以是純粹為視圖View服務的資料結構定義。

(2)但是,合适的命名有助于幫助我們思考和編碼,從表達上呈現出我們的傾向和重點。

" There are only two hard things in Computer Science: cache invalidation and naming things. —— Phil Karlton

2. 常見的多複雜卡片的清單場景

這個場景可以部分回答問題一:為什麼Controller會膨脹,以及如何解決。

其它部分答案則落在複雜頁面場景的多delegate、target-action、notification-observer等視圖互動響應的處理邏輯上。

我認為,之前反對View引用Model,就是導緻MVC變成Massive View-Controller的一個原因。

另一個原因我認為是工具鍊隻提供了ViewController這樣的Controller模闆,隐式教導開發者都在這裡寫代碼。

這也可能是因為十幾年前移動網際網路還沒發展起來,移動App的複雜度低,是以提供了在當時簡單夠用的方案。

軟體開發架構模式淺談:一些思考和實踐記錄零、背景和問題一、從表現層的MVC談起三、寫在最後,回到問題

當隻能由Controller 持有-> Model的時候,那麼在多複雜卡片的清單場景中,必須由Controller來更新每個View的屬性/狀态。

  1. MyViewController需要為ContactCell更新它的各種相關屬性,類似的還有AddressCell、PackageCell等。
  2. MyViewController在更新AddressCell展示前,可能還需要先為它計算出合适的富文本展示内容。
  3. MyViewController需要響應不同Cell的點選互動行為,包含但不限于按鈕點選、輸入框變化、富文本跳轉、鍵盤起落等。
  4. MyViewController需要響應CollectionView/TableView的DataSource/Delegate各種方法實作。
  5. MyViewController需要響應Model層的變更通知,或者是另外一個ViewController抛過來的廣播通知。

然後MyViewController就爆炸了。

針對這種場景,我的解法是:

  1. 通過讓View->Model,基于工廠模式,把元件化Cell基于資料更新的布局邏輯交給View負責,如contactCell.configUIWithModel( contactModel )。這樣有點類似上面DDD提到的充血Model,具備高内聚的特點,帶來好處:
    1. 和減輕控制器負擔、推入域模型類似,通過把資料驅動布局的代碼推入元件域内,減輕了MyViewController的負擔。
    2. 利于做這部分元件化Cell的UI測試。
    3. 利于這些元件化視圖複用到其它場景,比如交易管理場景的訂單卡片可以複用到搜尋場景中,不用在SeachViewController裡複制粘貼一大堆代碼,隻需要從Model取一個資料對象丢給元件化Cell即可。
  1. 基于ViewController,拆分出不同職責的擴充,比如MyViewController+Delegate專門複雜響應代理事件處理。
  2. 定義出其它類型的Controller,比如MyDataSourceController,專門為TableView提供資料源,可以類比參考Android中ListView的Adapter+ViewHolder。
工廠模式下,産品的刷漆、烘幹、印花等操作會在内部完成,不會丢一個模型讓客戶去自己貼logo。MVC的每一部分都可以用不同的設計模式來組合實施,實作解耦或動态靈活的目标。

對應下圖:

軟體開發架構模式淺談:一些思考和實踐記錄零、背景和問題一、從表現層的MVC談起三、寫在最後,回到問題

到這裡已經回答了前面的問題一和問題二。

更多解法可以參考上面提到的相關建議,比如lighter view controllers。

這裡采用了 VIew -> Model 的方案,用來參與解決Massive View-Controller的問題,并且讓View更容易複用和做UI測試,帶來了好處。

可以結合前面提到的

“當控制器由于責任過多而變得過于複雜時,需要将業務邏輯從控制器移出并推入域模型中。”

再進一步讨論下。

我的了解和舉例:

  1. 存在一個輸入框,讓使用者送出物流單号。
  2. 使用者在輸入過程或者完成輸入後,由View通過delegate模式路由給Controller做校驗,而Controller可能還要進一步依賴Model去做更完整的校驗(如網絡請求到服務端,因為物流單号的規則很多而且可能動态更新)。
  3. 當Controller責任過多、代碼膨脹、過于複雜時,就将物流單号這塊業務邏輯推入 物流(單号)域模型中,即由View直接通過delegate模式交給 LogisticsModel來做校驗。
  4. 也是 View -> Model 。

不一定對,抛(huan)磚(ying)引(lai)玉(pen)。

那麼,存在VIew -> Model,有什麼壞處嗎?

3. 一個Kotlin跨平台場景案例

這裡不具體展開講Kotlin及其跨平台相關内容,隻是描述從MVC模式做跨平台遷移時遇到的問題。

軟體開發架構模式淺談:一些思考和實踐記錄零、背景和問題一、從表現層的MVC談起三、寫在最後,回到問題
這裡的ViewController/Activity放在哪裡,也和上面的一個問題相呼應。

雖然

D-KMP

主張通過全新建構工程寫代碼的方式來實踐,但從實際情況出發,絕大多數現有系統都會是以單點嘗試、漸進式的方式來落地,或發展、或回撤。

那麼,如上圖所示:

  1. 如果在既有MVC代碼結構中,View -> Model,在這種漸進式遷移場景下,就需要修改View來适配新的ViewModel。
  2. 如果 View 不引用 Model,則是由 Controller來做膠水層設定更新視圖(指令式UI)。
  3. 後者的好處是,保持View的獨立性,隻需要修改這個業務場景對應的單個Controller即可。因為View具有可複用性,可能在另外還沒準備遷移/改變的子產品裡也有使用。

是以,此處不建議 View -> Model。

那麼,誰對呢?

4. 誰對誰錯的務虛讨論

當有程式員要推薦使用其它架構模式的時候,通常開頭的一句話就是先說MVC模式的問題。

比如ReSwift在寫 Why ReSwift? 時,開頭第一句話就是:Model-View-Controller (MVC) is not a holistic application architecture.

我個人認為,

  • 架構是一個名詞(n.)+動詞(v.)。
    • 架構(n. & v.)是為了幫助 開發者在交流時有一緻的了解、在業務需要時能夠便于擴充、在出問題時能夠快速定位等等(對抗熵增)。具體還是看采用這個架構的得失,要解決什麼問題或帶來什麼好處,然後帶來什麼成本或付出什麼代價。
    • 架構(v.)通過配置設定每部分代碼的職責并為他們取名(好比iOS/Android開發工程師這樣的崗位名稱,讓别人一看就知道是做什麼的),然後幾個名字加在一起 形成了架構模式這個抽象概念。
    • 從具體到抽象,然後再由這個抽象概念去指導程式員實踐寫代碼,促進了架構的傳播,比如MVC、MVP、MVVM、MVVM-C、MVI、MV-Whatever,VIPER,Redux and More……
  • 有時候并不一定是架構模式的錯,還有可能是平台/架構在讓架構模式自傳播時采用的具體方案出了點問題,又或者是開發者自己寫代碼的問題。
  • 有時候架構模式之間也不是互斥的,也可以在不同場景下互補。比如在MVC裡,每個業務表現子產品不一定要有三個元素齊聚,甚至也可以 VC-M-VC 共用一個M(可參考斯坦福iOS開發課程内容)。

有一個實際的業務場景是這麼實踐的:

軟體開發架構模式淺談:一些思考和實踐記錄零、背景和問題一、從表現層的MVC談起三、寫在最後,回到問題

MVC和MVVM在一個業務場景裡相結合。

這裡提到了MVVM,

前面的Kotlin跨平台圖,除了涉及到 View -> Model 的引用關系是否應該存在的讨論,也涉及到了Declarative-UI和MVVM架構模式等概念,

再順便展開下。

4.1 MVVM 和 MVW

MVC、MVP 和 Declarative-UI 這三個名詞概念都有幾十年曆史了,其中聲明式UI在近十年又開始火了起來;

而MVVM則有十幾年曆史。

官方對

MVVM

有這麼一些描述:

  • V和VM是一對多的關系,即View 1:n ViewModel。相比于 MVC裡 Controller 1:n View,顯然MVC的C更容易膨脹,是以上面也提到了使用多Controller方案。
  • V引用VM,VM操作M,而VM不需要引用V(和MVP不同)。VM作為V的上下文,包含V所需用來展示的資料,響應V被使用者觸發的事件。
  • V對M無感覺,反過來 M 對 V和VM 也無感覺。整體是松散解耦的模式。
  • 當VM的屬性值發生變化時,通過資料綁定方式傳達給V。這就需要有機制支撐,有對應的機制MVC也能做資料綁定。

基于上述描述我畫了下圖:

軟體開發架構模式淺談:一些思考和實踐記錄零、背景和問題一、從表現層的MVC談起三、寫在最後,回到問題

總體來說,MVVM是基于事件驅動的、以資料綁定機制為支撐的松散解耦架構模式。

  • 它的前提是有系統/平台/架構的機制支撐,不然實作成本和複雜度有點大。
  • 相比MVC,它的優勢是視圖控制邏輯不太會膨脹,代碼單元更容易被測試,在可讀性、可維護性上更好。
  • 它可能帶來的成本/問題是入門上手較難,簡單場景下使用容易過度設計,複雜場景下出問題調試比較麻煩。

考慮到ViewController在該場景的薄膠水特質,以及也參與視圖展示和使用者響應,是以我把它放在V裡。

由于業界有太多MV-開頭的模式名詞了,是以Angular官方直接聲明了一個MVW:

I hereby declare AngularJS to be MVW framework - Model-View-Whatever. Where Whatever stands for "whatever works for you".

這種聲明有個好處,就是免去了誰對誰錯/誰好誰壞的争執,而重點關注于誰适合。

5. 誰對誰錯的務實案例: VIPER 和分層演變

關于誰對誰錯/誰好誰壞,可以再來看一個案例。

5.1 架構模式的應用

VIPER概念由View、Interactor、Presenter、Entity、Router幾個元素組成,大緻如下:

軟體開發架構模式淺談:一些思考和實踐記錄零、背景和問題一、從表現層的MVC談起三、寫在最後,回到問題

我之前寫過MVC、MVP、MVVM、VIPER等架構模式下的代碼,完全實作或不完全實作。

有一次,我在某個業務表現子產品裡應用VIPER,然後定義了一個XxxNetworkInteractor類,用來負責做網絡請求。

軟體開發架構模式淺談:一些思考和實踐記錄零、背景和問題一、從表現層的MVC談起三、寫在最後,回到問題

5.2 VIPER架構模式的演變

後來随着業務場景的變化,一個業務子產品可能需要對接多套網關服務,

XxxNetworkInteractor就要做抽象隔離,消除業務邏輯對多套網關請求的感覺,并且應用到其它業務子產品。

這就有點像 VPER - I - VPER 模式 —— 多個業務子產品對 Interactor 進行了複用。

軟體開發架構模式淺談:一些思考和實踐記錄零、背景和問題一、從表現層的MVC談起三、寫在最後,回到問題

5.3 進化

  • 随着對接網關數的增加、網關能力的增強,XxxNetworkInteractor也配套建設了更多能力。
  • 随着使用XxxNetworkInteractor的子產品越來越多,不同業務的一些通用訴求和處理邏輯也随之增加。
  • 随着XxxNetworkInteractor的功能越來越強大,代碼越來越多,逐漸需要抽離出一個單獨子產品,不管是從提高編譯速度,還是從封裝暴露等角度。

于是,XxxNetworkSDK.framework誕生了。

軟體開發架構模式淺談:一些思考和實踐記錄零、背景和問題一、從表現層的MVC談起三、寫在最後,回到問題

5.4 退化

再後來,随着技術和業務的變化,底層網關服務ATop成為了領域範圍内的事實标準,之前遇到的問題也消失了,而XxxNetworkSDK又帶來一些成本,比如要配套ATop的能力更新進行疊代維護。

此時,XxxNetworkSDK可以退出曆史舞台了,讓業務子產品直接面向ATop程式設計,這樣既降低了維護成本,又帶來了一定的包大小收益。

軟體開發架構模式淺談:一些思考和實踐記錄零、背景和問題一、從表現層的MVC談起三、寫在最後,回到問題

以後,假如有另外一個領域範圍的業務場景(采用了XTop),要複用最上層的業務子產品,

由于在另外一個領域範圍,業務子產品要從 調用ATop 改為調用XTop。

那麼,接手或負責遷移複用的開發者,會不會在想:為什麼這些業務子產品直接調用ATop,而沒有使用一個XxxNetworkInteractor來做分層隔離呢?讓業務不要感覺具體的資料庫或網絡服務實作。

  • 如果有,他隻要做一件事情:讓XxxNetworkInteractor對接XTop即可。
  • 如果沒有,他需要去替換修改每個業務子產品的調用代碼、傳回值處理等等。

三、寫在最後,回到問題

不管是務虛的讨論,還是務實的案例,或者是Angular的“whatever works for you”的觀點,

結論是沒有誰對誰錯、誰好誰壞,隻有實際場景下要解決的核心問題。

那麼,回到想要解決的問題:

我的想法是以可測性作為手段,來保障功能更新改造或代碼重構後,可在合理時間範圍内得到充分回歸驗收,保障相關元件、子產品或整體産品的品質。

具體的方案實施上,因為是以可測性為重要關注點,再結合目前的技術方向,我會傾向于采用MVVM。

  • MVVM的架構模式在了解和認知上比較成熟(應該是移動端開發領域TOP2流行的),便于實施和傳播,并通過模式的名稱來展現要強調的關注點:可測性。
  • MVVM可以更好地結合SwiftUI+Combine 、Kotlin跨平台等技術方向。
  • MVVM完全版的上手門檻和簡單場景的過度設計問題,可以通過采用不完全版MVVM來解決。
    • 不完全版的MVVM可以cover适用于簡單場景的MVC,近似于 超集-子集 關系。
    • 雖然也可以通過多Controller的方式來解決MVC膨脹問題,但MVC的命名在實踐中就容易讓程式員弱化掉可測性這個關注點(也可能是我個人了解和實踐不夠正确)。
  • 複雜場景的調試問題、更多可測性的實踐,需要再摸索下,也希望得到相關分享和指點。