GithubHelp home page GithubHelp logo

00mjk / qubits Goto Github PK

View Code? Open in Web Editor NEW

This project forked from akonwi/qubits

0.0 0.0 0.0 129 KB

How I'd like to do CQRS

Home Page: http://akonwi.io/qubits

License: MIT License

CoffeeScript 60.25% JavaScript 39.75%

qubits's Introduction

Qubits

This was originally a simple POC and a way for me to write down my thoughts about how I would want to implement an eventsourced CQRS system. The focus here is on components/tools and functions that can be interchanged rather than a full framework.

components

  • Domain Model (Aggregate)

    This is the object that represents the state of our model. It is responsible for changing its own state as a result of Commands. Each state change results in an Event.

  • Events

    Objects representing a fact of state change in the domain model.

  • EventStore

    A storage facility for events/history/facts. This can be in memory or backed by a database.

  • EventBus

    The medium through which facts of state change are shared to interested observers.

  • EventListeners

    These are the observers of facts of state changes. They are functions to be invoked when the Aggregate has changed its state.

  • Repository

    A component through which we create and access the domain model. It's an in-memory collection of Aggregates.

  • Commands

    Objects representing an intent of state change by the user on the Aggregate.

  • CommandHandlers

    Functions with the purpose of communicating the intended state change to the Aggregate.

Based on these definitions of the components and given CommandHandlers (CH) and actions the Aggregate can do (A), the system should work like this:

CH(Command) -> A() -> [...Event]

This means every intention to change the state of the domain model results in n events (where n = 0 is a failure and n > 0 is success).

Examples of usage

Of course, I'll use a Todo application to demonstrate how this works.

const {defineAggregate, Event, EventStore, Repository, EventBus} = require('qubits')

const Todo = defineAggregate({
  name: 'Todo',
  state: {
    description: null,
    completed: false
  },
  methods: {
    complete: () => {
      this.state.completed = true
      return Event({
        aggregateId: this.id,
        name: 'TodoCompletedEvent',
        payload: {completed: true}
      })
    }
  }
})

// Create commands to represent intent to change state.
// These are just factory functions
const TodoCommands = {
  CreateTodo: ({id, description }) => {
    return {name: 'CreateTodo', message: {id, description}},
  },
  MarkAsCompleted: ({id}) => {
    return {name: 'MarkAsCompleted', message: {id}}
  }
}

const TodoEventStore = EventStore()
// If you want to persist events somewhere else like a database,
// it's easy to override how the event store works.
//
// const TodoEventStore = EventStore({
//  add: event => // put it somewhere
//  getEvents: => // return an array (or Promise of an array) of events
// })

const TodoRepository = Repository(Todo, TodoEventStore)

const TodoCommandHandlers = {
  CreateTodo: attrs => {
    return TodoRepository.add(attrs)
  },
  MarkAsCompleted: ({ id }) => {
    const todo = TodoRepository.load(id)
    return todo.complete()
  }
}

const TodoEventBus = EventBus()

// These are event listeners. They are plain functions with side effects.
// They don't need to return anything because they are simply observers
const TodoCreatedEventListenerToUpdateDB = event => // Update database...
const TodoCreatedEventListenerToLogStuff = event => // Do some logging...
const TodoCompletedEventListenerToSendNotification = event => // whatever...

TodoEventBus.registerListeners({
  TodoCreatedEvent: [
    TodoCreatedEventListenerToUpdateDB,
    TodoCreatedEventListenerToLogStuff
  ],
  TodoCompletedEvent: [TodoCompletedEventListenerToSendNotification]
})

It can(but doesn't have to) all come together like so...

const TodoFlow = Qubits.Flow({
  eventStore: TodoEventStore,
  eventBus: TodoEventBus,
  commandHandlers: TodoCommandHandlers
})

// Later when the user wants to do things...
TodoFlow.dispatch(TodoCommands.CreateTodo({id: 'todo1', description: 'Create a todo'}))
TodoFlow.dispatch(TodoCommands.MarkAsCompleted({id: 'todo1'}))

qubits's People

Contributors

akonwi avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.