Skip to content

Instantly share code, notes, and snippets.

@ToJans
Created September 21, 2010 15:36
Show Gist options
  • Save ToJans/589876 to your computer and use it in GitHub Desktop.
Save ToJans/589876 to your computer and use it in GitHub Desktop.
preview of refactoring for simplecqrs
Another preview of an update of my simpleCQRS stuff....
No idea where I'm going with this, but the important aspects to note are:
- Complete persistence ignorance in both domain objects and command handlers (loading & saving is handled by the message bus, and uses event sourcing underneath)
- Client side command validation should always happen without having the aggregate root available => RegisterValidator
- Untangle dependencies:
* Commmands and Events have no dependencies
* Commandhandlers have dependencies on commands & domain objects
* EventHandlers have dependencies on events
* Domain objects have dependencies on events
* instead of having a base class with an "ApplyEvent" method, I opt to let an event-/commandhandler return IEnumerable events/commands,
so no dependency to the bus/dybnamic proxy/other mumbo-jumbo is needed in the domain classes
When this all works out, an NDepend graph should show an untangled model of the domain & it's behavior...
As usual: send comments tojans@twitter
using System;
using System.Collections;
using SimpleCQRS2.Example.Domain;
using SimpleCQRS2.Example.Messages;
namespace SimpleCQRS2.Example.Handlers
{
public class CommandHandler
{
SomeReadModelUpdater sru;
public CommandHandler(SomeReadModelUpdater sru)
{
this.sru = sru;
RegisterHandler<Score,CreateScore >((ar,msg) => ar.CreateScore(msg.PlayerName));
RegisterHandler<Score,IncrementScore>((ar,msg) => ar.IncrementScore());
RegisterHandler<Score,DecrementScore>((ar,msg) => ar.DecrementScore());
RegisterValidator<DecrementScore>("A score of 0 can not be decremented",
msg => sru.MyScoreBoard.Items[msg.AggregateRootId].Value == 0);
}
protected void RegisterHandler<TAggregateRoot,TMessage>(Func<TAggregateRoot,TMessage,IEnumerable> handler)
{
// TODO
}
protected void RegisterValidator<TMessage>(string message,Predicate<TMessage> pred)
{
//TODO
}
}
}
using System;
using SimpleCQRS2.Framework;
namespace SimpleCQRS2.Example.Messages
{
public class CreateScore: Command
{
public string PlayerName;
public CreateScore(string playername)
{
PlayerName = playername;
}
}
public class IncrementScore : Command
{
}
public class DecrementScore : Command
{
}
public class DeleteScore : Command
{
}
}
using System;
using SimpleCQRS2.Framework;
namespace SimpleCQRS2.Example.Messages
{
public class ScoreCreated : Event
{
public string PlayerName;
public ScoreCreated(string playername)
{
PlayerName = playername;
}
}
public class ScoreDeleted : Event
{
}
public class ScoreChanged : Event
{
public int Value;
public ScoreChanged(int value)
{
Value = value;
}
}
}
using System;
using System.Collections;
using SimpleCQRS2.Example.Messages;
using SimpleCQRS2.Framework;
namespace SimpleCQRS2.Example.Domain
{
public class Score
: IAggregateRoot
, IMessageHandler<ScoreChanged>
{
int Value;
public Guid AggregateRootId { get; set; }
public IEnumerable CreateScore(string playername)
{
yield return new ScoreCreated(playername).For(this);
}
public IEnumerable IncrementScore()
{
yield return new ScoreChanged(Value+1).For(this);
}
public IEnumerable DecrementScore()
{
if (Value > 0)
{
yield return new ScoreChanged(Value -1).For(this);
}
yield break;
}
// implement interface explicit, so it is not exported unless casted to IMessageHandler
IEnumerable IMessageHandler<ScoreChanged>.Handle(ScoreChanged msg)
{
Value = msg.Value;
yield break;
}
}
}
using System;
using System.Collections;
using SimpleCQRS2.Example.Messages;
using SimpleCQRS2.Example.ViewModels;
namespace SimpleCQRS2.Example.Handlers
{
public class SomeReadModelUpdater
{
public ScoreBoard MyScoreBoard = new ScoreBoard();
public IEnumerable Handle(ScoreCreated evt )
{
MyScoreBoard.Items.Add(evt.AggregateRootId,new ScoreBoard.Item()
{
MyGuid = evt.AggregateRootId,
Value = 0,
PlayerName = evt.PlayerName
});
yield break;
}
public IEnumerable Handle(ScoreChanged evt)
{
MyScoreBoard.Items[evt.AggregateRootId].Value = evt.Value;
yield break;
}
public IEnumerable Handle(ScoreDeleted evt)
{
MyScoreBoard.Items.Remove(evt.AggregateRootId);
yield break;
}
}
}
using System;
using System.Collections.Generic;
namespace SimpleCQRS2.Example.ViewModels
{
public class ScoreBoard
{
public class Item
{
public string PlayerName;
public int Value;
public Guid MyGuid;
}
public readonly Dictionary<Guid, Item> Items = new Dictionary<Guid, Item>();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment