前一篇文章 :"学习领域驱动设计开篇"给大家主要了解了下领域驱动设计是什么!这篇文章主要介绍下上下文映射图及架构相关方面的知识。
1.上下文映射图
1.1上下文映射图为何如此重要
当项目中开始采用DDD时,首先你应该为当前的项目绘制一个上下文映射图,该图主要描述当前项目中的限界上下文之间的集成关系!而上下文映射图的作用就是帮助我们从解决方案空间的角度来看待问题。(限界上下文已在上篇文章中介绍了)
U表示上游(Upstream)、D表示下游(Downstream)
1.2绘制上下文映射图
上下文映射图表现的是项目当前的状态,如果项目在将来发生变化,你可以到那时才对上下文映射图做相应的更新,关注当前的项目状态可以帮助你了解你所处的位置,并帮助你决定如何走出下一步。上下文映射图并不是一种企业架构,也不是系统拓扑图!上下文映射图展示了一种组织动态能力(Organizational dynamic),它可以帮助我们识别出有碍项目进度的一些管理问题。
这里介绍一个有意思的名词:大泥球(Big Ball Of Mud),当我们检查已有的系统时,经常会发现系统中存在混杂在一起的模型,他们之间的边界是非常模糊的。此时你应该为整个系统绘制一个边界,然后将其归纳在大泥球范围之内。往往在我们所在的项目中,经常是项目版本的迭代的时候出现这样的情况,导致后期维护代码越来越困难。所以我们需要在迭代的时候不断的对问题空间进行评估!
举个上下文映射图的例子:例如某网站的电商网站,身份认证模块与商品模块(涉及商品的购买加入购物车功能)。根据以上的信息构建一个上下文映射图。
会员模块/身份认证/商品模块,这三个不同的模块若是三个不同的小组同时去开发,那么这个会员账户模块作为上游,则需要考虑其他两个模块。那么则会员模块则定义一个接口,让其他两个模块通过接口来查询会员账户信息。这种方式叫做:开放主机服务:该模式可以通过REST实现,亦可以通过消息机制实现。
而会员会员接口信息的发布涉及到发布语言,常见的有XML、JOSN。而发布语言可以使用事件驱动架构。
身份认证的这块的防腐层的含义就是我这边的身份验证逻辑不能完全的依赖于上层。若完全的依赖的话就导致上层的更改,身份认证的逻辑就需要不断的变化。
2.架构
2.1简单描述
在没有具体的功能需求时候,我们是不能对软件的质量做出评估,也不能做出正确的架构选择。所以没有最好的架构模型,只有合适的架构模型。
2.2分层
分层架构是所有架构的始祖。它支出N层架构系统,因此被广泛的应用于Web、企业级应用、桌面应用等等系统中。例如我们熟知的三层架构。在分层架构中,我们将领域模型和业务逻辑分离出来,并减少对基础设施、用户界面甚至应用逻辑的依赖。传统的分层架构:用户接口层(User Interface)、应用层(Application Layer)、领域层(Domain Layer)、基础设施层(Infrastructure Layer)。分层重要的原则就是:每层只能与位于下方的层发生耦合。
用户界面只用于处理用户显示和用户请求,它不应该包含领域和业务逻辑。可能有这样的误区:用户界面需要对用户的输入进行验证,那么它就应该包含业务逻辑。事实上,用户界面所进行的验证和对领域模型的验证是不同的,用户输入的验证只是领域的模型的验证。而业务逻辑可能是用户购买多少金额而立减多少这样的业务逻辑。
应用服务是位于应用层中的,应用服务可以控制持久化事务和安全认证。最佳方案就是应用服务使用工厂模式或者聚合函数实例化对象。
2.3改进版分层—依赖倒置原则(Dependency Inversion Principle)
1.高层模块不应该依赖于底层模块,两者都应该依赖于抽象
2.抽象不应该依赖于细节,细节应该依赖于抽象
应用层可以采用不同的方式来获取这些实现,包括依赖注入(Dependency Injection)、服务工厂(Service Factory)、插件(Plug In)
2.4六边形架构
六边形架构又称:端口与适配器,是一种具有对称性特征的架构风格。不同的客户通过"平等"的方式与系统交互,当产生一个新的客户的时候,只需要添加一个新的适配器就可以了。
2.5面向服务架构
面向服务架构(Service-Oriented Architecture)有以下服务设计原则
- 服务契约
- 松耦合
- 服务抽象
- 服务重用性
- 服务自治性
- 服务无状态性
- 服务可发现性
- 服务组合性
2.6REST
在开放主机服务中可以使用REST,REST是Web架构的一种架构风格,准确的说REST是构建Web服务的一种方式。
2.7命令和查询职责分离—CQRS
在项目我们通常创建一个实体Model,该Model可能既用于插入又用于显示。这时候就有一个问题,那就是当业务需要要求显示的展示不同的时候,那么我就需要修改该Model,可能修改的时候还会影响插入功能。这时候我们就需要考虑命令和查询分离。
一个方法修改了对象的状态,该方法成为命令(Command),一般该方法返回void 。如果一个方法返回了数据,该方法便是一个查询(Query),该方法返回数据类型。命令模型(Command Model )一般包含add()、save()及主键查询方法。而查询模型(Query Model)则创建就是我们需要显示的模型实体。查询模型并不是一种规范的数据模型,它并不是反映领域行为,只是用于数据显示。
2.8事件驱动架构
事件驱动架构(Event-Driven Architecture)是一种处理事件的生成、发现和处理任务的软件架构。其中事件驱动最简单的实现就是管道和过滤器的组合。管道模式的升级版本就是"长时处理过程"。
设计长时处理过程的三个方法
- 将处理过程设计成一个组合任务,使一个执行组件进行跟踪,并对各个步骤和任务完成情况进行持久化
- 将处理过程设计成一个组合,这些聚合在一系列的活动中相互协作,一个或多个聚合实例充当执行组件并维护整个过程的状态
- 设计一个无状态的处理过程,其中每一个消息都对所接受到的消息进行扩充—即向其中加入额外的信息—然后再将消息发送到下一个处理组件。
3.总结
第二点的介绍的架构里面,当然还有本文中没有介绍到的架构,其中介绍的到也只是一些简单的定义描述,具体的怎么使用还是需要看实际的需求。而我认为目前需要掌握的就是命令与查询职责的分离。对于一个业务项目经常变化的来说的项目,命令与查询职责的分离能够很好的减少后期的代码的维护,也比较灵活的适合业务的发展的需求。好了,时间也不早了,今天文章先写到这里。下篇将介绍实体。