极客大学架构师训练营 微服务网关 领域驱动设计 DDD OAuth 2.0 中台架构 第 20 课 听课总结

用户头像
John(易筋)
关注
发布于: 2020 年 08 月 13 日

说明

讲师:李智慧



微服务网关

基于网关的微服务架构

网关作用

微服务网关

网关管道技术

网关本身没有什么业务,主要职责是各种校验与拦截,这些职责可以通过管道技术连接起来。



实现管道技术的责任链设计模式

Flower 异步网关与异步微服务框架

开源地址:

https://github.com/zhihuili/flower



利用Servlet3 实现异步网关

开放平台网关

  • API 接口:是开放平台暴露给合作者使用的一组API, 其形式可以是 Restful、WebService、RPC 等各种形式。

  • 转义转换:将各种 API 输入转换成内部服务可以识别的形式,并将内部服务的返回 封装成 API 的格式。

  • 安全:除了一般应用需要的身份识别、权限控制等安全手段,开放平台还需要分级的访问带宽限制,保证平台资源被第三方应用公平合理使用,也保护网站内部服务不会被外部应用拖垮。

  • 审计:记录第三方应用的访问情况,并进行监控、计费等。

  • 路由:将开放平台的各种访问路由映射到具体的内部服务。

  • 流程:将一组离散的服务组织成一个上下文相关的新服务,隐藏服务细节,提供统一接口供开发者调用。



开放授权协议 OAuth 2.0



资源所有者:用户;



授权码授权

OAuth 2.0 一共有四种授权模式,分别是授权码、隐式授权、资源所有者密码凭据和客户端凭据。



目前互联网上使用最多也是最安全的一种方式是授权码方式。

  • Resource Owner: 用户;

  • Client:用户用的 App;

  • User-Agent: 比如微信、淘宝;

  • Authorization Server:授权中心;



领域驱动设计 Domain-Driven Design

为什么需要 DDD

很多项目的实际情况:

  • 用户或者产品经理的需求零零散散,不断变更。

  • 工程师在各处代码中寻找可以实现这些需求变更的代码,修修补补。

  • 软件只有需求分析,并没有真正的设计,系统没有一个统一的领域模型维持其内在的逻辑一致性。

  • 功能特性不是按照领域模型内在的逻辑设计,而是按照各色人等自己的主观想象设计。



项目时间一长,各种困难重重,需求不断延期,线上 bug 不断,管理者考虑是不是要推到重来,而程序员则考虑是不是要跑路。



例子:

  • 早期的遥控器,有一堆密密麻麻的按钮,实际上很多都用不着的,现在就设计成只剩下几个就够用了。

  • iPhone之前的手机,密密麻麻的按钮,iPhone出来以后,前面就只有一个Home键,现在有FaceId, Home键也没了。



事务脚本(一直在用,不推荐)

问题在于:Service 是业务逻辑的核心。每次增加一种contractID合同类型, 就增加一个if else, 随着业务的变更,Service 类就变得特变臃肿,变得代码发臭。



领域模型(推荐)

每种contractID合同类型,都要增加一种contact、product、recognitionStrategy。



贫血模型 vs 充血模型

  • 由于事务脚本模式中,Service、Dao这些对象只有方法,没有数值成员变量,而方法调用时传递的数值对象,比如 Contract,没有方法(或者只有一些 getter、setter 方法),因此事务脚本又被称作贫血模型。

  • 领域模型的对象则包含了对象的数据和计算逻辑,比如合同对象,既包含合同数据,也包含合同相关的计算。因此从面相对象的角度看,领域模型才是真正的面向对象。收入确认和合同强相关的,是合同对象的一个职责,那么合同对象应该提供一个 calculateRecognition 方法计算收入。

  • 领域模型是合并了行为和数据的领域的对象模型。通过领域模型对象的交互完成业务逻辑的实现,也就是说,设计好了领域模型对象,也就设计好了业务逻辑实现。和事务脚本被称作贫血模型相对应的,领域模型也被称作为充血模型。



DDD战略设计

领域是一个组织所做的事情以及其包含的一切。通俗地说,就是组织的业务范围和做事方式,也是软件开发的目标范围。



