Think Before Coding

To content | To menu | To search

Tag - Event Sourcing

Entries feed - Comments feed

Friday, April 11, 2014

Monoidal Event Sourcing

I Could not sleep… 3am and this idea…

 

Event sourcing is about fold but there is no monoid around !

 

What’s a monoid ?

 

First, for those that didn’t had a chance to see Cyrille Martaire’s  fabulous explanation with beer glasses, or read the great series of post on F# for fun and profit, here is a quick recap:

 

We need a set.

Let’s take a simple one, positive integers.

 

And an operation, let say + which takes two positive integers.

 

It returns… a positive integer. The operation is said to be closed on the set.

 

Something interesting is that 3 + 8 + 2 = 13 = (3 + 8) + 2 = 3 + (8 + 2).

This is associativity: (x + y) + z = x + (y + z)

 

Le last interesting thing is 0, the neutral element:

x + 0 = 0 + x = x

 

(N,+,0) is a monoid.

 

Let say it again:

(S, *, ø) is a monoid if

  • * is closed on S  (* : S –> S > S)
  • * is associative ( (x * y) * z = x * (y * z) )
  • ø is the neutral element of * ( x * ø = ø * x = x )

warning: it doesn’t need to be commutative so x * y can be different from y * x !

 

Some famous monoids:

(int, +, 0)

(int, *, 1)

(lists, concat, empty list)

(strings, concat, empty string)

 

The link with Event Sourcing

 

Event sourcing is based on an application function apply : State –> Event –> State, which returns the new state based on previous state and an event.

 

Current state is then:

fold apply emptyState events

 

