写点什么

第十周 架构方法学习总结

用户头像
兵长
关注
发布于: 2020 年 11 月 30 日

微服务网关



基于网关的微服务架构





网关作用





微服务网关





网关管道技术



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





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





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 是一个不错的方式。



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



用户头像

兵长

关注

还未添加个人签名 2018.03.16 加入

还未添加个人简介

评论

发布
暂无评论
第十周 架构方法学习总结