Article / 文章中心

浅谈软件开发架构模式

发布时间:2022-01-17 点击数:194

作者 | 思禽

文章来源 | 阿里巴巴淘系技术团队


背景和问题



我个人平时会比较慎用“架构”这个词


1.一方面是觉得业界有很多架构大师和架构模式,而我的认知和实践有限;


2.另一方面是因为这个词看着挺高大上、有点务虚,如果不结合实际场景的具体问题来讨论,容易陷入“PHP是最好的语言”这样的辩论赛中。而不同场景中又有各自的问题,程序员们通过自己的理解和思考、针对实际场景对一些架构模式进行了扩展实践,以此来解决遇到的问题,也会基于同一个模式延伸出一些派生概念。


兵无常势,水无常形。 


所以,我个人的观点是:以要解决的问题为出发点,去讨论我们要采用的架构模式(技术方案)。


另外,由于我们是站在很多巨人肩膀上的,讨论时可以站在一些软件设计/开发原则的基础上。


写这篇文章,我也是从解决一些问题的目的出发的:


1.最近和团队同学讨论了相关话题,虽然大多数同学在实践上基本一致,但具体到话术、名词概念和具体使用的理解和实践上有些差异(这是很正常的,因为业界对同一个模式的理解和实践也不同)。我结合一些实际编码场景做了一番陈述,为了避免后续重复大费口舌,所以打算写下来,以后有需要直接发文章链接。


2.由于我个人的认知和实践有限,所以也希望能抛(huan)砖(ying)引(lai)玉(pen),让我学到更多。


3.虽然同一个架构模式在不同业务/技术领域的实施会有区别,但同一个团队内应该保持一致性,因为这样有助于日常的code review、功能模块的交接backup等活动,尤其是有利于使用统一的单测建设方案来保障我们的产品质量


    1. 实际问题:我最近在开发商家合并发货的功能,但由于之前基础发货功能的界面和逻辑并不是我开发的,所以我在修改原有代码、支持有非常多细节逻辑的合并发货能力时,就在担心对原有发(zhong)货(yao)能力的影响。而这时候,如果有单测的保障,我就可以更放心地进行功能升级改造了 —— 别说更复杂的合并发货能力了,而这类诉求在复杂的交易场景里很普遍。


提炼一下我遇到的具体问题:


在由不同开发人员持续迭代、进行功能升级的软件开发活动中,如何保障具有复杂逻辑的商家经营工具的产品质量。

软件开发活动

软件开发活动是整个流程的核心环节:接收产品和视觉设计需求/变更作为输入,然后输出客户可用的终端产品。


而统一的软件开发架构模式,则是我们保障软件开发质量的基础。(这里就不具体展开WHY了)


由于讨论的是具体面向客户使用的业务场景,少不了客户操作交互的视图层(View),所以我从MVC开始谈起。


从表现层的 MVC 谈起

表现层的 MVC


虽然我平时比较慎用“架构”这个词,但我平时喜欢随手拍一些建筑物。


因为建筑之美,会让我联想到软件的架构也应该有美感,毕竟Software Architecture这个概念也是起源于Architecture。


当然,由于软件的可移植性、可复用性,从某些角度来讲,软件架构相比建筑架构有其更复杂的地方。


这时候,架构这个词就会给我一种接地气的感觉:有多少块砖,每块砖做什么用、放到哪里去,这块砖 和 那块砖怎么黏在一起或互相支撑。


MVC诞生至今已经超过40年了(Since 1979),10多年前就得到过很广泛的讨论和实践,穿越时空到今天肯定有其反脆弱性和内在核心价值。


虽然如今乍看起来好像已经过气、被讨论过千百遍了,但仍然有很多程序员会有不同理解和看法,或多或少。


这是很正常的,上面也提到了部分原因,这里具体再展开下。


MVC 在经典三层架构里的位置


MVC是一种通用架构模式,早期PC时代应用在桌面客户端,后来在Web时代变得流行(我以前写PHP也用过相关MVC框架),如今在移动互联网时代也得到广泛应用。


上面这三个场景的应用,都是面向客户的,需要交互表现的。


从MVC命名中的View(视图)也可以看出,MVC模式应用在软件系统架构里的表现层。


