DDD落地:从网易新闻APP重构,看DDD的巨大价值

尼恩说在前面

在40岁老架构师 尼恩的读者交流群(50+)中,最近有小伙伴拿到了一线互联网企业如阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格,遇到很多很重要的面试题:

谈谈你的DDD落地经验?

谈谈你对DDD的理解?

如何保证RPC代码不会腐烂,升级能力强?

微服务如何拆分?

微服务爆炸,如何解决?

你们的项目,DDD是怎么落地实操的?

所以,这里尼恩给大家做一下系统化、体系化的梳理,使得大家可以充分展示一下大家雄厚的 “技术肌肉”,让面试官爱到 “不能自已、口水直流”

也一并把这个题目以及参考答案,收入咱们的 《尼恩Java面试宝典PDF》V130版本,供后面的小伙伴参考,提升大家的 3高 架构、设计、开发水平。

《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》的PDF,请到文末公号【技术自由圈】获取

除了本文,尼恩输出了一个 《从0到1,带大家精通DDD》系列,帮助大家彻底掌握DDD,地址是:

《阿里DDD大佬:从0到1,带大家精通DDD》

《阿里大佬:DDD 落地两大步骤,以及Repository核心模式》

《阿里大佬:DDD 领域层,该如何设计?》

《极兔面试:微服务爆炸,如何解决?Uber 是怎么解决2200个微服务爆炸的?》

《阿里大佬:DDD中Interface层、Application层的设计规范》

《字节面试:请说一下DDD的流程,用电商系统为场景》

《DDD如何落地:去哪儿的DDD架构实操之路》

《DDD落地:从腾讯视频DDD重构之路,看DDD极大价值》

《DDD落地:从美团抽奖平台,看DDD在大厂如何落地?》

《美团面试:微服务如何拆分?原则是什么?》

《DDD神药:去哪儿结合DDD,实现架构大调优》

大家可以先看前面的文章,再来看本篇,效果更佳。

另外,尼恩会结合一个工业级的DDD实操项目,在第34章视频《DDD的学习圣经》中,给大家彻底介绍一下DDD的实操、COLA 框架、DDD的面试题。

DDD现在非常火爆,是有其巨大生产价值,经济价值的, 绝不仅仅是一套概念那么简单。

DDD的绝大价值,具体请参见以下视频:

从腾讯视频DDD重构案例,看看DDD极大价值

文章目录

    • 尼恩说在前面
    • 网易新闻App架构重构实践
    • 移动端架构与网站架构的区别
    • 网易新闻客户端的架构演进历程
      • 第一阶段:Static Method
      • 第二阶段:MVP
      • 第三阶段:MVPs
      • 第四阶段:符合 DDD 的 VIPER
    • 基于 DDD 的短视频架构优化
    • DDD 的选型与实践
      • 选型背景
      • 落地难题
      • 重构效果
    • DDD 落地面面观
    • 说在最后
    • 尼恩技术圣经系列PDF

网易新闻App架构重构实践

作者:小智

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

当前,大多数移动开发团队将 MVP 作为业务层的核心架构模式,并在此基础上实现了客户端的组件化、插件化、容器化等。然而,作为业务层核心的 MVP 架构模式仍存在诸多问题。在领域驱动设计(DDD)思想的指导下,网易新闻 App 对其架构进行了全面重构,取得了良好的重构质量和项目收益。那么,移动端架构与网站架构有何不同?网易新闻客户端的架构演变过程是怎样的?为何选择 DDD 思想来指导重构?在 DDD 实践中应注意哪些方面?

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

传统的网站架构,通过超文本传输协议,使得浏览器能够便捷地将我们想要访问的页面展示出来。每个网站由多个页面组成,这些页面都属于 Web Server 的一部分,如图 1 所示。

图 1 Website 与 Server 抽象模型

图 1 Website 与 Server 抽象模型

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

相较之下,移动端 App 需先让用户进行安装,然后才能访问页面。移动端的高并发网络请求等场景通常交由 Server 端处理,而移动端更关注处理用户交互和界面变化,如图 2 所示。

图 2 Application 与 Server 抽象模型

图 2 Application 与 Server 抽象模型

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

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

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

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

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

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

第一阶段:Static Method

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

在 Static Method 的模式中,技术团队将 View 抽象为一块蛋糕,蛋糕上需添加奶油、柠檬、樱桃(Model)等食材。负责输送材料的加工厂(Static Method)派遣工人(而非厨师)将材料直接运送并摆放在蛋糕上,如图 3 所示。这样蛋糕便具备了所有应有的食材成分。然而,食材摆放随意,使得蛋糕显得混乱,如果再继续这样堆砌食材,它就不再像是一块蛋糕了。