(for those using C# Linq, fold is the same as .Aggregate)

 

Which is great because higher level functions and all…

 

But fold is event more powerful with monoids ! For integers, fold is called sum, and the cool thing is that it’s associative !

 

With a monoid you can fold subsets, then combine them together after (still in the right order). This is what give the full power of map reduce: move code to the data. Combine in place, then combine results. As long as you have monoids, it works.

 

But apply will not be part of a monoid. It’s not closed on a set.

 

To make it closed on a set it should have the following signature:

 

apply: State –> State –> State, so we should maybe rename the function combine.

 

Let’s dream

 

Let’s imagine we have a combine operation closed on State.

 

Now, event sourcing goes from:

 

decide: Command –> State –> Event list

apply: State –> Event –> State

 

to:

decide: Command –> State –> Event list

convert: Event –> State

combine: State –> State –> State

 

the previous apply function is then just:

apply state event = combine state (convert event)

 

and fold distribution gives:

 

fold apply emptyState events = fold combine emptyState (map convert events) 

 

(where map applies the convert fonction to each item of the events list, as does .Select in Linq)

 

The great advantage here is that we map then fold which is another name for reduce !

 

Application of events can be done in parallel by chuncks and then combined !

 

Is it just a dream ?

 

Surely not.

 

Most of the tricky decisions have been taken in the decide function which didn’t change. The apply function usually just set state members to values present in the event, or increment/decrement values, or add items to a list… No business decision is taken in the apply function, and most of the primitive types in state members are already monoids under there usual operations…

 

And a group (tuple, list..) of monoid is also a monoid under a simple composition:

if (N1,*,n1) and (N2,¤,n2) are monoids then N1 * N2 is a monoid with an operator <*> ( (x1,x2) <*> (y1,y2) = (x1*y1, x2¤y2)) and a neutral element (n1,n2)…

 

To view it more easily, the convert fonction converts an event to a Delta, a difference of the State.

 

Those delta can then be aggregated/folded to make a bigger delta.

It can then be applied to a initial value to get the result !

 

 

The idea seams quite interesting and I never read anything about this.. If anyone knows prior study of the subject, I’m interested.

 

Next time we’ll see how to make monoids for some common patterns we can find in the apply function, to use them in the convert function.

Monday, July 29, 2013

Command Events and Context

A remark by @serialseb after my previous post :

 

First, here is some the distinction between a Command and an Event.

A command express what you want to do. Usually expressed with a verb in the present tense:
WithdrawMoney

A event express what actually happened. Usually expressed with a verb in the past tense;
MoneyWithdrawn

As you can anticipate, what you request is not always what actually happens:
WithdrawMoney($100000000)

A Command is still an Event ?

Let’s go a bit meta.

The fact that you decide you want to do something is something that happens in time. So it can also be considered as an event !

True… but what’s the usefulness of this ?

Someone who would like to study the correlation between your desires and their realizations will model both as events..

This can be the same in a tracking context. Track both causes and effects..

Should we just ignore the distinction then ?

Surely not !

It’s here again a matter of context. Of Bounded Context.

Let’s take a sample with different kind of concepts, Value Object and Entities, to highlight how the same thing can take different modeling forms in different contexts:

Money is usually modeled as a Value Object, which implies equality by Value. I give you $10 you give me $10, we’re even, even if I give you a bill and you give me some coins.

In the context of fraud tracking, this can be very different. Bills have a tracking number, and you can model it as entity.

If you make both context work together you’ll go through an Anti Corruption Layer for context mapping. You’ll not model all your accounting with entities for money because some other context models it this way !

In the case of Command and Events, some contexts can be interested in the fact that a decision was made, so this will be modeled as an event. But in the context where this decision happens, the decision is different from the actual outcome, and not being clear about this difference can lead to several issues..

For example if you model a withdrawal with  a Withdrawal concept: It is not clear whether it represe,ts the fact that you asked it to happen or the fact that is has actually been done.

Being explicit on it with WithdrawMoney / MoneyWithdrawn removes the ambiguity.

In the context of event sourcing, this distinction is very important as the previous article showed. As is the distinction between upstream events and internal events, since upstream events is input and will only produce things you’d like to happen, so are closer to commands from the system point of view.

Of course if your context is not about time and decision, don’t use these concepts that would be useless. You’re writing a compiler ? Forget about all this.

Should I have Command DTOs ?

not necessarily, a command can be modeled as a function/method call. So creating Command object is not mandatory.

It can still be useful for dispatch, storage for diagnostics, functional test etc.

Sunday, July 28, 2013

Event Sourcing vs Command Sourcing

Last month, I made a presentation about Event Sourcing - a shorter version of my DevoxxFr talk. After me, Etienne and Maher from Sfeir, did a presentation on the same subject and their architecture inspired by LMAX.

I immediately noticed their reference to this Event Sourcing page by Martin Fowler, and started to see several point of pain lurking in their long term maintenance…

I won’t make a flaming post against Martin Fowler that has written lots of interesting stuff. Even this article says nothing wrong. It just takes a way that can cause long term pains as expressed in the page itself…

Sourcing Events, but which Events ?

The article starts with a totally valid definition of Event Sourcing:

Capture all changes to an application state as a sequence of events.

The question then is… where do these events come from ?

In this case when the service is called, it finds the relevant ship and updates its location. The ship objects record the current known state of the ships.
Introducing Event Sourcing adds a step to this process. Now the service creates an event object to record the change and processes it to update the ship.

A C# sample a bit further to make it clearer:

class EventProcessor...
IList log = new ArrayList();
public void Process(DomainEvent e) {
e.Process();
log.Add(e);
}

As you can notice, the Event is produced before reaching the event processor…

Constrast this with the following version:

class Cargo
{
IList log = new List();
private State currentState;
public Cargo(IEnumberable events)
{
foreach(var @event in events)
Apply((dynamic) @event);
}
public void Arrive(Port port)
{
// logic to verify the action can be done
// based on current state and command parameters
if (IsAlreadyInPort) throw Exception();
// create an event of what happened with this action
// it should not mutate state,
// but it can capture external state when it arrives
// it's also based on current state and command parameters
var @event = new ShipArrived(id, port, DateTime.Now)
// apply change du to the event
// it should require only current state and
Apply(@event);
log.Add(@event);
// events will be published to the rest of the system
// from there.. This is where further side effect will
// occure
}
private void Apply(ShipArrived @event)
{
// no decision should happen here !
currentState.Port = @event.Port;
currentstate.LastMove = @event.Time;
}
}

From a functional point of view this pattern can be build from two pure functions:

Decide:
Command -> State -> Event list
ApplyStateChange:
State -> Event -> State

Here, stored event has been produced by the aggregate itself ! The output is stored.

Nice, but why should I care ?

After all, since Martin says the first version is ok… let’s go !

This would be without noticing several warnings in the rest of the article.

External Systems

from the same page:

One of the tricky elements to Event Sourcing is how to deal with external systems that don't follow this approach (and most don't). You get problems when you are sending modifier messages to external systems and when you are receiving queries from other systems.

