CQRS框架(nodejs的DDD开发落地框架)初识感想

CQRS是啥?DDD又是啥?

这两个概念其实没什么神秘的,当然此文章中的这两个概念以曾老师的课程为准(关于CQRS和DDD的标准概念,google上已经很多了,不再赘述。)

DDD(Domain Driven Design),领域驱动设计开发。

DDD和OOP有什么同吗?其实就我个人经验来说,没有任何不同(当然你可以反驳我),DDD就是OOP。这里以曾老师课上的概念为准,domain就是世界,包含了当前所有actor的一个域,这个域是一个上帝视角,可以监听每一个域中发生的事件,并且记录。

CQRS,既命令和查询职责分离(Command Query Responsibility Segregation)。

在普通mvc架构中,对于数据库的CRUD基本都是写在controller层,这样一来路由非常臃肿,而且维护起来简直是噩梦。

CQRS将查询与职责分离。简单说来,就是写操作和读操作分离,读操作写在路由中,写操作通过面向对象写入类的业务方法中,这样路由中的查询部分薄了,而且对于写操作的可读性,重用性和维护性大大提高。

相比较于普通mvc,cqrs分为核心层Core(及核心层扩展Core Extension)应用层(Application),UI层,看起来3层,其实是四层,但是由于核心层与核心层扩展的伸缩性很强,并且针对项目的大小来决定,所以就我觉得用3.5层来描述比较合适。

取cqrs文档中的例子


const {Actor} = require("cqrs");

module.exports = class User extends Actor{
  constructor(data){
     const {name} = data;
     super({
       name,
       createTime: Date.now(),
       stars:[], // 被关注明星的 ids
       watchers:[] //  关注者的 ids
     });
  }

  // 关注某位明星
  async follow(starId){
    const service = this.service;
    const star = await service.get("User",starId);
    if(starId !== this.id && star){
      await star.addWatcher(this.id);
      this.$(starId)
    }
  }

  // 取消关注某位明星
  async unFollow(starId){
    const star = await this.service.get("User",starId);
    if(star){
      await star.deleteWatcher(this.id);
      this.$(starId);
    }
  }

  // 加入关注者 watcher
  addWatcher(watcherId){
    if(watcherId !== this.id)
    this.$(watcherId);
  }

  // 取消被关
  deleteWatcher(watcherId){
    this.$(watcherId);
  }

  get updater(){
    return {
      follow(json, event){
        const stars = json.stars;
        stars.push(event.data);
        return {
          stars
        }
      },
      unFollow(json, event){
        const stars = json.stars;

        var set = new Set(stars);
        set.delete(event.data);

        return {
          stars:[...set]
        }
      },
      addWatcher(json,event){
        const watchers = json.watchers;
        watchers.push(event.data);
        return {
          watchers
        }
      },
      deleteWatcher(json,event){
        const watchers = json.watchers;
        const set = new Set(watchers);
        set.delete(event.data);
        return {
          watchers:[...set]
        }
      }
    }
  }
}

以上例子是一个cqrs (传送门)Actor的实现,通过this.$产生一个事件,事件由updater接收,进行数据的真正修改。


const {Domain} = require("cqrs");
const User = require("./User");
const domain = new Domain();

// 注册 User Actor 类
domain.register(User);

// 即时异步执行函数
(async function () {

  // 创建用户1
  let user1 = await domain.create("User",{
    name:"leo"
  });

  // 创建用户2
  let user2 = await domain.create("User",{
    name:"zengliang"
  })

  // user1 关注 user2
  await user1.follow(user2.id);

  console.log(user1.json.stars); // 打印一下 user1 监听所有 ids
  console.log(user2.json.watchers);  // 打印一下 user2 追随者的所有 ids

  user1.unFollow(user2.id);  // user1 取消关注 user2

  // 重新加载 user1 和 user2
  user1 = await domain.get("User",user1.id);
  user2 = await domain.get("User",user2.id);

  console.log(user1.json.stars); // 打印一下 user1 监听所有 ids
  console.log(user2.json.watchers);  // 打印一下 user2 追随者的所有 ids

})();

以上是在运行中对User实例对象的操作,关注与取关的操作。

Any fool can write code that a computer can understand. Good programmers write code that humans can understand. -- 某位大牛

以上的例子很好的诠释了可读性还有重用性。对于写操作来说,完全用业务方法来实现,那么路由中可以仅包含cqrs中Q的部分,这样做到了业务和查询分离,那么迷惑也开始解开了。

  • 写操作,用业务方法来完成,属于核心层
  • query,既查询操作,写在router中,是应用层变薄