领域驱动设计就是从领域出发,分析领域内模型及其关系,进而设计软件系统的方法。

子域

领域是一个组织所做的事情以及其包含的一切。这个范围就太大了,不知道该如何下手。所以通常的做法是把整个领域拆分成多个子域,比如用户、商品、订单、库存、物流、发票等。



如何划分子域?

卖家提现功能是属于用户子域?订单子域?财务子域?还是直接设计一个提现子域?



卖家提现有可能是财务的子域。



子域就是微服务,微服务的边界就清楚了。



限界上下文

在一个子域中,会创建一个概念上的领域边界,在这个边界中,任何领域对象都只表示特定于该边界内部的确切含义。这样边界便成为限界上下文。限界上下文和子域具有一对一的关系,用来控制子域的边界,保证子域内的概念统一性。



通常限界上下文对应一个组件或者一个模块,或者一个微服务,一个子系统。

上下文映射图

不同的限界上下文,也就是不同的子系统或者模块之间会有各种的交互合作。DDD 使用上下文映射图来设计这种关联和交互。



DDD战术设计

实体

领域模型对象也被称为实体,每个实体是唯一的,具有一个唯一标识,一个订单对象是一个实体,一个产品对象也是一个实体,订单ID或者产品ID是它们的唯一标识。实体可能会发生变化,比如订单的状态会变化,但是它们的唯一标识不会变化。



实体设计使 DDD 的核心所在,首先通过业务分析,识别出实体对象,然后通过相关的业务逻辑设计实体的属性和方法。这里最重要的是,是要把握住实体的特征是什么,实体应该承担什么职责,不应该承担什么职责,分析的时候要放在业务场景和界限上下文中,而不是想当然地认为这样的实体就应该承担这样的角色。

值对象

并不是领域内的对象都应该被设计为实体,DDD 推荐尽可能将对象设计为值对象。比如像住址这样的对象就是典型的值对象,也许建在住址上的房子可以被当做一个实体,但是住址仅仅是对房子的一个描述,像这样仅仅用来做度量或描述的对象应该被设计为值对象。



值对象的一个特点是不变性,一个值对象创建以后就不能再改变了。如果地址改变了,那就是一个新地址,而一个订单实体则可能会经历创建、待支付、已支付、待发货、已发货、待签收、待评价等各种变化。

聚合

聚合是一个关联对象的集合,我们将其作为一个单元来处理数据变更。每个集合都有一个根和一个边界。边界定义了聚合内部的内容。根是聚合中包含的单个特定实体。



聚合根:将多个实体和值对象聚合在一起的实体。

DDD 分层架构

领域实体的组合调用和事务控制在应用层。

用户支付 应用层会多个领域层:订单状态,支付等。



DDD 六边形架构

领域模型通过应用程序封装成一个相对比较独立的模块,而不同的外部系统则通过不同的适配器和领域模型交互,比如可以通过 HTTP 接口访问领域模型,也可以通过 Web Service 或者消息队列访问领域模型,只需要为这些不同的访问接口提供不同的适配器就可以了。



DDD 战略设计与战术设计

  • 领域、子域、界限上下文、上下文映射图,这些是 DDD 的战略设计。

  • 实体、值对象、聚合、CQRS、实践溯源,这些是 DDD 战术设计。

  • 通过战略设计,划分模块和服务的边界及依赖关系,对微服务架构的设计至关重要。

李智慧老师经历的一个 DDD 重构实践过程

  • 当前系统设计与问题汇总讨论:架构与代码混乱,需求迭代困难,部署麻烦,bug率逐渐升高。

  • 针对问题分析具体原因:子系统 A 太庞大,模块 B 和 C 职责不清,业务理解不一致;

  • 重新梳理业务规则和边界,明确业务术语:DDD 战略设计,领域建模。

  • 技术框架选型与落地方案验证:DDD 战术设计,样例代码。

  • 任务分解与持续重构:在不影响业务开发的前提下,按照战略与战术设计,将重构开发和业务迭代有机融合。



DDD 对个人成长的价值

