HTML5技术

DDD 领域驱动设计-如何 DDD? - 田园里的蟋蟀

字号+ 作者:H5之家 来源:博客园 2016-04-15 14:00 我要评论( )

注:科比今天要退役了,我是 60 亿分之一,满腹怀念~ 前几天看了园友的一篇文章《我眼中的领域驱动设计》,文中有段话直击痛点:有人误认为项目架构中加入 Repository,Domain,ValueObject 就变成了 DDD 架构。没错,我就是这样,不过准确的来说,并不能称

注:科比今天要退役了,我是 60 亿分之一,满腹怀念~

前几天看了园友的一篇文章《我眼中的领域驱动设计》,文中有段话直击痛点:有人误认为项目架构中加入 Repository,Domain,ValueObject 就变成了 DDD 架构。没错,我就是这样,不过准确的来说,并不能称为 DDD 架构,而是我之前经常说的“伪 DDD”设计,后来我还抽离出了一个伪 DDD 设计框架:DDD.Sample,大家有兴趣的可以瞧瞧,在实际项目的开发中,我用它做过了几个不太大的项目,我个人觉得用起来很顺手,当然并没有真正的 DDD 设计,只不过用了一个空的架构而已,然后冠以”DDD 开发“的名号。

因为之前有过 DDD 设计的痛苦经历(短消息系统),具体表现就是,如果真正 DDD 设计,需要花费大量的时间和精力,可能几天都在思考一个问题或者考虑几行代码的编写,但最后也可能没什么结论或结果,并且这个过程是很艰难和痛苦的,所以我后来就变懒了,懒的去思考项目所表现的业务,也不再考虑如何去设计领域模型,只是在考虑如何让框架用起来更爽,DDD.Sample 前两个应用的实际项目,我都是在完善这个框架,比如 Repository 和 UnitOfWork 的设计等等,所以,关于领域模型的设计,就是一堆贫血模型。不过,后来应用的第三个项目,也就是上一个实际项目,我觉得不能再这样下去了,因为没啥意义,框架一遍一遍的套用,而 DDD 却和它没半毛钱关系,所以,我就花了点时间去思考(只是简单的思考):我做这个项目的核心业务是什么?我该如何提炼出核心业务?提炼出核心业务之后,其他的任何实现都是为核心业务服务的,所以,你可以把这个核心业务看成领域模型。

关于第三个应用项目,实际上就是我们园子的“提到我”系统,现在已经应用在新闻评论了,大家可以去瞧瞧,类似为微博的“提到我”,相对比较简单的一个系统,你可以在评论中 @一个人,然后另一个人会接受通知,那这个系统的核心业务是什么?其实就是上面那句话,只不过你需要抽离出一些内容,如果领域专家和开发人员进行交流这个系统的设计,那领域专家的表述就是:你可以在评论中 @一个人,然后另一个人会接受通知,领域专家可能不懂代码设计,他的这个表述就是最直接和最精准的业务,所以,我们需要针对这段话,再和领域专家深入探讨下所蕴含的业务:

  • 你可以在评论中 @一个人 -> @一个人 -> 怎么能得到并确认这个“一个人” -> @匹配规则
  • 另一个人会接受通知 -> 通知 -> 通知所 @的人
  • 所以,@匹配规则和通知所 @的人是“提到我”系统的核心业务,确定好核心业务了,那就该具体的实现了,关于这个我没有深入的去考虑,就直接放在了 Mention(提到)中,大致代码:

    namespace CNBlogs.Mention.Domain { public class Mention : IAggregateRoot { SplitRegex = "::  @,"; Regex MentionsRegex = new Regex($"@([^{SplitRegex}]+)", RegexOptions.Compiled); public int Id { get; set; } public string Content { get; set; } public int ContentId { get; set; } public AppType AppType { get; set; } ... //抽离 public async Task<List<int>> Extract() { ... } //通知 public async Task Notify() { ... } } }

    看起来很简单,就是把两个方法放在了 Mention 中,但这简单的操作却好像给 Mention 领域模型生命一样,不再那么贫血,对于复杂系统的业务变化,往往是核心业务的变化,其他的都是为核心业务服务的业务流程,并不能真正称为业务,比如 Application 层的代码,现在领域专家说 @一个人的规则需要改变,或者通知规则需要变化,我们只需要修改 Mention 领域模型的代码就行了,其他的代码并不需要修改,这就是 DDD 设计最浅显的体现。

    大致贴下 Application 层的伪代码:

    namespace CNBlogs.Mention.Application.Services { public class MentionService : IMentionService { private IMentionRepository _mentionRepository; private IUnitOfWork _unitOfWork; public MentionService(IUnitOfWork unitOfWork, IMentionRepository mentionRepository) { _unitOfWork = unitOfWork; _mentionRepository = mentionRepository; } public async Task<SubmitResult> Submit(string content ,int contentId, AppType appType) { var notifyMentions = new List<Domain.Mention>(); var existingQuery = _mentionRepository.Get(contentId, appType); var mention = new Domain.Mention() { Content = content, ContentId = contentId, AppType = appType }; var userIds = await mention.Extract(); foreach (var userId in userIds) { var userQuery = existingQuery.Where(x => x.UserId == userId); if (await userQuery.AnyAsync()) { await userQuery.UpdateAsync(x => new Domain.Mention { Content = content, DateUpdated = DateTime.Now }); } else { mention.UserId = userId; _unitOfWork.RegisterNew(mention); notifyMentions.Add(mention); } } if (await _unitOfWork.CommitAsync()) { foreach (var notifyMention in notifyMentions) { await notifyMention.Notify(); } (); } return new SubmitResult { IsSucceed = false }; } } }

    可以看到,Submit 中的操作基本上都是工作流程,先抽取用户,再进行判断更新,然后进行持久化,最后进行通知,没有任何业务体现,所以,如果核心业务发生了变化,这部分的代码并不需要随之改变。

    如何 DDD?

    引自:《Implementing DDD Reading - Strategic Design》

     

    1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

    相关文章
    • 设计模式(1)单例模式(Singleton) - Fonour

      设计模式(1)单例模式(Singleton) - Fonour

      2017-04-23 12:00

    • 架构设计师能力模型 - BloodyAngel

      架构设计师能力模型 - BloodyAngel

      2017-03-28 11:00

    • 设计模式(0)简单工厂模式 - Fonour

      设计模式(0)简单工厂模式 - Fonour

      2017-03-25 15:01

    • 没有功能需求设计文档?对不起,拒绝开发! - CharlieChu

      没有功能需求设计文档?对不起,拒绝开发! - CharlieChu

      2017-03-16 13:04

    网友点评
    b