图 3 Static Method 蛋糕加工模型

图 3 Static Method 蛋糕加工模型

因此,随着时间推移和业务迭代加速,这种失去封装、多态和继承的面向对象特性的工具类设计难以应对业务变化。因此,转向流行的 MVP 模式成为必然趋势。

第二阶段:MVP

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

由于 Presenter 与 View 通过接口协议绑定,一个 Presenter 中的业务逻辑通常只能为一个 View 服务。因此,代码复用性较差,容易产生大量冗余代码。

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

图 4 MVP 蛋糕加工模型

图 4 MVP 蛋糕加工模型

第三阶段:MVPs

为解决 MVP 代码复用问题,许多设计方法将 View 与 Presenter 改为多对一模式,即一个 Presenter 可为多个 View 服务,而一个 View 也可被多个 Presenter 控制。这意味着更多 Presenter 参与其中,会产生更多适应不同 View 的接口。

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

图 5 MVPs 蛋糕加工模型

图 5 MVPs 蛋糕加工模型

第四阶段:符合 DDD 的 VIPER

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

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

图 6 VIPER 蛋糕加工模型

图 6 VIPER 蛋糕加工模型

通过这种分工合作的模式,VIPER 架构不仅提高了工作效率,还降低了出错率。每个环节都有专门的负责人,使得整个流程更加顺畅。此外,这种架构还有助于后续的迭代和升级,因为各个模块之间的耦合度较低,便于独立开发和更新。

基于 DDD 的短视频架构优化

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

图 7 视频详情页抽象结构

图 7 视频详情页抽象结构

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

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

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

DDD 的选型与实践

选型背景

新闻客户端的多数业务模块在设计初期的时候,多数业务模块所承载的业务量并不大。但随着需求的逐渐增加,为了快速迭代,开发人员往往将代码堆积在一起,导致业务模块间的边界变得模糊,耦合度也越来越高。

为了解决这个问题,DDD 的限界上下文为技术团队提供了明确领域模型边界和实现解耦的方法。VIPER 是一种符合 DDD 理念的架构模型,尽管最初在 iOS 端流行,但其核心思想与 The Clean Architecture 相似,因此同样适用于 Android 端,成为一种通用解决方案。

落地难题

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

在工作流程方面,传统需求评审涉及产品经理、项目经理、软件工程师、UI 交互设计师等,但关注点往往集中在整体业务,事件划分不够明确。要推动多个团队改变评审方式以确定限界上下文的事件风暴,具有一定的困难。因此,开发团队在编码阶段开始前,进行内部技术评审,邀请准领域专家与开发人员共同分析讨论界限上下文。

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

重构效果

在基于 DDD 的架构重构初期,新闻客户端选择了视频详情、视频列表和图集三个业务模块进行 VIPER 重构,以探索 DDD 的实际应用。

  • 在重构质量上,先确定领域模型,代码整体解耦符合预期,三个模块重构后上线均未出现严重线上问题。
  • 在项目收益上,一方面,DDD 帮助团队提高迭代开发效率;另一方面,代码可维护性大幅提高,模块错误率降低约 50%。

新闻客户端以半年为周期,统计模块重构前半年与重构后半年的系统故障率(主要指开发期间产生的问题),如图 9 所示。数据表明,业务变化频繁的模块(如视频)通过 DDD 获得的模块稳定性收益更为显著。

通过采用 DDD 理念进行架构重构,新闻客户端在快速迭代和需求变化的过程中,实现了更高的灵活性、可扩展性和代码质量。通过明确领域模型边界、优化工作流程和转变编码思维,团队成功应对了落地难题,为客户端在竞争激烈的市场中奠定了基础。

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

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

DDD 落地面面观

自从2003年领域驱动设计(DDD)概念提出以来,它在软件学术界赢得了广泛认可。然而,受到国内外开发环境、开发者观念等多种因素影响,DDD在国内的实际应用并未完全达到预期效果。从2013年开始,微服务架构和中台化在国内逐渐兴起,DDD作为指导原则,有助于明确划分领域和子领域,因此在企业应用实践中取得了良好成果,成为国内突然流行的主要原因之一。

对开发团队而言,实施DDD的关键环节是通过事件风暴进行领域分析建模,这对领军人物的领域素养要求较高,需要承担领域专家的职责。