如果一个工作多年的程序员,还是仅仅写一些跟他工作第一年差不多的 CRUD 代码。那么他迟早会遇到自己的职业危机。公司必然愿意用更年轻、更努力,当然也更低薪水的程序员来代替他。至于学习新技术的能力,其实多年工作经验也并没有太多帮助,有时候也许还是劣势。



资深程序员真正有优势的是TA在一个业务领域的多年积淀,对业务领域有更深刻的理解和认知。那么如何将这些业务沉淀和理解反映到工作中,体现在代码中呢? 实践 DDD 是一个不错的方式。



如果一个人有多年的领域经验,那么必然对领域模型设计有更深刻的认识,把握好领域模型在不断的需求变更中的演讲,使系统维持更好的活力,并因此体现自己的真正价值。

DDD战略建模,在重构业务系统时的实践 (逻辑思维)

主讲人:韩宇斌 (得到后端业务线 Leader)

目录:

  1. 用领域驱动来把握真正的业务需求;

  2. 领域驱动设计指导架构设计与建模;

  3. 用限界上下文来保护领域。



领域驱动设计帮助我解决了工作的难题

  • 无路可退:入职第一个任务;

  • 左右为难:实现技术重构的目标,满足不了业务需求!不去实现,又不知道该做什么?



得到 App 电商业务涉及的组织和系统





得到 App 目前如何确认收入

谁还没有个过去

没有订单时



财务:必须记录订单及交易状态

不靠谱的任务:增加一个订单中间层

实现了“订单化”后的调用关系



实现了“订单化”后,依赖于耦合加剧



原系统架构的问题很快暴露



财务:尽快把所有交付内容都接入“订单化”



接到的重构任务:订单代理(订单化)系统

  • 实现 一个代理服务;

  • 对接 交易平台组的订单系统和基础平台组的支付系统;

  • 推动 若干个业务系统改造,改成调用新的代理服务。

订单代理系统如何隔离变化



“同时满足”了业务需求和技术目标

业务需求:所有的商品都实现“订单化”。

技术:不光都实现“订单化”,我们还实现个“订单化的代理系统”,应对外部系统的变化。



方案确定了!但这是业务的目标吗?

实现“订单化”并不是业务的真正需求

面临的挑战

  • 无路可退:入职第一个任务;

  • 左右为难:实现“订单代理系统”,满足不了业务需求!不去实现“订单代理系统”,那该做什么?



没有把握真正需求的原因



领域驱动设计的工作方式





  • 问题域:电商的发货与算账;

  • 业务期望:精确交付。



理解“订单化”在需求中作用和意义。

提炼和理解一些“统一语言”

领域驱动设计,找到真正的业务需求



二、领域驱动设计指导架构设计与建模

电商的基本业务模型

“个体户” 或 “小商贩”



订单代理系统架构的弊端

  • 每个业务依然是个“”,相同功能的代码依然会重复;

  • 改成调用订单代理系统,交付数据的准确性依然达不到财务要求。



需求:财务核算级别的精确交付

“小商贩”模式能解决技术问题,但不能满足业务需求。



交易领域中缺少一个专注交付的子领域。



重新理解和确定了领域问题





得到后端的核心子领域问题:是“履约”,是交付订单交付系统。



指导建模:把握领域并识别限界上下文。

目标:让业务方从“小商贩”入驻“超市”。

订单交付系统接管业务的交易行为

订单交付系统满足了业务和技术的目标

  • 业务方不再是“小商贩”,入驻“超市”称为“卖家”;

  • 交付的数据达到财务精准核算的要求。



发布于: 2020 年 08 月 13 日 阅读数: 101
用户头像

John(易筋)

关注

问渠那得清如许?为有源头活水来 2018.07.17 加入

工作10+年,架构师,曾经阿里巴巴资深无线开发,汇丰银行架构师/专家。开发过日活过亿的淘宝Taobao App,擅长架构、算法、数据结构、设计模式、iOS、Java Spring Boot。易筋为阿里巴巴花名。

评论 (1 条评论)

发布
用户头像
订单支付系统和交易中心系统不能够合并在一起吗?
2020 年 09 月 08 日 14:10
回复
没有更多了
极客大学架构师训练营 微服务网关 领域驱动设计 DDD OAuth 2.0 中台架构 第20课 听课总结