在微软官方文档里,也明确把MVC放在Web Presentation Patterns下。

Web Presentation Patterns


我之所以没有在上图中对M-V-C添加箭头线条,是因为在这一点上,不同程序员也有不同理解和实践。(2)


这是第一个需要明确的点:MVC架构模式在多层系统架构里的应用范围。


左侧 业务表现层-业务服务层-基础服务层 是移动端三层架构模式,未涉及到 C/S 交互;右侧是Web B/S场景的三层架构模式。


因为有些应用会比较简单,根本不需要业务服务或基础服务层,纯粹靠一个MVC(或者VC)就能交付出一个Mobile/Web App;而且在一些业务系统里,Web前端/桌面客户端/移动App 也可能会被简化为 大前端/大终端表现层;所以可能基于不同信息,不同程序员对此会有不同认知。


但随着用户终端应用的重要性和复杂度的提升,已经从简单应用发展到复杂多团队协同的平台型或航母级应用,仅靠一个MVC来完成交付是不合适的。


也可以反过来想,程序员会把以下代码放在客户端代码的哪一层:


1.对Web引擎的扩展逻辑。


2.通信协议的结构定义,以及相应的socket连接和通信代码。


3.一个业务相关且UI无关的平台开放能力。


4.Crash捕获、卡顿监控、日志埋点等功能实现,比如Android在做APM相关事情时会采用AOP方式,利用ASM、AspectJ等方案来做字节码插桩。


5.……


业界基于 MVC 模式的不同实践


前面提到不同程序员对MVC模式的理解和实践存在差异,业界大厂亦然,比如苹果、微软,在自身实践MVC模式或者向开发者提供相关文档时,也一样有不同的说法。


  • 微软


微软2014年的文档描述


上图是微软2014年的文档描述。


微软2021年10月份更新的文档中使用了下图:


微软在MVC的实践


可以看出微软在MVC的实践上:


1.Controller可以引用View和Model。


2.View可以引用Model。


3.这里的Model倾向于是Passive。


值得注意的是,微软在文档里写到:


1.强类型视图通常使用 ViewModel 类型,旨在包含要在该视图上显示的数据。 控制器从模型创建并填充 ViewModel 实例。


2.控制器不应由于责任过多而变得过于复杂。 要阻止控制器逻辑变得过于复杂,请将业务逻辑推出控制器并推入域模型。


  • 苹果 & 斯坦福


苹果和斯坦福10年+前给的MVC模式图

上图分别是苹果和斯坦福10年+前给的MVC模式图。之所以把它们放在一起,是因为斯坦福这张图也是他们iOS开发课程上的课件,基本也是基于Apple的官方文档来的。


不过这份官方文档已经是Retired Document,并声明不一定是目前的最佳实践:


Important: This document may not represent best practices for current development. Links to downloads and other resources may no longer be valid.


是的,上图应该产出于移动互联网方兴未艾的时候,随着移动互联网蓬勃发展,“最佳实践”被一路多种挑战 —— MVC也被戏称为Massive View Controller,如何重构Massive View Controller为Lighter View Controller也成为了一个专题。


上面两张图呈现出:


1.Controller引用View和Model,做update操作。


2.Model通过KVO和(广播)通知来触达Controller,驱动Controller做出响应。


3.View通过DataSource、Delegate、Target-Action等方式解耦、弱依赖Controller,由Controller对各种用户操作、UI渲染诉求做出响应。


4.View和Model之间是隔离的。


微软和苹果的异同点


1.相同点:Model包含 所需的数据结构封装,以及相应数据操作的方法定义。即Data + 本地或远端的CURD。


2.差异点:微软给的图中,View可以引用Model,而苹果给的图中不行。


一些问题和思考


1.View有箭头指向Model,这里的引用关系是指什么?是View持有Model.Data数据对象,还是View调用Model.CURD方法。


2.Controller的本意是Controing Logic,那除了ViewController外,是否还可以有其它的XxController,比如DataSourceController、NotificationController?


3.从命名上看,既然ViewController 既有View 又有Controller,那为什么把它放在 C里面,而不放在V里面呢?比如当我们在iOS/Android开发中引入MVVM模式后,ViewController或Activity属于M-VM-V的哪部分呢,