Skip to content

Instantly share code, notes, and snippets.

@JefClaes
Created February 5, 2013 18:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save JefClaes/4716622 to your computer and use it in GitHub Desktop.
Save JefClaes/4716622 to your computer and use it in GitHub Desktop.
Naïve ES take 1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NaiveEventSourcing
{
class Program
{
static void Main(string[] args)
{
var travelerService = new TravelerService();
travelerService.Handle(new TakeItemCommand("Tootbrush"));
travelerService.Handle(new TakeItemCommand("Map"));
Console.ReadLine();
travelerService.Handle(new TakeItemCommand("CellphoneCharger"));
Console.ReadLine();
}
}
// Service handles commands, and translates them to events which will get applied to the AR
public class TravelerService : IHandle<TakeItemCommand>
{
// This should be an eventstore
// Events per AR
private static List<IEvent> _events = new List<IEvent>();
private void Record<TEvent>(TEvent @event) where TEvent : IEvent
{
_events.Add(@event);
}
// Apply event to the AR.
// Is it after applying that we get write to our read store(s)?
// What do we pass on to the eventhandlers then, the AR, and eventname?
private void Play()
{
var traveler = new Traveler();
foreach (var @event in _events)
{
dynamic ev = @event;
traveler.Apply(ev);
Console.WriteLine(string.Format("Played event " + @event));
}
Console.WriteLine(string.Format("Number of events: " + _events.Count));
}
// Translate, record, and play everything to get the AR in the correct state
public void Handle(TakeItemCommand command)
{
var @event = new TookItemEvent(command.ItemName);
Record(@event);
Play();
}
}
public interface IHandle<T> where T : ICommand
{
void Handle(T command);
}
public interface ICommand { }
public class TakeItemCommand : ICommand
{
public TakeItemCommand(string itemName)
{
ItemName = itemName;
}
public string ItemName { get; private set; }
}
public class Traveler
{
private List<TravelerItem> _items;
public Traveler()
{
_items = new List<TravelerItem>();
}
public void Apply(TookItemEvent @event)
{
_items.Add(new TravelerItem(@event.Name));
}
}
public class TravelerItem
{
public TravelerItem(string name)
{
Name = name;
}
public string Name { get; private set; }
}
public interface IEvent { }
public class TookItemEvent : IEvent
{
public TookItemEvent(string name)
{
Name = name;
}
public string Name { get; private set; }
public override string ToString()
{
return "Took " + Name;
}
}
}
@yreynhout
Copy link

Op die manier ga je wel wat ceremonie krijgen in services. Bovendien geef je ze een verantwoordelijkheid die ze mijnsziens niet nodig hebben (heel het apply gedoe). Dat is eigenlijk een interne verantwoordelijkheid van een "eventsource" (hetzij een aggregate in DDD parlance). Verplaats de code in de service naar de Traveler en maak die onzichtbaar voor de buiten wereld. Ik fork even ...

@yreynhout
Copy link

https://gist.github.com/yreynhout/4716699 - is een voorbeeld mbv Rx (via NuGet Rx Main installeren) dat mooi aangeeft hoe events uit de source kunnen vloeien. In de praktijk wil je natuurlijk wel wat meer controle over de source. Wat wel al duidelijk zou moeten zijn is dat je aan de buitenkant (service, object api call) je helemaal niks van dat ES gedoe ziet. Als dat wel zo zou zijn, dan vrees ik dat je heel de tijd met je neus op de technische feiten wordt gedrukt. Niet echt productief. Alternatief kan je ook opteren voor een "pull"-based implementatie: https://github.com/yreynhout/AggregateSource/blob/master/AggregateSource/AggregateRootEntity.cs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment