EF几乎是按照领域的概念诞生,它可以和Clean结合(ECF是我新想出的名字)。ECF 是为了统一业务架构开发方式,也可以说成在 微服务架构 中服务的通用开发方式。当有了统一开发方式后,协作将更上一层楼。

最近没工作,就写了这章。是为了团队协作的,如何能被更多知道同样知识的人快速了解业务系统?

通用名词:DDD中定义了通用名词,意为某件事情的专业术语,软件中也可拥有。Clean和DDD的战术设计近乎一致。

先看看Clean中的概念,简略意思是低耦合高内聚。每一个方法都需要遵循SOLID,命名为特殊的含义。从方法名中能看到它的功能,即使它的内部很复杂。都能通过几句简短的代码,飞快的看到过程。过程中隐藏着复杂细节,不需要及时的都去了解,就能理解这个方法都做了什么事情。

低耦合是代表,不同的模块之间更改没有冲突。

高内聚是代表,上层不同的模块调用下层相同的模块,这个下层模块更改,多个上层模块也被更改。

EF中DbContext,则符合领域的概念代表一个上下文,它被设计的很灵活,DbContext是一个仓储管理者(意为DDD中的仓储模式,多个仓储的管理者)。用DbContext可以直接调用出多个不同仓储,用linq简单的方式操作仓储的API。从操作仓储API中可以操作多个实体(意为DDD中的聚合根模式)。

如图所示ECF整体上包含的(剪头方向代表正被它使用的):

实体

Entity 实体是与数据库接触的模型体,它可以是存储在内存数据库中的缓存,也可以是关系型数据库中的表。

每一个实体有自己的行为方法。不过有些特殊的实体,却能管理其他实体的行为,它是实体管理者也叫聚合根。实体管理者它被任命管理它所认知范围内所有的实体。实体管理者不能处理过程业务,过程业务只能是管理者实现。

不可变的值

实体中很重要的值对象,在实体中通常会有要改一起改的属性,它们不能只改一个,是一个整体。这种一般会把它做成结构体,在实体中做成结构属性,以防止对它进行破坏。

管理者

Manager 是遵循SOLID的好管理者。它指的是只做有意义的事情,在代码层面是独一无二的,它可以方便上层调用最少量代码。一直在上层编写可能会有很多重复功能,更改其一偶尔忽略其二的事情常常发生,它的出现将改变这一切。

它是范围生命周期的服务,它会使用工厂,使用缓存,使用外部服务,DbContext,日志等项。它将暴露只属于它的仓储,而不是DbContext(DbContext 可以切换不同的关系型数据库,使得仓储不用改变),还将暴露对上层有意义的方法和属性。它的方法不能隐藏业务过程,只能隐藏代码和业务细节。它的方法命名必须简明要义,必须让外部来看瞬间理解其意思,而不是添加更多的注释。

模型

模型和实体一样重要,它可以是分页带很多查询参数的请求模型、外部服务的模型、工厂的模型等等。它不是数据库交互的模型体,它也可以包含行为。

外部服务

外部服务应该是瞬态生命周期可以有服务注册选择项,最常包含的有链路追踪,单例HttpClient。只能被管理者调用,这是因为在上层不需要处理细节。

实体规则

了解实体的行为方法后,还需要了解实体上有些行为是不允许的会报错。通常是有属性不能为空,字符串长度太长等项。这种应该在领域中呈现,作者自己命名为 实体规则。实体规则能被实体的行为调用,还可以被数据传输对象的规则调用。实体规则是被注入为单例的服务,实体规则可以有服务注册选择项。实体规则的方法要简明要义,请求参数必须有是否抛出异常的选项,返回值必须是bool类型。

数据传输对象

是Rpc的过程传输对象,一般有请求参数和返回参数。数据传输对象不能直接是实体,因为不易于前端的使用,可能会有前端不认识的属性出现。请求参数,每个API都必须不一样,返回参数,则相反尽量使用同样的返回参数,请求和返回都应该用最少的属性满足,这样设计有易于前端的使用。一般命名规则为,请求参数动词在前名词在中间最后加上Dto。返回参数则是名词加上Dto,嵌套返回参数亦是如此。

映射

几乎映射规则是实体和数据传输对象的映射,一般只服务于Rpc。在管理者中应该尽量减少映射的出现,因为管理者的请求应该只接受实体和工厂模型的传输。

数据传输对象规则

是最终要返回给用户的错误信息,是单例声明周期的服务可以有服务注册选择项。不可包含DbContext,它应该是无状态的规则,可以调用专有的实体规则来满足高内聚。

一般有状态的规则应该在业务中体现,若是出现问题应该抛出异常返回400 BadRequest,并且不提示任何信息,这很有可能是一个破坏请求,生产环境正常业务下是不会出现400的。

有状态的规则在业务中体现,必须有专门的API去给前端判断,比如昵称是否重复API,而不是主API出现判断。

Rpc

远程过程调用API,应该尽可能的用过滤器保护内部业务和数据,这包含请求缓存,限流,授权等项。

它的业务过程应该简单清晰,包含使用日志,使用数据传输对象规则、映射规则、DbContext和管理者、还有实体等项。

集成事件

只有上层才会有集成事件和外部系统发送事件交互,从而解耦项目之间的依赖。不可否认的是集成事件和Rpc如出一辙,都可以使用相同的战术,需要保护内部业务和数据。(领域事件是项目内部发生,依赖注入的方式做成的)

单元测试

由于项目是高内聚,低耦合,这使得其中的每个方法,都可以进行单元测试。

