CloudNotes之领域建模篇:领域模型简介
CloudNotes领域模型还是相对简单的,并不一定需要采用面向领域驱动的设计方法来解决CloudNotes的领域问题。但出于以下几个方面的原因,我还是采用了面向领域驱动的方式来开发CloudNotes:
- 领域驱动是企业级应用开发的一种指导性模型,以领域模型作为软件开发的中心,符合解决问题的基本思路
- 现有的企业级应用开发框架对面向领域的开发模式支持得越来越好,如果选用这种方式,可以在CloudNotes中更好地利用这些框架的最新功能,为系统开发寻求新的机遇
- 自己对领域驱动设计相对比较熟悉,而且也维护了一套自己研发的DDD开发框架Apworks。在CloudNotes中直接复用该框架,可以大大减小开发投入,缩短开发周期
- 温故而知新,选用DDD来指导CloudNotes开发,可以获取到有关DDD的更多信息
接下来,让我们一起对CloudNote的领域模型作些简单的了解。
基本模型
如果你使用的是Visual Studio 2013/2015旗舰版(Ultimate Edition),那么在打开CloudNotes解决方案后,你可以在CloudNotes.Design项目下,找到CloudNotesModel.classdiagram类图设计文件:

双击该文件,可以打开CloudNotes的领域模型设计视图。到目前为止,CloudNotes的领域模型如下:

