摘要:基于DDD的思想,新闻客户端实现了一套包含UseCase的基础框架,划分出了领域模型,由于视频详情页由多Fragment组成,技术团队还加入了共享变量层,使拥有统一生命周期的组件之间能解耦传递数据,重构后的视频详情页整体架构如图8所示。在基于DDD的架构重构初期,新闻客户端选取了视频详情、视频列表和图集三个业务模块使用VIPER重构,对DDD进行尝试性探索。

作者|小智

嘉宾|李云鹏

当前,大多数移动开发团队选择以MVP作为业务层的核心架构模型,在此基础上实现了客户端的组件化、插件化、容器化等,但作为业务层核心的MVP架构模式至今仍有诸多弊端。网易新闻App在领域驱动设计(DDD)思想指导下,对其架构做了整体重构,得到了不错的重构质量与项目收益。移动端架构与网站架构的区别是什么?网易新闻客户端的架构演进历程是怎样的?为什么要选择DDD思想来指导重构?DDD落地中应当关注哪些方面?带着这些问题,InfoQ记者采访了网易高级客户端工程师李云鹏,他也将在QCon北京2020上带来《在领域驱动设计(DDD)下重构网易新闻APP架构》的演讲。

1

移动端架构与网站架构的区别

传统意义上的网站架构,通过超文本传输协议,浏览器可以快捷方便地将我们想要访问的页面呈现在眼前。每个网站由多个页面组成,这些页面也都属于WebServer的一部分,如图1所示。

图1Website与Server抽象模型

网站大多数时候不需要关注离线化,而主要关注负载均衡、高并发和多级缓存等场景,以实时响应大规模流量。

而移动端App需要用户先进行安装操作,然后再进行页面访问,其中的高并发网络请求等场景通常交由Server端处理,移动端则更关注处理用户交互与界面变化,如图2所示。

图2Application与Server抽象模型

所以移动端和网站端的核心关注点不同,也就造成了二者在架构上的历史演进的不同。举一个简单的例子,最初起源于.NETFramework3.0的模型/视图/视图模型(MVVM)思想,从WPF应用过渡到ASP.NET,用于网页的开发,后来却在移动端成为最流行的架构模式之一。

随着网站端的历史演进,网页的工作量和跨平台的需求增长迅速,使得网站前端开发的重要性日趋明显,网站端已经抽象为了前端和后端,网站前端通过浏览器实现跨平台,与移动端共同组成了大前端。

目前常见的移动端架构设计模式主要包括关注面向接口编程的MVP(Model-View-Presenter)、关注数据驱动与双向绑定的MVVM(Model-View-ViewModel)、关注表现层分离的MVC(Mode-View-Controller)和符合领域驱动设计思想(DDD)的TheCleanArchitecture等。

2

网易新闻客户端的架构演进历程

网易新闻客户端的架构演进主要经历了四个阶段:StaticMethod、MVP、MVPs和VIPER。

为摆脱沉重晦涩的架构模型束缚,网易新闻客户端团队将一些软件设计中的元素抽象为轻松的食品加工中的元素,用蛋糕模型来做示例。

第一阶段:StaticMethod

从最初的设计阶段开始,为了简单地达到代码的可复用性,新闻客户端采用了一种StaticMethod的设计方式,将业务逻辑按照业务模块转移到一些工具类中,使得开发人员可以用最小成本复用这些业务逻辑。

在StaticMethod的模式中,技术团队将View抽象为一块蛋糕,蛋糕上面需要奶油,柠檬,樱桃(Model)等食材,所有负责输送材料的加工厂(StaticMethod)派工人(而不是厨师)将材料直接运送并摆放在蛋糕上面,如图3所示。这使得蛋糕最后拥有了所有他该有的食材成分。但这些食材存在随意摆放,使蛋糕变得混乱的情况,如果再继续这样堆砌食材,它就不再像是一块蛋糕了。

图3StaticMethod蛋糕加工模型