针对移动端领域,The Clean Architecture 是目前最适合、符合 DDD 理念的架构模型。Google 官方推出的安卓蓝图项目为 MVP 提供了一套符合 The Clean Architecture 的 MVP-Clean 项目,开发者可以借此展开逐步探索和尝试。

由于国内外软件工程师的职业环境和所承受的压力有所不同,在面对突发业务需求冲击时,开发者往往只能疯狂堆叠代码,导致被迫放弃 DDD 设计。需求变更时,容易出现风险。

在风险加剧的情况下,各种推诿责任的现象频发,问题本质归咎于组织结构、环境因素以及边界划分不明确。

针对组织和团队层面,初期无需大规模调整,即可满足 DDD 转型需求,并为后续微服务和中台化建设提供便利。但需注意,改变团队成员固有的开发思维至关重要,团队内应定期举办 DDD 相关分享,使大家对 DDD 观念逐渐认同。

总之,在国内软件开发环境中,实践 DDD 具有重要意义。遵循 DDD 原则,开发者能够更好地应对业务需求变化,提高代码质量和系统稳定性。在组织及团队层面,推动 DDD 转型有助于微服务架构和中台化的实施,提升整体开发效率。为实现这些目标,团队需共同努力,培养领域素养,明确边界划分,并改变固有思维,为 DDD 实践奠定坚实基础。

说在最后

DDD架构如何落地,是是非常常见的面试题。

以上的内容,如果大家能对答如流,如数家珍,基本上 面试官会被你 震惊到、吸引到。

在面试之前,建议大家系统化的刷一波 5000页《尼恩Java面试宝典PDF》,并且在刷题过程中,如果有啥问题,大家可以来 找 40岁老架构师尼恩交流。

最终,让面试官爱到 “不能自已、口水直流”。offer, 也就来了。

当然,关于DDD,尼恩即将给大家发布一波视频 《第34章:DDD的学习圣经》, 帮助大家彻底穿透DDD。

尼恩技术圣经系列PDF

  • 《NIO圣经:一次穿透NIO、Selector、Epoll底层原理》
  • 《Docker圣经:大白话说Docker底层原理,6W字实现Docker自由》
  • 《K8S学习圣经:大白话说K8S底层原理,14W字实现K8S自由》
  • 《SpringCloud Alibaba 学习圣经,10万字实现SpringCloud 自由》
  • 《大数据HBase学习圣经:一本书实现HBase学习自由》
  • 《大数据Flink学习圣经:一本书实现大数据Flink自由》
  • 《响应式圣经:10W字,实现Spring响应式编程自由》
  • 《Go学习圣经:Go语言实现高并发CRUD业务开发》

……完整版尼恩技术圣经PDF集群,请找尼恩领取

《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》PDF,请到下面公号【技术自由圈】取↓↓↓

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/164128.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GEE:梯度提升树(Gradient Boosting Tree)分类教程(样本制作、特征添加、训练、精度、参数优化、贡献度、统计面积)