咱们暂且不考虑C# class、aggregate root等这些UML构造型,这些内容我会在接下来的文章中详细介绍(顺带会介绍Visual Studio对于模型设计与自动化代码产生的支持)。从该图可以看出,CloudNotes的领域模型还是相对简单的。基本上可以分为三个大部分:笔记、用户以及客户包(ClientPackage)。或许你会考虑,是否可以将这些部分看成是DDD的界定上下文(Bounded Context)呢?
界定上下文(Bounded Context)
是的,我们可以考虑将CloudNotes的领域模型划分为三个界定上下文:
- 笔记界定上下文:管理系统中所有的笔记内容
- 用户认证与授权上下文:管理系统账户、角色以及权限
- 客户包管理上下文:管理针对所有客户端平台的升级包
从DDD角度看,由于模型被划分为多个上下文,而且上下文中的子模型也都是高内聚的(界定的),因此有可能会产生概念或语义上的二义性,而这又是通用语言(Ubiquitous Language)所不能容忍的。比如,一个经典的例子就是银行系统里“Account” 的概念:一个提供在线服务的银行系统,简单地说可以粗略地分为两个界定上下文:银行业务以及在线服务。对于银行业务而言,Account表示客户的银行账户,而对于在线服务而言,Account则又表示客户的在线登录账号,而且一个在线登录账号下可以承载多个银行账户,好比招商银行一网通账号可以有多个银行卡账户和信用卡账户等。那么在做系统设计的时候,遇到Account概念时,如何保证团队交流的准确性呢?因此,需要在领域模型中有一个能够解除这种二义性的“组件”,负责帮助团队人员在整个领域模型的理解与交流上保持一致。这种“组件”就是平时常说的“上下文映射(Context Map)”。有关界定上下文以及上下文映射的详细介绍,可以参考这篇文章:Strategic Domain Driven Design with Context Mapping。
当应用程序所需处理的领域变得很大时,引入界定上下文是很有必要的,从实践角度考虑,使用界定上下文不仅可以在一个相对封闭的范围内,使用一个相对较小的子领域模型,而且还可以从一定程度上提升应用程序的性能:比如某个操作只会发生在系统的某个子领域内部,又如较小的领域模型能够减少系统的处理开销。在Entity Framework 代码先行(Code-First)的开发过程中,可以很好地引入界定上下文的概念,以将复杂的领域模型划分成多个相对较小的简单的领域模型,不仅在模型设计还是在性能上,都有着很好的表现。有关这个话题的更多内容,可以参考我之前翻译的一篇文章:Entity Framework模型在领域驱动设计界定上下文中的应用。
CloudNotes的领域模型相对简单,而且虽然目前后台采用的是Entity Framework,但使用Entity Framework并不是必须的,今后有可能会换成其它的数据持久化系统(比如MongoDB),因此也没有按照上面所述的方式应用界定上下文的相关概念。
实体键
由于CloudNotes使用了Apworks框架,因此CloudNotes领域模型中的实体都是使用Guid作为实体键的。这一问题就要引入对Apworks框架的讨论。在Apworks框架中,我们可以看到以下代码:
public interface IEntity
{
/// <summary>
/// Gets or sets the identifier of the entity.
/// </summary>
Guid ID { get; set; }
}
在Apworks中,实体键是Guid类型的。有关实体键的类型选择,在Vaughn Vernon的《实现领域驱动设计》一书中,有相关的描述。概括起来,大致有以下几种情况:
- 用户指定实体键:这种方式最为直观:用户在界面上直接提供某个值,作为实体的键值。但通常而言,实体键值应该是不可变(immutable)的,于是,当用户为某个实体选定了实体键值后,一般是不允许修改的。但这样做又显得跟标准的用户操作流程不相符:我自己输入的东西,凭什么不让我改?另一种情况就是,用户可以修改实体键的值,但这种修改或许还会带来更多的影响,例如某个实体键发生变化时,由该实体发起的所有事件数据中针对该实体的引用也要发生改变。当然,如果应用程序需要保证实体键的可读性时,我们就不得不设计一套合理的机制,来确保可读性和可行性不会发生冲突
- 应用程序产生实体键: 很多应用程序会通过应用程序来产生实体键,比如通过应用程序开发框架提供的Guid/UUID生成算法来产生实体键。使用Guid不仅简单而且相对比较高效,更重要的是,它不需要依赖于应用程序以外的任何外部机制,比如持久化系统等。此外,正如《实现领域驱动设计》一书中所述,有些对性能要求很高的系统,会在一个独立的服务器上(或者有可能是一个后台的服务上)缓存一定数量的ID值,使用Guid就不会产生因ID服务器崩溃或重启而出现ID值重复或不连续的情况,因为Guid的生成程序始终能够保证ID值的唯一性。另一方面,如果需要通过应用程序来产生实体键值,那么我们就需要完美地解决ID值的同步问题,而且还需要考虑性能问题,更进一步,企业级应用系统往往都是由多个应用程序组成的,是否,以及如何保证实体键在这些应用之间的统一,也是一件不容易的事情
- 借助持久化机制产生实体键:这种情况非常常见,例如ORM系统会借助关系型数据库为实体设置键值。这也是一种简单方便的ID值获取方式,因为可以借用持久化机制来获得ID值缓存的功能,而且还能保证ID值的唯一性。但这往往也并不高效,毕竟需要借助外部系统,持久化机制的性能表现,也将对应用程序本身的性能造成影响甚至成为性能瓶颈。对于大型分布式企业级应用解决方案而言,也存在ID值的同步和统一的问题,例如应用程序A和B采用了不同的持久化机制,然而却无法保证原本应该保持一致的实体键值
- 外部界定上下文指定实体键:这种方式并不常见,在大型的企业级应用系统解决方案中可以用到,但也并不一定会采用这种方式。它是通过领域事件的方式,在界定上下文之间进行信息传递,比如本地界定上下文(Local Bounded Context)通过订阅来自外部界定上下文的领域事件,并通过事件中的信息,以在本地界定上下文中还原实体,于是ID值也一并被还原过来,以便表示当前实体与外部界定上下文中另一对象是同一实体
很显然,Apworks采用的就是上述Guid的方式,这样做实现起来比较简单高效,而且Guid值类型的特性,在绝大多数存储系统中都能很好地支持。当然它也有一些弊端,比如可读性差,以及在某些存储系统中性能并不算太好等。无论如何,就Apworks框架本身而言,应该提供一套实体键产生的框架,以便开发人员能够扩展ID值的产生机制,而不应该将ID值类型限定在Guid之上。这在老版本的Apworks中是有类似机制的,只是在考虑到装箱、拆箱带来的性能问题后,就在新的版本中,把这种机制给取消了,也就演变到目前的这种情形。今后我还是会继续改进这部分的设计的。
总结
CloudNotes的领域模型相对简单,实现上采用了Apworks框架,并借用了Visual Studio Ultimate的Architecture功能,对领域模型进行可视化设计和自动化代码生成。或许在今后领域模型会进一步修改,或者逐渐变大,或许也会由此而采用一些新的技术,并产生新的解决方案。到目前为止,CloudNotes的领域模型规模还是很小的,本系列文章也会首先针对当前的这个模型来进行介绍。
CloudNotes之领域建模篇:领域模型简介的更多相关文章
- iOS开发UI篇—CALayer简介
iOS开发UI篇—CALayer简介 一.简单介绍 在iOS中,你能看得见摸得着的东西基本上都是UIView,比如一个按钮.一个文本标签.一个文本输入框.一个图标等等,这些都是UIView. 其实 ...
- iOS开发多线程篇—多线程简介
iOS开发多线程篇-多线程简介 一.进程和线程 1.什么是进程 进程是指在系统中正在执行的一个应用程序 每一个进程之间是独立的.每一个进程均执行在其专用且受保护的内存空间内 比方同一时候打开QQ.Xc ...
- SAP-ABAP系列 第一篇SAP简介
第一篇 SAP简介 SAP全名为System Application and Products in Data Processing.SAP目前是全世界排名第一的RP软件,号称“全球最大的企业管理解决 ...
- Hadoop入门第五篇:Hive简介以及部署
标签(空格分隔): Hadoop Hive hwi 1.Hive简介 之前我一直在Maxcompute上进行大数据开发,所以对数仓这块还算比较了解,在接受Hive的时候基本上没什么大的障碍.所以, ...
- Swift入门篇-swift简介
潜水博客园很多年,闲来无事,聊一下自己的经历,语文不好(如有什么错别字,请您在下评论)望您谅解,没有上过什么学的 在前期 ios入门篇 -hello Word(1) 文章中介绍我这半年准备写一些ios ...
- 《Genesis-3D开源游戏引擎完整实例教程-2D射击游戏篇:简介及目录》(附上完整工程文件)
G-3D引擎2D射击类游戏制作教程 游戏类型: 打飞机游戏属于射击类游戏中的一种,可以划分为卷轴射击类游戏. 视觉表现类型为:2D 框架简介: Genesis-3D引擎不仅为开发者提供一个3D游戏制作 ...
- 《Genesis-3D开源游戏引擎完整实例教程-跑酷游戏篇:简介及目录》(附上完整工程文件)
跑酷游戏制作 游戏类型: 此游戏Demo,为跑酷类游戏. 框架简介: 游戏通常由程序代码和资源组成.如果说模型.贴图.声音之类的可以给游戏环境提供一个物理描述和设置,那么脚本和代码块会给游戏赋予生命, ...
- mysql基础篇-----mysql简介
2017-04-19 一.mysql简介 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品.MySQL 是最流行的关系型数据库管理系统之一,在 ...
- Python【初识篇】简介
python是什么? 为什么学python? python在权威语言排序网站上的热度 python历史排名 python应用领域 哪些公司在用python python官方简介 上面的话简单的总结来说 ...
随机推荐
- Js 变量声明提升和函数声明提升
Js代码分为两个阶段:编译阶段和执行阶段 Js代码的编译阶段会找到所有的声明,并用合适的作用域将它们关联起来,这是词法作用域的核心内容 包括变量声明(var a)和函数声明(function a(){ ...
- Jquery mobiscroll 移动设备(手机)wap日期时间选择插件以及滑动、滚动插件
Jquery Mobiscroll是一个用于触摸设备(Android phones, iPhone, iPad, Galaxy Tab)的日期和时间选择器jQuery插件.以及各种滑动插件 可以让用户 ...
- CoreCRM 开发实录——Travis-CI 实现 .NET Core 程度在 macOS 上的构建和测试 [无水干货]
上一篇文章我提到:为了使用"国货",我把 Linux 上的构建和测试委托给了 DaoCloud,而 Travis-CI 不能放着不用啊.还好,这货支持 macOS 系统.所以就把 ...
- 使用 JavaScript 和 canvas 做精确的像素碰撞检测
原文地址:Pixel accurate collision detection with Javascript and Canvas 译者:nzbin 我正在开发一个需要再次使用碰撞检测的游戏.我通常 ...
- windows+nginx+iis+redis+Task.MainForm构建分布式架构 之 (nginx+iis构建服务集群)
本次要分享的是利用windows+nginx+iis+redis+Task.MainForm组建分布式架构,由标题就能看出此内容不是一篇分享文章能说完的,所以我打算分几篇分享文章来讲解,一步一步实现分 ...
- 第一个移动前端开源项目-dailog
你还在为手机上没有忙碌光标而发愁吗?你还在抱怨弹出框组件要依赖zepto/jqery吗?你还在纠结是否要自己写一套还是去网上寻找成现成的UI组件吗?YouA为你轻松解决所有烦恼.YouA是我为移动前端 ...
- PHP-----文件系统的交互
本文讲解php中于文件交互中所使用的函数 代码示例 <html> <head> <title> File Detail </title> </he ...
- C++ 拷贝构造函数和赋值运算符
本文主要介绍了拷贝构造函数和赋值运算符的区别,以及在什么时候调用拷贝构造函数.什么情况下调用赋值运算符.最后,简单的分析了下深拷贝和浅拷贝的问题. 拷贝构造函数和赋值运算符 在默认情况下(用户没有定义 ...
- BPM生产安全管理解决方案分享
一.方案概述生产安全管理是企业生产管理的重要组成部分,组织实施好企业安全管理规划.指导.检查和决策,保证生产处于最佳安全状态是安全管理的重要内容和职责.H3 BPM企业生产安全管理解决方案是一套专门为 ...
- VS2015墙内创建ionic2 【利用nrm更换源,完美!】
STEP 1 设置cnpm npm install -g cnpm --registry=https://registry.npm.taobao.org 一句话建立cnpm STEP 2 安装nr ...