单元测试最终的目的是:将这个方法过去错误进行保留,当需要修改这个方法时,可以运行过去的错误,用来兼容新的的业务规范。

其他配置项

应该与业务需要适配,尽量去做出灵活的配置。不应该出现不认识或者无用的配置属性。知己知彼百战百胜,配置项不是一定要记住,也不是一定要把注释写在配置文件中。正确的做法是,给每一项属性加上完整的注释。

规模大成分布式

当知道如何完成一个独立项目后,后面应该知道如何分布式项目,完成上下文解耦。

举个例子,有个用户项目,包含登录,注册。还包含,管理员的用户创建不需要登录。一方流量大,一方根本没流量,在同一个项目中。此时是需要完成上下文解耦,一个上下文变成两个项目。身份项目服务于普通用户,账号管理服务于管理员。

我们知道既然慢慢的分布成了多个项目变成了分布式,就要设计很多东西:日志收集、指标监控、链路追踪、分布式缓存、缓存淘汰策略、领导选举、哨兵模式、索引文档、服务发现、健康检查、负载均衡、网关、消息队列、分布式设计模式、Sagas等项。这里每一项在关键时刻就需要上,不上就很难做成,切忌不可操之过急,根据团队成员分配,微服务是把双刃剑。

当项目和工具太多又需要承受每个服务的管理,就需要容器化服务。容器越来越多,就需要上管理容器的工具K8s。当数据库承受不住还要上集群数据库,都知道集群数据库不是一般的贵,要是上不起只能跑到消息队列。

这只是表象,实际中许多还需要处理存储图片,文件,静态资源,还需要上了对象存储。资源太卡,还需要CDN。域名,DNS等等等很多。每一个知识点的用处都有讲究,知识层出不穷很多很多,学不完根本学不完。

最后

借鉴了微软微服务文档(https://learn.microsoft.com/zh-cn/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/)、微软EF文档(https://learn.microsoft.com/zh-cn/ef/core/)、《Clean架构》、《领域驱动设计》、《微服务设计模式》。如有异议欢迎探讨。

随机推荐

  1. This application failed to start because it could not find or load the Qt platforms plugins

     由于一直在linux下操作,今天Qt移植平台的时候导致.exe可执行文件一直运行不起来,提示缺少某些dll库,这个问题解决起来简单(直接去qt源码里面查找对应库添加到可执行文件目录就行),但是之后一 ...

  2. 笔记:C++学习之旅---指针

    笔记:C++学习之旅---指针 为什么要使用指针 因为在操作大型数据和类时,由于指针可以通过内存地址直接访问数据,从而避免在程序中赋值大量的代码,因此指针的效率最高,一般来说,指针会有三大用途: 1: ...

  3. 【易车网实例】x-sign逆向保姆级教程

    易车号x-sign逆向 前言 许多网站都有反爬机制,x-sign加密就是许多反爬虫机制的其中一种,本次将以易车号作为目标进行演示. 方法仅供学习参考. 链接:https://hao.yiche.com ...

  4. jenkins的安装和配置(flask结合jenkins半自动化部署流程)

    jenkins在虚拟机中安装 1.1 背景介绍 Jenkins 是一款流行的开源持续集成(Continuous Integration)工具,广泛用于项目开发,具有自动化构建.测试和部署等功能. Je ...

  5. 2022-12-09:上升的温度。以下的数据输出2和4,2015-01-02 的温度比前一天高(10 -> 25),2015-01-04 的温度比前一天高(20 -> 30),sql语句如何写? DR

    2022-12-09:上升的温度.以下的数据输出2和4,2015-01-02 的温度比前一天高(10 -> 25),2015-01-04 的温度比前一天高(20 -> 30),sql语句如 ...

  6. 2020-11-01:rust中带move闭包和不带move闭包有什么区别?

    福哥答案2020-11-01: 1.是否是同一个变量:带move闭包,函数外和函数内的同名变量不是同一个变量.不带move闭包,函数外和函数内的同名变量是同一个变量.2.执行完闭包后:带move闭包, ...

  7. 2022-06-19:给出n个数字,你可以任选其中一些数字相乘,相乘之后得到的新数字x, x的价值是x的不同质因子的数量。 返回所有选择数字的方案中,得到的x的价值之和。 来自携程。

    2022-06-19:给出n个数字,你可以任选其中一些数字相乘,相乘之后得到的新数字x, x的价值是x的不同质因子的数量. 返回所有选择数字的方案中,得到的x的价值之和. 来自携程. 答案2022-0 ...

  8. 2022-01-06:N个结点之间,表世界存在双向通行的道路,里世界存在双向通行的传送门. 若走表世界的道路,花费一分钟. 若走里世界的传送门,不花费时间,但是接下来一分钟不能走传送门. 输入: T为

    2022-01-06:N个结点之间,表世界存在双向通行的道路,里世界存在双向通行的传送门. 若走表世界的道路,花费一分钟. 若走里世界的传送门,不花费时间,但是接下来一分钟不能走传送门. 输入: T为 ...

  9. 狂神说ngnix笔记

    Nginx 一.什么是Nginx 二.Nginx的作用 三.Nginx的安装 1. Windows下安装 2.Linux下安装 3.Nginx目录结构 4.Nginx常用命令 5.Nginx配置文件结 ...

  10. git push origin master 提示输入用户名和密码

    今天更换了一台电脑,重新配置了SSH keys:但是在push得时候提示我输入用户名和密码 taodeMacBook-Pro:my_trip_proj tao$ git push origin mas ...