Many of the advantages of Event Sourcing stem from the ability to replay events at will, but if these events cause update messages to be sent to external systems, then things will go wrong because those external systems don't know the difference between real processing and replays.

The second version doesn’t suffer this problem…

Because rebuilding the state (like done in the constructor) only use the Apply method (or the ApplyStateChange function in the functional version)..

This Apply method only works with internal state and produces no external side effects..

External Queries

Another problem arising with Martin Fowler’s proposal:

The primary problem with external queries is that the data that they return has an effect on the results on handling an event. If I ask for an exchange rate on December 5th and replay that event on December 20th, I will need the exchange rate on Dec 5 not the later one.

Here again, the second version doesn’t suffer the problem..

The data from the external system will be used to build the event. It can be directly stored in it (like the current time in the sample), but can also be used in a computation. For instance, command contains prices in USD, query an current rate from USD to EUR, compute a price in EUR and put it in the event.
The rate at the time of the computation is baked in the event ! No need to remember the rate value afterward, especially no need to complex external system gateway.

It could still be better for debugging purpose to put the used rate explicitly in the event.

But the second version intrinsically handles this issue gracefully…

External Interactions

Both queries and updates to external systems cause a lot of complication with Event Sourcing. You get the worst of both with interactions that involve both. Such an interaction might be a an external call that both returns a result (a query) but also causes a state change to the external system, such as submitting an order for delivery that return delivery information on that order. 

Problem solved by version 2….

Code Changes

So this discussion has made the assumption that the application processing the events stays the same. Clearly that's not going to be the case. Events handle changes to data, what about changes to code?
[…]
The third case is where the logic itself changes over time, a rule along the lines of "charge $10 before November 18 and $15 afterwords". This kind of stuff needs to actually go into the domain model itself. The domain model should be able to run events at any time with the correct rules for the event processing. You can do this with conditional logic, but this will get messy if you have much temporal logic. The better route is to hook strategy objects into a Temporal Property: something like chargingRules.get(aDate).process(anEvent). Take a look at Agreement Dispatcher for this kind of style.

Wooo… when I read this, it’s a red flag for me ! I never want to deal with this kind of problems !

Especially if they’re expected to happen for sure !

How does it go with the second version ?

Events are produced by the code that contains the logic. Before November 18, the events emitted where based on code that charge $10. After, the code charges $15.

When using the Apply method, it doesn’t have to know how much to charge, it’s already in saved events !

There is no need to keep an history of versions of domain logic - except in your source control !

It can even cop with changes far more complex that the one in this sample. In any case, all data needed to compute current state has been put in the event.

Correcting logic bugs

One of the advantages advanced by Martin Fowler, is that you can change how you take the decision after the fact.

But if an event is an event, it already happened, and there’s no way we can go back in time to change it. We wont be able to change external side effects anyway, so just accept it.

It’s still possible to apply compensations… like accountants. When they charged you to much, they don’t use a time machine to make has if nothing happened.. the just add a chargeback entry at the end of the ledger.

Command Sourcing ?

I call the pattern proposed by Martin Fowler Command Sourcing.

A Command is a request made to the system to do something. At this point a lot of thing can still happen. It can fail, it can be influenced by external state..

An event is something that happen and that cannot be changed.

You can protest that an Arrival Event is an event, not a command.

Sure, but for the system it’s an upstream event. Not something that happened in the system.

Where’s the difference in the second verions ?

The upstream version will go to a reactor that will produce an Arrive command (notice the present tense) inside the system.
The system will then produce a ShipArrived event (notice the passed tense). This event has been emitted by the system itself.

The Martin Fowler’s version takes a shortcut: bypassing the reactor emitting a command, but it is equivalent to sourcing commands.

Martin, this is a call to action !

Since a lot of people have read, and will read the entry on your web site, can you add something about the pattern described here to reduce the pain of people that will want to start with Event Sourcing ?

Tuesday, June 21, 2011

Event Sourcing and CQRS, Dispatch options 2