作者:CSDN @ _养乐多_ 本文将介绍在Google Earth Engine (GEE)平台上进行梯度提升树(Gradient Boosting Tree)分类的方法和代码,其中包括制作样本点教程(本地、在线和本地在线混合制作样本点,合并样本点等),加入特征变量(各种指数、纹理特征、时间序列特征、物候特征…

OpenStack云计算平台-启动一个实例

目录 一、创建虚拟网络 ​二、创建m1.nano规格的主机 三、生成一个键值对 四、增加安全组规则 ​五、启动一个实例 1、确定实例选项 2、创建实例 3、使用虚拟控制台访问实例 4、验证能否远程访问实例 一、创建虚拟网络 下面的说明和框图使用示例IP 地址范围。你必须依…

Altium Designer学习笔记12

把几个层理解下: layer名称功能说明信息Toplayer信号层铜箔层,电气连接的层Bottomlayer信号层铜箔层,电气连接的层Internal Planes内层连接地和电源上,一般情况下不布线,是由整片铜膜组成的Mechanical 1机械层电路板机…

String 、StringBuffer 和 StringBuilder 的区别?

String 使用 String 声明一个字符串的时候,该字符串会存放在堆中的字符串常量池中。因为在java中所有的String 都是以常量表示,且由 final 修饰,因此在线程池中它的线程是安全的 且 不可变的 。每个 String 在被创建后就不再发生任何变化。 …

mysql按年、季度、月,统计

以下是按年、按季度和按月统计SQL查询语句: 按年统计: SELECTds.checker,YEAR(ds.create_time) AS settleYear,SUM(ds.quantity) AS quantity,SUM(ds.approval_price) AS approvalPrice FROMdata_settle ds WHEREds.delete_flag 0AND ds.approval_sta…

漏洞盒子公益SRC

漏洞盒子公益SRC,小小地记录一下第一个月的成果

数据中台建设方法论

1、数仓的概念和了解--业务的痛点 产生的痛点:数据资产比较模糊、数据的质量比较低、重复建设、代码的耦合性比较强。 2、数据仓库中的常见的模型: 1、心型模型:中间是一张事实表,周围都是维度表。 对于心型模型的主要的特点&a…

面向未来的自动化:拥抱机器人即服务(RaaS)

01. RaaS是什么? 对于希望实现业务流程自动化的公司来说,机器人通常是一笔巨大的资本支出。由于机器人非常昂贵,公司可能需要等待数年才能看到投资回报。正是由于这一现实,许多较小的组织无法投资机器人。 但一些机器人公司正在采…

算法通关村第十二关-青铜挑战字符串

大家好我是苏麟 , 今天带来字符串专题 . 转换成小写字母 描述 : 给你一个字符串 s ,将该字符串中的大写字母转换成相同的小写字母,返回新的字符串。 题目 : LeetCode 709.转换成小写字母 : 709. 转换成小写字母 分析 : 这个题可以先遍历整个字符串…

Mybatis和MybatisPlus:数据库操作工具的对比

目录 什么是mybatis 什么是mybatisplus MyBatis-Plus:为简化数据库操作而生的强大工具 一、MyBatis-Plus的背景和概述 二、MyBatis-Plus的主要特点 三、如何使用MyBatis-Plus mybatis-Plus的优势 什么是Hibernate Hibernate:Java开发者的数据持久…

光谱图像超分 Benchmark

光谱图像超分 Benchmark 文章目录 光谱图像超分 Benchmark0. pioneer工作及综述基于深度学习的高光谱多光谱融合(updating)1. 空间光谱图像超分 (to be updated)2. 高分辨率多光谱图像超分(to be updated)3…

重生之我是一名程序员 39 ——C语言题目之青蛙跳台阶

哈喽啊大家晚上好!今天给大家带来的是C语言经典题目之青蛙跳台阶。青蛙跳台阶是一个数学问题,也是一个经典的递归问题。假设一只青蛙要跳上一个n级台阶,它可以每次跳1级台阶或2级台阶。问:青蛙跳上这个n级台阶总共有多少种不同的跳…

AMESim|学习记录

此文记录AMESim学习过程中的各种情况。 目录 01 王佳. AUV 浮力调节系统设计及控制策略研究[D]. 天津大学, 2017.01 王佳. AUV 浮力调节系统设计及控制策略研究[D]. 天津大学, 2017. 01 王佳. AUV 浮力调节系统设计及控制策略研究[D]. 天津大学, 2017. 开始步入正文 01 王佳.…

【Leetcode合集】14. 最长公共前缀

14. 最长公共前缀 14. 最长公共前缀 代码仓库地址: https://github.com/slience-me/Leetcode 个人博客 :https://slienceme.xyz 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀,返回空字符串 ""。 示例 …

【UE】用样条线实现测距功能(下)

目录 效果 步骤 一、实现多次测距功能 二、通过控件蓝图来进行测距 在上一篇(【UE】用样条线实现测距功能(上))文章基础上继续实现多次测距和清除功能。 效果 步骤 一、实现多次测距功能 打开蓝图“BP_Spline”&#xff0c…

cherry pick的使用

https://blog.csdn.net/weixin_55229531/article/details/128726872

SPS简单对应分析

前言: 本专栏参考教材为《SPSS22.0从入门到精通》,由于软件版本原因,部分内容有所改变,为适应软件版本的变化,特此创作此专栏便于大家学习。本专栏使用软件为:SPSS25.0 本专栏所有的数据文件请点击此链接下…

Git如何修改提交(commit)用户名称(user.name)和邮箱(user.email)

Git用户名 Git查看用户名 git config user.name修改Git提交用户名 修改全局Git用户名 git config --global user.name "xx" 修改当前服务/项目Git用户名 git config user.name "xx"如果出现以下错误,解决方案如下: 错误案例&am…

量子计算概述

目录 1.量子计算介绍 2.量子计算应用 3.量子计算研究机构 1.量子计算介绍 量子计算是一种遵循量子力学规律调控量子信息单元进行计算的新型计算模式。经典计算使用2进制进行运算,但2进制只有0和1两种状态,而量子计算除了包含0和1两种状…