Not production ready. API might change heavily. First public release will be 0.2.0
Behavior-first application development. Runs on NodeJS and modern Browsers.
Because MVC evolved.
- Emphasize Domain-driven design, Event-driven architecture and Task-based UIs.
- Start with the Behavior of your application and go from there (BDD)
- Put the the Domain Model in the very center of your Layered Architecture (Onion / Hexagonal)
- Explicitly set boundaries for parts of your application (BoundedContexts / MicroServices)
- Separation of concerns using Commands and Queries (CQRS / Flux)
- Capture all changes to your application state as a sequence of DomainEvents (EventSourcing)
- Support occasionally connected clients (offline-first / nobackend)
- Be reactive (Manifesto)
Take a look at the eventric TodoMVC for a running example, or try it yourself:
We need to install eventric first.
npm install eventric
Having discussed the upcoming TodoApp Project with the Business-Experts and fellow Developers it got clear that we should start with a Context
named Todo
.
eventric = require('eventric');
todoContext = eventric.context('Todo');
Inside of our Todo
Context things will happen which are called DomainEvents. A technique to come up with these is called EventStorming. Lets add two called TodoCreated
and TodoDescriptionChanged
.
todoContext.defineDomainEvents({
TodoCreated: function(params) {},
TodoDescriptionChanged: function(params) {
this.description = params.description;
}
});
Now we need an Aggregate which actually raises this DomainEvents.
todoContext.addAggregate('Todo', function() {
this.create = function() {
this.$emitDomainEvent('TodoCreated');
}
this.changeDescription = function(description) {
this.$emitDomainEvent('TodoDescriptionChanged', {description: description});
}
});
Hint:
this.create
is called by convention when you create an aggregate usingthis.$aggregate.create
Hint:
this.$emitDomainEvent
is dependency injected
To actually work with the Context
from the outside world we need CommandHandlers
. Let's start by adding a simple one that will create an instance of our Todo
Aggregate.
todoContext.addCommandHandler('CreateTodo', function(params) {
this.$aggregate.create('Todo')
.then(function (todo) {
return todo.$save();
});
});
Hint:
this.$aggregate
is dependency injected
It would be nice if we could change the description of the Todo
, so let's add this CommandHandler
too.
todoContext.addCommandHandler('ChangeTodoDescription', function(params) {
this.$aggregate.load('Todo', params.id)
.then(function (todo) {
todo.changeDescription(params.description);
return todo.$save();
});
});
And last but not least we want to console.log when the description of the Todo
changes.
todoContext.subscribeToDomainEvent('TodoDescriptionChanged', function(domainEvent) {
console.log(domainEvent.payload.description);
});
Initialize the Context, create a Todo
and tell the Todo
to change its description.
todoContext.initialize()
.then(function() {
todoContext.command('CreateTodo');
})
.then(function(todoId) {
todoContext.command('ChangeTodoDescription', {
id: todoId,
description: 'Do something'
});
});
After executing the Commands the DomainEventHandler will print Do something
. Your Todo
Aggregate is now persisted using EventSourcing into the InMemory Store
.
To execute all (client+server) tests, use:
gulp spec
You can watch for file-changes with
gulp watch
gulp bump:patch
git add .
git commit -m"$VERSION"
git push
npm publish
git checkout -b release master
gulp dist
git add .
git commit -m"$VERSION"
git tag $VERSION
git push --tags
git checkout master
git branch -D release
MIT
Copyright (c) 2013-2014 SixSteps Team, eFa GmbH