所以,随着时间的推进和业务迭代的不断加速,这种丧失了封装、多态和继承的面向对象特性的工具类设计,难以应对业务的变化,过渡到流行的MVP模式已成必然趋势。

第二阶段:MVP

传统的MVP模式中,一个View由一个Presenter管理,在这种模式下产生了代码复用的难题。

由于Presenter与View通过接口协议绑定,通常一个Presenter里的业务逻辑只能为一个View服务,代码复用性的丧失会导致大量冗余代码的产生。

Presenter与View为一对一的方式,就像一块蛋糕(View),指派给一个厨师(Presenter)去制作,但是厨师一个人需要做的事情太多,他需要亲自加工食材(Model),再将这些材料一一装饰在蛋糕上面,如图4所示。如果这时候再告诉他我们的蛋糕还需要添加一些突然增加的装饰和点缀,他可能会面临崩溃。

图4MVP蛋糕加工模型

第三阶段:MVPs

为了解决MVP代码复用的问题,大多数的设计方式都是将View与Presenter改为多对一的模式,使得一个Presenter可以为多个View服务,而一个View也被多个Presenter控制。更多的Presenter介入也意味着这些Presenter为了适应不同的View将产生更多的接口。

Presenter与View为多对一的方式,就像一块蛋糕(View),指派给多个厨师(Presenters)在共同加工。而每个厨师可能会处理多块蛋糕,他们同时还要做好手上的装饰品(Model),再亲自将其放在每个蛋糕上。在这期间,厨师们直接接触每块蛋糕时,还加入了很多他们擅长的但是蛋糕不需要的手艺。多个厨师围着一块蛋糕转,蛋糕有了很多他原本不想拥有的东西,而这些厨师们也难以管理,他们直接操控蛋糕,没人能够合理控制他们,如图5所示。所以,新闻客户端过渡到了符合DDD的VIPER模式下。

图5MVPs蛋糕加工模型

第四阶段:符合DDD的VIPER

在符合领域驱动设计的VIPER架构设计模式下,一块蛋糕(View)只由一个主厨(Presenter)进行装饰摆放,但是蛋糕上所有的饰品食材,都由这位主厨指派给多个不同的厨师(Interactor)进行加工(Entity)。当这些厨师加工完毕后,再把材料送过来,通知主厨,由主厨亲自进行摆放。

那些负责加工的厨师没有机会再直接接触到蛋糕,蛋糕只有它原本应有的样子,变得更加利于加工制作。更美好的是,以往蛋糕需要每个厨师亲自配送到它需要被送达的地方,现在厨师只需要打个电话,一切配送工作都将由快递员(Router)去完成,如图6所示。

图6VIPER蛋糕加工模型

3

基于DDD的短视频架构优化

以网易新闻客户端的视频详情页为例,新闻客户端的视频详情页结构可以抽象为图7。初期设计的视频详情页,所承载的业务并不多,界面也较为简单,Holder、子页面和适配器等都在Fragment类中定义实现。但是随着短视频风口的到来,业务加速迭代,视频的业务需求急剧增加,视频详情页所需要承载的业务也越来越多,Fragment类从最初的几百行,急速扩张到两千多行。基于旧有的视频详情页设计,加入新的业务,使得维护成本变得越来越高,类也变得越来越大,臃肿膨胀的类已经变为了“面条代码”。

图7视频详情页抽象结构

基于DDD的思想,新闻客户端实现了一套包含UseCase的基础框架,划分出了领域模型,由于视频详情页由多Fragment组成,技术团队还加入了共享变量层,使拥有统一生命周期的组件之间能解耦传递数据,重构后的视频详情页整体架构如图8所示。

图8视频详情页重构后的架构设计图

4

DDD的选型与实践

选型背景

新闻客户端的多数业务模块在设计初期的时候,承载的业务都不是很多。当某些业务模块的需求逐渐增加,开发人员为了快速完成迭代工作,代码经常会冲刺堆积在一起,久而久之,业务模块之间的边界变得越来越不清晰,耦合也变得越来越严重。