In the part one comments, Clement suggested a more efficient solution than registering handler in constructor.

 

The proposed solution is to have a RegisterAllEvents virtual method in which event handler registration would occur. This method is a method instance to have access to this but will be called only once per class. The registration use Expression<Action<T>> to access the expression tree and extract the method info of the handler. This enables type checking, make R# happy – no unused methods – and make reflection not too painful.

 

Good solution.

 

I didn't go that far because with Event Sourcing, you usually keep aggregates in memory, so aggregates are instantiated once per service lifetime.
I just crafted a small performance test :

 

 


using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace AggregatePerfTest
{
class Program
{
static void Main(string[] args)
{
var watch = new Stopwatch();

const int count = 10000000;
Guid id = Guid.NewGuid();

watch.Start();
for (int i = 0; i < count; i++)
new AggregateRegisteredOncePerInstance(id);

watch.Stop();

Console.WriteLine(watch.Elapsed.TotalMilliseconds);

watch.Reset();
watch.Start();

for (int i = 0; i < count; i++)
new AggregateRegisteredOncePerClass(id);

watch.Stop();

Console.WriteLine(watch.Elapsed.TotalMilliseconds);

}
}

public class AggregateRegisteredOncePerClass
{
private readonly Guid id;

private static readonly object ClassInitLock = new object();
private static bool initialized;


public AggregateRegisteredOncePerClass(Guid id)
{
this.id = id;

lock (ClassInitLock)
{
if (!initialized)
{
initialized = true;
// registration happens only once here
}
}
}

public Guid Id
{
get { return id; }
}
}

public class AggregateRegisteredOncePerInstance
{
private readonly Guid id;
private readonly Dictionary<Type, dynamic> handlers =
new Dictionary<Type, dynamic>(5);
public AggregateRegisteredOncePerInstance(Guid id)
{
this.id = id;
Register<int>(OnSomethingHappened);
Register<double>(OnSomethingHappened);
Register<float>(OnSomethingHappened);
Register<long>(OnSomethingHappened);
}

public Guid Id
{
get { return id; }
}

public void DoSomething()
{
Apply(1);
}

private void OnSomethingHappened(int message) { }
private void OnSomethingHappened(double message){ }
private void OnSomethingHappened(float message) { }
private void OnSomethingHappened(long message) { }

protected void Apply<T>(T @event)
{
handlers[typeof (T)](@event);
}

protected void Register<T>(Action<T> handler)
{
handlers.Add(typeof(T), handler);
}
}
}

The code is straight forward, I just created two aggregate classes :

  • one with registration in .ctor based on this post code
  • one without any registration at all, considering that doing it once is the same as not doing it for large numbers, but I added a lock section with a boolean check to simulate what will done on each instance creation.

I created 10.000.000 instances for each, and you get:

  • 3978ms for the one with .ctor registrations,
  • 377 ms for the one without.

It's true that it makes a difference. But how many aggregates do you have in your system ?

 

With 10.000 aggregate you're still under 8ms. I think you can afford that.

 

This is then a trade-off between performance and simplicity :

  • If you have very large numbers, go for expression tree parsing, class lock management etc.
  • In any other situation I recommend using registration in .ctor that makes the code easy to implement in approximately 5min.

Thursday, June 9, 2011

Time

556656621_ba9e8c870f[1]

How do we usually manage time in applications ?

Timers, threads, concurrency locks…

If we want to practice Domain Driven Design, we’re surely at the wrong level of abstraction.

 

What is time, btw ?

Tricky question. We know what time is, but… giving a definition is not that easy.

What defines time ? The second ?

Not really. It is used as a measure of time, but it doesn’t seem sufficient.

 

Let’s have a look at Wikipedia’s definition of time  :

Time is a part of the measuring system used to sequence events, to compare the durations of events and the intervals between them, and to quantify rates of change such as the motions of objects. […]

Now we have something interesting : Time is what happens between events.

But what is this thing between events.

The definition of the measure unit surely can give us further insight.

Lest have a look at Wikipedia’s definition of the second :

[…] Since 1967, the second has been defined to be

the duration of 9,192,631,770 periods of the radiation corresponding to the transition between the two hyperfine levels of the ground state of the caesium-133 atom.

The second is defined as a count of transitions between states of an atom of cesium.

