CloudNotes领域模型还是相对简单的,并不一定需要采用面向领域驱动的设计方法来解决CloudNotes的领域问题。但出于以下几个方面的原因,我还是采用了面向领域驱动的方式来开发CloudNotes:

  1. 领域驱动是企业级应用开发的一种指导性模型,以领域模型作为软件开发的中心,符合解决问题的基本思路
  2. 现有的企业级应用开发框架对面向领域的开发模式支持得越来越好,如果选用这种方式,可以在CloudNotes中更好地利用这些框架的最新功能,为系统开发寻求新的机遇
  3. 自己对领域驱动设计相对比较熟悉,而且也维护了一套自己研发的DDD开发框架Apworks。在CloudNotes中直接复用该框架,可以大大减小开发投入,缩短开发周期
  4. 温故而知新,选用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之领域建模篇:领域模型简介的更多相关文章

  1. iOS开发UI篇—CALayer简介

    iOS开发UI篇—CALayer简介   一.简单介绍 在iOS中,你能看得见摸得着的东西基本上都是UIView,比如一个按钮.一个文本标签.一个文本输入框.一个图标等等,这些都是UIView. 其实 ...

  2. iOS开发多线程篇—多线程简介

    iOS开发多线程篇-多线程简介 一.进程和线程 1.什么是进程 进程是指在系统中正在执行的一个应用程序 每一个进程之间是独立的.每一个进程均执行在其专用且受保护的内存空间内 比方同一时候打开QQ.Xc ...

  3. SAP-ABAP系列 第一篇SAP简介

    第一篇 SAP简介 SAP全名为System Application and Products in Data Processing.SAP目前是全世界排名第一的RP软件,号称“全球最大的企业管理解决 ...

  4. Hadoop入门第五篇:Hive简介以及部署

    标签(空格分隔): Hadoop Hive hwi 1.Hive简介   之前我一直在Maxcompute上进行大数据开发,所以对数仓这块还算比较了解,在接受Hive的时候基本上没什么大的障碍.所以, ...

  5. Swift入门篇-swift简介

    潜水博客园很多年,闲来无事,聊一下自己的经历,语文不好(如有什么错别字,请您在下评论)望您谅解,没有上过什么学的 在前期 ios入门篇 -hello Word(1) 文章中介绍我这半年准备写一些ios ...

  6. 《Genesis-3D开源游戏引擎完整实例教程-2D射击游戏篇:简介及目录》(附上完整工程文件)

    G-3D引擎2D射击类游戏制作教程 游戏类型: 打飞机游戏属于射击类游戏中的一种,可以划分为卷轴射击类游戏. 视觉表现类型为:2D 框架简介: Genesis-3D引擎不仅为开发者提供一个3D游戏制作 ...

  7. 《Genesis-3D开源游戏引擎完整实例教程-跑酷游戏篇:简介及目录》(附上完整工程文件)

    跑酷游戏制作 游戏类型: 此游戏Demo,为跑酷类游戏. 框架简介: 游戏通常由程序代码和资源组成.如果说模型.贴图.声音之类的可以给游戏环境提供一个物理描述和设置,那么脚本和代码块会给游戏赋予生命, ...

  8. mysql基础篇-----mysql简介

    2017-04-19 一.mysql简介 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品.MySQL 是最流行的关系型数据库管理系统之一,在 ...

  9. Python【初识篇】简介

    python是什么? 为什么学python? python在权威语言排序网站上的热度 python历史排名 python应用领域 哪些公司在用python python官方简介 上面的话简单的总结来说 ...

随机推荐

  1. 一次修改闭源 Entity Provider 程序集以兼容新 EntityFramework 的过程

    读完本文你会知道,如何在没有源码的情况下,直接修改一个 DLL 以去除 DLL 上的强命名限制,并在该程序集上直接添加你的“友元程序集(一种特殊的 Attribute,将它应用在程序集上,使得程序集内 ...

  2. Java8实战分享

    虽然很多人已经使用了JDK8,看到不少代码,貌似大家对于Java语言or SDK的使用看起来还是停留在7甚至6. Java8在流式 or 链式处理,并发 or 并行方面增强了很多,函数式的风格使代码可 ...

  3. 我为NET狂官方面试题-数据库篇答案

    题目:http://www.cnblogs.com/dunitian/p/6028838.html 汇总:http://www.cnblogs.com/dunitian/p/5977425.html ...

  4. 23种设计模式--责任链模式-Chain of Responsibility Pattern

    一.责任链模式的介绍 责任链模式用简单点的话来说,将责任一步一步传下去,这就是责任,想到这个我们可以相当击鼓传花,这个是为了方便记忆,另外就是我们在项目中经常用到的审批流程等这一类的场景时我们就可以考 ...

  5. 使用Zabbix监控Oracle数据库

    Orabbix介绍 监控Oracle数据库我们需要安装第三方提供的Zabbix插件,我们先测试比较有名的Orabbix,http://www.smartmarmot.com/product/orabb ...

  6. java 利用ManagementFactory获取jvm,os的一些信息--转

    原文地址:http://blog.csdn.net/dream_broken/article/details/49759043 想了解下某个Java项目的运行时jvm的情况,可以使用一些监控工具,比如 ...

  7. StatePattern(状态模式)

    /** * 状态模式 * @author TMAC-J * 状态模式和策略模式很像,其实仔细研究发现完全不一样 * 策略模式各策略之间没有任何关系,独立的 * 状态模式各状态之间接口方法都是一样的 * ...

  8. Consul-template的简单应用:配置中心,服务发现与健康监测

    简介 Consul-template是Consul的一个方扩展工具,通过监听Consul中的数据可以动态修改一些配置文件,大家比较热衷于应用在Nginx,HAProxy上动态配置健康状态下的客户端反向 ...

  9. 微信小程序开发日记——高仿知乎日报(中)

    本人对知乎日报是情有独钟,看我的博客和github就知道了,写了几个不同技术类型的知乎日报APP要做微信小程序首先要对html,css,js有一定的基础,还有对微信小程序的API也要非常熟悉 我将该教 ...

  10. 2016/12/28_javascript

    今天学习的主要内容: javascript: 1.if语句,switch语句,while循环以及for循环: 1)if语句 if(boolean){}; if(boolean){} else if(b ...