在使用普通mvc的时候,逻辑和查询通常都会放在路由当中,这样造成的高耦合性(coupling)让代码的重用性,可读性,可伸缩性很差。维护起来简直噩梦连连。我的第一个项目是用标准mvc完成,后期加新需求的时候基本山就是牵一发动全身,也是我的经验确实不够对于很多地方没有对代码进行可重用的封装。

现在浅谈一下 Auxo(传送门)

Auxo框架集成了Nuxt(Vue),Vuex,Express,cqrs四个重要框架。这样在开发时就不用再辛苦搭建开发环境了,直截了当。Auxo是约定式的框架,关于文件结构是根据Nuxt(传送门)的,所以有必要读一读Nuxt的文档,对Nuxt有一定了解之后就可以用了而且上手很快,因为基本上不需要配置什么东西。

在Auxo框架中,数据遵循Event Sourcing原则,分两个collection。

  • 一个是事件数据库记录在domain中发生的所有事件,让事件回溯、长故事(saga)和事件锁(lock)成为可能;
  • 另外一个是查询数据库,记录普通数据,我自己的理解就是面向数据库开发的那种最基本的数据库。

eventstore

记录事件对象的数据库,可以通过该数据库的数据进行数据回溯。

snap

事件快照。domain中的事件的一个snapshot,我暂且理解为一个log

server/index.js 中的 req.dbs req.$domain

这两个属性已经在框架中直接挂载在了req对象上,归功于曾老师。在server/index.js中,已经定义好了,这个文件相当于express的app.js,只是文件名不一样。
req.dbs就是上述的查询数据库,可以使用mongojs来query。
req.$domain就是domain,即上帝视角,可以用以下语句


req.$domain.get('User', uid); // 获取User对象
req.$domain.create('User', {username: 'ephraimguo', password:'*******'}); // 创建user对象

等domain对象的方法进行数据操作。

在Vue组件中的axiosdomain

这两个对象已经写在plugins/文件夹里面,可以直接在Vue组件中引用如下

    <!-- Vue Template -->
</template>
<script>
    import axios from '@/plugins/aixos'
    import domain from '@/plugins/domain'
    // ... codes ...
</script>
<style>
    /* some style sheet */
</style>

Listener 核心层扩展 (有个小坑)

起初看到曾老师用listener但是不明白怎么监听,而且去看epxress-cqrs的源码的时候,看到listener的路径是作参数与传入了的。

截取一段express-cqrs的源码


// Register Actors Class from actors folder
ActorList.filter(Actor => /.*\.js$/.test(Actor)).
    forEach(Actor => domain.register(require(path.join(actorPath, Actor))));

// Get Listener from listener folder
listeners.filter(listener => /.*\.js$/.test(listener)).
    forEach(listener => require(path.join(listenerPath, listener))(domain));
  • 第一步,在根目录下添加listener文件夹
  • 第二部,创建新的监听js文件,

Listener 内部写法,如下(个人经验)



module.exports = function(domain){
    // Utilise domain.on(...) to make onAction listening
}


这次先暂时聊这么多,cqrs还有很多好用的方法和思想可以慢慢琢磨,而且这种编程思想易实践,并且对全局的把控更精准,心有猛虎细嗅蔷薇,当然这篇文章也是针对上过曾老师课的童鞋们,不算是扫盲,过后会继续写一些关于cqrs框架应用的文章,也欢迎大家提问,并且一起讨论。如果有错误,也请大家指正,我会马上修改。

来源:https://segmentfault.com/a/1190000016772949

原文地址:https://www.cnblogs.com/datiangou/p/10173208.html

时间: 2024-08-29 10:35:15

CQRS框架(nodejs的DDD开发落地框架)初识感想的相关文章

应用程序框架实战十三:DDD分层架构之我见(转)

前面介绍了应用程序框架的一个重要组成部分——公共操作类,并提供了一个数据类型转换公共操作类作为示例进行演示.下面准备介绍应用程序框架的另一个重要组成部分,即体系架构支持.你不一定要使用DDD这样的架构,使用单层架构和普通三层架构一样可以,不过你如果希望获得更进一步的复用性和封装度,使用更加面向对象的技术是必经之程. 我在2010年以前还在使用古老的ASP.NET WebForm和原始的Ado.Net.之前我有个观念:.NET技术发展太快,跟着微软屁股后面跑太累,所以只使用它一些原始的东西,自己封

转-基于NodeJS的14款Web框架

基于NodeJS的14款Web框架 2014-10-16 23:28 作者: NodeJSNet 来源: 本站 浏览: 1,399 次阅读 我要评论暂无评论 字号: 大 中 小 摘要: 在几年的时间里,Node.js逐渐发展成一个成熟的开发平台,吸引了许多开发者.有许多大型高流量网站都采用Node.js进行开发,像PayPal,此外,开发人员还可以使用它来开发一些快速移动Web框架. 下面就介绍14款基于Node.js的Web应用框架,大家不... 在几年的时间里,Node.js逐渐发展成一个成