We measure time by considering that the ~time~ between those state transitions is constant.

What if it’s not ?

It’s not that important if other events seem synchronized with those events. Will come back to this later.

 

Events

Let’s step back a bit.

 

How do you feel time passing ?

By looking at your watch ?

 

Maybe, but how could you explain that an hour sometimes seems so long, and sometimes passes in a flash ?

 

Time seems slow and empty when you’re bored.

Times seems fast and full when you’re busy with interesting things.

When you’re bored, it’s because few interesting things happen.

 

You can deduce from this that your personal state transitions are those interesting things that happen.

These are meaningful events. Things that happens and change you deeply.

 

Of course a lot of things happen between those meaningful events, you’re moving, thinking. Your blood flows through your body, but it is just maintenance move. You don’t change deeply.

Maybe some things happen between state transition of a cesium atom, but since we cannot notice it and give it a meaning for now, it has no influence.

 

But when when a meaningful event happens, you change. You’re not the same before and after.

This is what time is about, and this is why it’s one way.

Before –> Event –> After

Events define time by causality

This perception of meaningful events is surely a reason why people say the time pass faster when old. In your 6 first years any event around you is meaningful. Any event make you change since you have no previous knowledge. Then has time goes by, you integrate knowledge and filter things you already know, you’ve already seen. When old, a year can more easily seem the same than the year before.

But some people continue to enjoy and learn as much as they can to still have a long now.

 

When do your system change ?

Your system never change for no reason.

It’s always because a meaningful event happened.

This event can be a user interaction, a call from an external system, a sensor trigger…

And when things change because it’s midnight ?

It simply means that midnight is a meaningful event in your system.

 

Where are those meaningful events in your code ? Hidden in infrastructure code ?

 

I hear Greg Young say :

Make the implicit explicit !

And it’s simple :

Use Domain Events.

 

Once you’ve introduced Domain Events in your domain model, you have made Events and so Time explicit in your domain.

There is no change in the domain that is not due to an Event.

The events appear everywhere in the Ubiquitous Language :

  • When the client HasMoved to a new location, send him a welcome kit.
  • When a RoomHasBeenOverbooked try to relocate the customer
  • Every day at midnight = MidnightOccured, change last minute prices.

I’m sure you can find examples in your own domain. If your domain is business related, it has to deal with time because business is about time and money.

 

Time is now part of your Ubiquitous language and you have an implementation for it.

And that’s huge.

Tuesday, October 19, 2010

Duck : Delete Update Create Killer

Duck sign, Stockbridge High StreetI recently had a remark from Frederic Fadel from Aspectize, telling me about Event Sourcing something like:

Why would you like to write SQL to write data to your read model when our product can do it for you ?

I acknowledge that their product is fancy. You simply declare your db data schema, your UI and services and bind it all together.

But it doesn’t fit well with CQRS and Event Sourcing. And I want to do Event Sourcing for domain and business reasons, not technical reasons.

But he was write on this point :

I don’t want to write SQL to denormalize my events to my queryable storage.

What are my options ?

  • Writing SQL by hand, but testability is low, and you’ll get a mix of C# to get data from the events, and SQL for the Update queries.
  • Using an ORM. When doing NHibernate you don’t really write SQL. Testability wont be great anyway.

The problem with ORMs

ORM are usually better at getting data than at changing it. You can do it, but let’s look at what happens.

The ORM loads data from your Db into entities that will be tracked by an identity tracker. Then you change the values in memory . Then the ORM will find what needs to be sent back to the server and make a query to the Db so that the change happens.

But what I need to do is a lot simpler. Just emit some INSERT, UPDATE or DELETE based on current table values and event data.

With an ORM, what happens if the data is changed between loading and saving ? I’ll have to manage some versioning and/or transaction. And I’ll make two roundtrips to the server needlessly.

Here comes Duck

Duck is a kind of ORM oriented toward Delete Update Create.

Don’t ask Duck to load data in memory, it simply can’t.

You simply express how data should change based on current row content and values that you’ll pass.

It avoids the first roundtrip to the database, and make shorter code to express the change.

Let’s see how to use it

First, you should declare a class that has the structure of your table with public get/set properties, and marked with a Table attribute :

     [Table]
