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.hqwc.cn/news/211483.html

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

相关文章

电子学会C/C++编程等级考试2023年03月(一级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:字符长方形 给定一个字符,用它构造一个长为4个字符,宽为3个字符的长方形,可以参考样例输出。 时间限制:1000 内存限制:65536输入 输入只有一行, 包含一个字符。输出 该字符构成的长方形,长4个字符,宽3个字符。样例输入…

SPSS多元对应分析

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

EI论文故障识别程序:DBN深度置信/信念网络的故障识别Matlab程序,数据由Excel导入,直接运行!

​适用平台:Matlab2021b版及以上 本程序参考中文EI期刊《基于变分模态分解和改进灰狼算法优化深度置信网络的自动转换开关故障识别》中的深度置信网络(Deep Belief Network,DBN)部分进行故障识别,程序注释清晰&#x…

Action!录屏工具免费完整版,录屏软件,打开即可解锁最新完整可用版本,支持GPU加速HDR视频录制和播放

一、软件简介 本次带来的录屏工具已升级为【完整版本】,所有功能全部可用。该录屏工具支持GPU硬件加速,可以智能识别主流硬件设备,支持通过GPU进行HDR视频录制和播放进行。视频录制帧率最高支持360FPS,直播视频帧率最高支持60FPS…

C语言--给出一个点的坐标判断它在单位圆的内部外部还是上面

一.题目描述 给出一个点的坐标判断它在单位圆的内部外部还是上面 例如输入1,0,输出在圆上 二.思路分析 首先,单位圆是以坐标系原点为圆心、半径为1的圆。 给定一个点坐标 (x,y),我们可以使用勾股定理计算该点到坐标系原点的距…

注意:怎么用JMeter操作MySQL数据库?看完秒懂!

近期用JMeter做接口测试,遇到了一个需要用到数据数据库的场景:一个关于数据报告的页面,需要将数据库里面的数据求和或者取均值之后,展示出来。 如果要断言的话,需要连接数据库,通过写sql语句,将…

gRPC之gRPC负载均衡(客户端负载均衡)(etcd)

1、gRPC负载均衡(客户端负载均衡)(etcd) 本篇将基于etcd的服务发现前提下,介绍如何实现gRPC客户端负载均衡。 1.1 gRPC负载均衡 gRPC官方文档提供了关于gRPC负载均衡方案Load Balancing in gRPC https://github.com/grpc/grpc/blob/master/doc/load-balancing.m…

【数据结构/C++】栈和队列_链队列

#include <iostream> using namespace std; // 链队列 typedef int ElemType; typedef struct LinkNode {ElemType data;struct LinkNode *next; } LinkNode; typedef struct {LinkNode *front, *rear; } LinkQueue; // 初始化 void InitQueue(LinkQueue &Q) {Q.fron…

听GPT 讲Rust源代码--src/tools(2)

题图来自AI生成 File: rust/src/tools/rust-analyzer/crates/hir-def/src/src.rs rust-analyzer 是一个 Rust 语言的语法分析器和语义分析器&#xff0c;用于提供代码补全、导航、重构等开发工具。而 rust-analyzer 的代码实现存储在 rust/src/tools/rust-analyzer 这个文件夹中…

经典滑动窗口试题(一)

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、将x减到0的最小操作数1、题目讲解2、讲解算法原理3、代码实现 二、无重复的最长子串1、题…

力扣:178. 分数排名(Python3)

题目&#xff1a; 表: Scores ---------------------- | Column Name | Type | ---------------------- | id | int | | score | decimal | ---------------------- 在 SQL 中&#xff0c;id 是该表的主键。 该表的每一行都包含了一场比赛的分数。Score …

gmapping仿真

文章目录 获取源码安装依赖项编译简单场景运行gmapping开启键盘控制通过launch文件来启动gmappingGmapping建图的参数设置地图的保存和加载参考 获取源码 cd ~/catkin_ws/src/ git clone https://gitcode.com/weixin_42990464/wpr_simulation.git git clone https://gitcode.c…