DDD的限界上下文可以帮助技术团队定义出清晰的领域模型边界,以达到解耦的目的。VIPER是符合DDD理念的架构模型,VIPER曾一直流行于iOS端,在Android端的应用案例非常少,但其实VIPER的核心思想是TheCleanArchitecture,所以它同样适用于Android端,是一个通用的解决方案。

落地难题

在将DDD落地的过程中,团队遇到的比较困难的问题大致是两方面,一方面在于优化工作流程,另一方面在于转变编码思想。

在工作流程方面,大多数互联网公司都会有需求评审会,其中会有产品经理、项目经理、软件工程师、UI交互设计师等参与。但传统形式的需求评审主要关注点还是在整体的业务本身,在事件划分上是非常模糊的,这与确定限界上下文的事件风暴相差一段距离,推动多个团队变更评审方式的难度比较大。所以,开发团队内部在编码阶段开始前,还会进行一次技术评审,由准领域专家们参与到其中,与开发人员共同分析讨论界限上下文。

在编码思想方面,需要团队成员接受DDD的思想,转变为领域驱动思维,技术团队在内部进行了一系列相关的分享,通过编程中的“隐喻”,让大家循序渐进地建立对DDD的认知,逐步加深了解。

重构效果

在基于DDD的架构重构初期,新闻客户端选取了视频详情、视频列表和图集三个业务模块使用VIPER重构,对DDD进行尝试性探索。

在重构质量上,由于先确定了领域模型,代码整体解耦符合预期,三个模块重构后上线均未产生严重线上问题。

在项目收益上,一方面,DDD帮助团队加速了迭代的开发效率,另一方面,代码的可维护性也有了比较大的提高,同时,模块错误率也约降低了约50%。

新闻客户端以半年为一个维度,统计出模块重构前半年和重构后半年的系统故障率(主要指程序开发期间产生的问题),得出了如图9所示的信息。数据发现,越是业务变化很频繁的模块(如视频),通过DDD获得的模块稳定性收益就越大。

图9DDD重构前后系统故障率统计图

5

DDD落地面面观

DDD从2003年被提出来以后,得到了软件学术界的高度认可,但由于国内外开发环境和开发人员思想理念不同等多种影响,导致DDD在国内的实践并不是很理想。从2013年开始,微服务架构和中台化在国内逐渐盛行,而DDD可以作为其指导思想,帮助微服务架构进行清晰的领域和子域划分,DDD逐渐在企业应用实践上获得理想的成果,这正是DDD在国内突然变得流行的最主要原因之一。

对于开发团队来说,实践DDD最重要的一步就是通过事件风暴来进行领域分析建模,但这对于带头发起人的领域素养要求较高,需要团队内有一位布道师开路,担任领域专家的职责。

针对移动端来说,目前最合适的、符合DDD的架构模型就是TheCleanArchitecture,Google官方推出的安卓蓝图项目也针对MVP提供了一套符合TheCleanArchitecture的MVP-Clean项目,开发者可以由此为起点进行逐步探索和尝试。

由于国内外软件工程师职业环境和所承受的压力有所不同,在很多突发性的业务需求的冲击下,使得开发者只能对代码做疯狂堆叠,导致开发者不得已放弃DDD的设计,而期间发生需求变更就很容易导致风险。

当风险变为危险后,发生各种互相推诿的现象,其问题本质归结起来无非是两方面,一方面是组织结构和环境所影响,另一方面是边界划分不明确。

对于组织和团队方面,前期无需变动,也可以满足向DDD转型的条件,也为后期再建设微服务和中台化提供了便利。但需要注意的是,改变团队成员的固有开发思维也是十分重要的一个环节,团队内应该定期组织关于DDD的分享,有利于使大家对DDD的观念潜移默化。

6

嘉宾介绍

李云鹏,网易新闻架构技术组工程师,国内首个移动架构模型书籍《移动开发架构设计实战》作者。10余年互联网行业经验,擅长移动端架构选型、项目重构与插件开发相关工作。曾就职于世界500强核心技术实验室,作为第一发明人,申请了14项专利和著作权。

相关文章