class Species
{
public Guid Id { get; set; }
public string Name { get; set; }
public string BinomialName { get; set; }
public bool IsEndangered { get; set; }
public int Population { get; set; }
}

It contains current observed species at an observatory.

Then a simple new statement, let’s say that a new species has be registered at the observatory :

     var duck = new DuckContext'(connectionString);
var speciesId = Guid.NewGuid();
duck.In<Species>()
.Insert(() =>
new Species
{
Id = speciesId,
Name = "Mallard",
BinomialName = "Anas platyrhynchos",
IsEndangered = false,
Population = 50
});

Nothing tricky here..

The observatory noticed a population decay, the species is endangered :

     duck.In<Species>()
.Where(r => r.Id == speciesId)
.Update(r => new Species {
Population = r.Population - 40,
IsEndangered = true});

Here, the use of the current value of Population will not load current value. It will the following statement :

UPDATE Species
SET
    Population = Population - 40,
    IsEndangered = 1
WHERE
    Id = @p0

I chose  to create a new Row from the old one rather than change the original one for two reasons :

  • It makes rows immutable and you don’t have to think about execution order between fields assignments. It’s the way SQL works
  • Linq Expressions cannot represent statement blocks and assignments in C#3, Duck would have been .Net only…

The –40 is directly in the query here because we used a constant. I we where using a variable, query would contain a parameter

Now the species has disappeared, it should be removed from the observed species (though it could be just an update somewhere else) :

     duck.In<Species>()
.Where(r => r.Id == speciesId)
.Delete();

Testability

To run your test you just have to use the InMemoryDuckContext… you have then access to Table<T>() that’ll enable you to set up your data and verify after execution that things changed as expected. I’ll talk a bit more about it soon.

Try it now, it’s OSS

You can grab the code at bitbucket and try it now :

http://bitbucket.org/thinkbeforecoding/duck

It’s in F# ! Writing a AST analyzer in F# is far more easy, concise and expressive than in C#. You’ll just have to reference Duck in you project, there’s no direct F# dependency.

Next episode will be about how to mix it with Rx (Reactive Framework) to declare your event handling logic.

Hope you like it, and don’t hesitate to give feedback and suggestions.

Monday, June 14, 2010

DDD Exchange 2010

I could not attend to this year’s edition that seemed really great with Eric Evans, Greg Young, Udi Dahan, Ian Cooper and Gojko Adzic.

The videos from the events should be soon somewhere around here.

And you can already find transcripts of the talks on Gojko ‘I post faster than people talk’s blog :

Eric Evans: Domain driven design redefined

Udi Dahan: the biggest mistakes teams make when applying DDD

Greg Young :Evolution of DDD: CQRS and Event Sourcing

 

If you also missed it, don’t make the same mistake next year, and register now for £50.00 (instead of £250.00) until the end of the week.

Sunday, April 25, 2010

Event Sourcing and CQRS, Events Deserialization

So we have our events serialized in our event store. Deserializing events is not an issue, until we start to make them evolve and need to manage several versions.

Since we never modify what has been log, we’ll have to deal with old versions anyway.

A simple way to do it is to maintain every versions of the events in the projects, and make the aggregate root accept all of them. But it will soon charge the aggregate root with a lot of code and will make it bloated rapidly.

This is why you can usually introduce a converter that will convert any version of the event to the last one (usually you provide methods to update to next version, and iterate until last version so that this part of the code is incremental). This is a convenient way to address the problem, but you still have classes v1, v2 … vn that you keep in your project only for versioning purpose even if you don’t use it anymore in your production code.

Events as documents

519485340_1a83117720_o[1]It is easy do deserialize an event as an object or a document, you only need to split two responsibilities in you deserialization process :

  • Stream reading
  • Object building

The deserializer will be in charge of reading the data, it reads the bits, and get the meaning from context, it will tell the Object Builder about objects types, fields names and value.

On its side, the ob ject builder will instantiate the objects, set fields values depending on names.

You can provides two distinct Object Builders. The strongly typed one will instantiate concrete .net types and set fields using reflection. The document builder one, will instantiate objects that will only be property bags.

When deserializing an event in its last version, you can use directly the strongly typed one, but when reading an previous version of the event, you can deserialize it as a document and give it to the converter.