应用程序框架实战十三:DDD分层架构之我见

前面介绍了应用程序框架的一个重要组成部分——公共操作类,并提供了一个数据类型转换公共操作类作为示例进行演示.下面准备介绍应用程序框架的另一个重要组成部分,即体系架构支持.你不一定要使用DDD这样的架构,使用单层架构和普通三层架构一样可以,不过你如果希望获得更进一步的复用性和封装度,使用更加面向对象的技术是必经之程. 我在2010年以前还在使用古老的ASP.NET WebForm和原始的Ado.Net.之前我有个观念:.NET技术发展太快,跟着微软屁股后面跑太累,所以只使用它一些原始的东西,自己封

应用程序框架实战十七:DDD分层架构之值对象(层超类型篇)

上一篇介绍了值对象的基本概念,得到了一些朋友的支持,另外也有一些朋友提出了不同意见.这其实是很自然的事情,设计本来就充满了各种可能性,没有绝对正确的做法,只有更好的实践.但是设计与实践的好与坏,对于不同的人,以及处于不同的环境都有不同的诠释,这是一个仁者见仁,智者见智的问题.DDD非常抽象,以至于它的每一个概念,对于不同的人都有不同的看法,更何况基于DDD的.Net实践,就更难分辨哪一个用法更标准.更正宗. 我对DDD的认识虽然还很肤浅,用得也很山寨,但这可能更加适合初步接触DDD的朋友.还是那

移动开发主流框架的选取以及技术选型方案解析

传统的移动开发模式主要分为三种,Native App,Web App 和 Hybrid App,对于目前微信端比较火爆的开发平台小程序,或者其他厂商推广的流应用.轻应用等开发方式,基本都离不开H5的支撑.目前App前端开发主流框架RN,Ionic,Vue都发展得不错.但是业务需求的快速发展,有些框架并不能够满足他们的需求,在不同的业务场景,受诸多约束因素的影响,研发团队应该如何在前端框架上做好选型? 根据目前51CTO社群(群号312724475)中大部分移动开发领域的开发者实际项目经验,我们邀

基于C/S架构的3D对战网络游戏C++框架 _05搭建系统开发环境与Boost智能指针、内存池初步了解

本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): 1.实现基本通信框架,包括对游戏的需求分析.设计及开发环境和通信框架的搭建: 2.实现网络底层操作,包括创建线程池.序列化网络包等: 3.实战演练,实现类似于CS反恐精英的3D对战网络游戏: 技术要点:C++面向对象思想.网络编程.Qt界面开发.Qt控件知识.Boost智能指针.STL算法.STL.

使用 ACE 库框架在 UNIX 中开发高性能并发应用

使用 ACE 库框架在 UNIX 中开发高性能并发应用来源:developerWorks 中国 作者:Arpan Sen ACE 开放源码工具包可以帮助开发人员创建健壮的可移植多线程应用程序.本文讨论创建使用 ACE 线程的应用程序的一些方法.Adaptive Communication Environment (ACE) 是一个高性能.开放源码.面向对象的框架和 C++ 类库,它有助于简化网络应用程序的开发.ACE 工具包包括一个操作系统层和一个封装网络 API 的 C++ 外观(facade

【课程分享】jQuery2.0应用开发:SSH框架整合jQuery2.0实战OA办公自动化(VSS、operamasks-UI框架)

我的qq是2059055336,对这个课程有兴趣的可以加我qq联系. 课程下载地址:链接:http://pan.baidu.com/share/link?shareid=395438909&uk=3611155194 密码:mlvl 课程下载地址:http://www.kuaipan.cn/file/id_192202874577496484.htm?source=1 一.本课程是怎么样的一门课程(全面介绍)    1.1.课程的背景 jQuery 2.0 正式版发布,不在支持 IE 6/7/8

Entity Framework 实体框架的形成之旅--实体框架的开发的几个经验总结

在前阵子,我对实体框架进行了一定的研究,然后把整个学习的过程开了一个系列,以逐步深入的方式解读实体框架的相关技术,期间每每碰到一些新的问题需要潜入研究.本文继续前面的主题介绍,着重从整体性的来总结一下实体框架的一些方面,希望针对这些实际问题,和大家进行学习交流. 我的整个实体框架的学习和研究,是以我的Winform框架顺利升级到这个实体框架基础上为一个阶段终结,这个阶段事情很多,从开始客运联网售票的WebAPI平台的开发,到微软实体框架的深入研究,以及<基于Metronic的Bootstrap开