The converter will then add/remove properties from the document to make it up to date, and the document will be used to create a concrete .net type of the last event version.

Here the process is quite the same, you should provide a document reader that will use the strongly typed object builder to instantiate the event.

There’s no need to keep every version of you Event Classes now since you can manipulate old versions as documents.

Using dynamic in C#4

Document manipulation can make things a bit messy since it can be hard to understand the original structure of the object. This is where you can use the DLR DynamicObject class to make the property bag (the document) a dynamic object that you’ll be able to use as any standard .net object.

This way, in the converter you can manipulate old versions of the events as .net objects without having to keep all those old classes that won’t be used anymore.

Saturday, April 17, 2010

Event Sourcing and CQRS, Bounded Contexts

Once again, I prefer a new post that a long comment reply. This one is about a important concept of Domain Driven Design, Bounded Contexts.

Hendry Luk asked :

Just 1 question, you represent borrower in events as a simple full-name string.
Is there any reason or just for sake of simplicity for example?
Supposed I'm using borrowerId, how would that work in other BC, say
LateBookNotifier (let's assume its a separate BC). How does this BC shows the
name of the borrower? Does it communicate directly with command BC using ACL?
Or does it also subscribe to BorrowerRegistered event as well (hence every BC
would have duplicate data of each of the borrowers, just like they do each of
the books)?

The short answer is ‘Yes, it was just for sake of simplicity’. In a real world scenario, borrowers would probably be entities, and thus would have an identity. I would even probably be an Aggregate Root.

The Borrower Aggregate Root would encapsulate state needed to perform commands on this Aggregate.

Bounded Contexts CommunicationsBooks

I can see the following contexts here :

  • Inventory : Manage books availability and state (the book has been damaged, there a notes written on it etc..)
  • Relationships : Manage contact by email, phone with borrowers, and tracks the care they take to your books, if they return it on schedule.

Since we are using CQRS (and even more, Event Sourcing), aggregates in these context don’t need more state that what’s needed to take decisions,

So a Book in the Inventory Context will probably not need more that the Id of the borrower and the date a witch it was borrowed.
We can then call the ReturnToShelf command on the Book that will publish a ReturnedLateToShelf { Book : bookId, By : borrowerId, After : 20 days, LateBy : 6 days  }.

A Handler at the Relationships Boundary will catch the event, and call a CheckExcuseForLateReturn on the Borrower Aggregate Root (based on its id). The command will check the borrower’ss record to see if its acceptable. It will simply publish a LateReturnGentlyAccepted if the borrower is usually in time, but will publish a KindnessLimitReached in the other case.

Another handler will catch it, and call SendAngryMessage on the Messaging Service. The role of the Messaging Service is to tweet borrowers to let them know they should not forget to return your books. How does this service know the twitter account of the borrower ? When the handler (the one that call SendAngryMessage) catches a BorrowerRegistered event or a BorrowerTwitterAccountChanged message, it says so to the service that can maintain a list of accounts in any desired storage (SLQ, NoSql, in memory.. ?). The SendAngryMessage can now tweet ‘Hey you filthy @borrower, you better return my book today or I shall share all the pics from your last party…’

Done.

Where does data live ?

There’s usually a huge concern about data duplication in all contexts. Is the info duplicated in so many places ?

There will be two main places :

  • The Persistent View Model used to see and edit borrower’s details
  • The Persistent View Model used by the messaging service to Query borrower’s twitter accounts. Here, no other borrower’s data is needed except its id and account name.

The Borrower Aggregate Root and Book Aggregate Root in the two main Domain Bounded Contexts will not need to keep track of this kind of data. They won’t need it in their decision process.

If you pursue this idea, to answer further to Leonardo, you’ll notice that strings will probably never been used as state inside Domain Bounded Context. They can appear as identity key, or just pass through a command and be republished in the following event. But since strings are rarely – if never – a good way to represent information on which you’ll have to take a decision, it should almost never be stored in an aggregate root current state. This is another reason why most domain models can fit in memory, because names, descriptions and other documents usually represent the biggest part of the data in a system, the remaining data is usually small. These documents and names are useless to run domain  internal logic (except validation rules, but not state change rules) so they can simply be logged in events and persisted in the Query’s View Models. Only state needed to take state change decisions will stay in memory.