Skip to content

Instantly share code, notes, and snippets.

@ToJans
Created August 14, 2010 03:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ToJans/523900 to your computer and use it in GitHub Desktop.
Save ToJans/523900 to your computer and use it in GitHub Desktop.
Event Driven Development POC
This is a draft for a blog article...
Please let me know what you think about it : ToJans@twitter
Currently doing a major rewrite... so it might take some time until I post on the blog
Behavioral Event Driven Development proof of concept !!!!
Introduction
I think I found the perfect match between #BDD and #CQRS !!
I call it Behavioral Event Driven Development or BEDD !!
(Also I like the name BEDD, since I only spent a few hours in my
BED last night because I wanted to get a POC out in the open :D )
It is bringing the workflow of Test Driven Development to the level
of Behavior Driven Development without all the usual hassle.
If you want to know why you should use BDD instead of TDD,
I would like to refer you to this article:
http://www.corebvba.be/blog/post/The-advantage-of-using-BDD-over-TDD.aspx
(I am shooting myself in the foot by saying this, since I spent quite some
hours on building my BDD framework Aubergine -
http://www.github.com/tojans/aubergine, but hey,
a man's gotta do what a man's gotta do... )
How does it work ?
- I started by implementing the class Specs.Search first, i.e. my specs.
I tried to make this as simple as possible, so a domain expert would probably
understand it (if you explain how the linq part works).
**** [1.specs.cs]
- By defining the specs, I knew what kind of events I would need, so I started
implementing events next (quite straightforward)
**** [2.events.cs]
- Up next : define the model
**** [3.model.cs]
- Finally, define the services by registering event handlers in the custom service bus.
The custom service bus uses some kind of pseudo-monads which allows you to redefine
behavior in several ways...
**** [4.Implementation.cs]
What do you think
In my personal opinion this has been the easiest and most obvious way to do BDD for me
in a long time... It also makes your programming flow very straightforward, so you
really do not need to think on what to implement next, and how to do it... I think
this might definitely be a BIG step forward, but I would really appreciate your opinion...
Remark
This POC is working perfectly, but the pseudo-monad wrapper for the event handlers
still need some work (i.e. handle some events on the ui-thread only for example)....
using System;
using System.Linq;
using BEDD.Services.Impl;
using BEDD.Tools;
using EventDrivenDevelopment.Example.Model;
using EventDrivenDevelopment.Example.Viewmodels;
using NUnit.Framework;
namespace EventDrivenDevelopment.Example.Specs
{
[TestFixture]
public class LibSpecs : NUnitSpecRunner
{
public LibSpecs()
{
SubscribeHandlers(new Handlers.BookShelfHandler());
As_a("Book owner");
I_Want_To("Be able to query my books");
So_that_I("Can avoid buying the same twice");
Given(new Messages.Events.BookHasBeenAdded("Tom Janssens","BDD for dummies","BDD","Aubergine"));
Given(new Messages.Events.BookHasBeenAdded("Liesbeth Kint","Handling difficult hubbies"));
Given(new Messages.Events.BookHasBeenAdded("Quinten Janssens","My life as a toddler","Family","Kids","Son"));
Given(new Messages.Events.BookHasBeenAdded("Matisse Janssens","My life as a toddler","Family","Kids","Son"));
}
[Test]
public void Latest_books_should_return_a_result()
{
When(new Messages.Queries.GetRecentBooks());
Then<Messages.Events.ScreenUpdated>(x => x.Has<Booklist>(bl=>bl.Books.Any()));
}
[Test]
public void Search_for_available_term()
{
When(new Messages.Queries.SearchForTerm("Kids"));
Then<Messages.Events.ScreenUpdated>(x => x.Has<Booklist>(bl=>bl.Books.Count()==2));
Then<Messages.Events.ScreenUpdated>(x => x.Has<Booklist>(bl=>bl.Books.Any(y=>y.Author=="Quinten Janssens")));
}
[Test]
public void Search_for_missing_term()
{
When(new Messages.Queries.SearchForTerm("om"));
Then<Messages.Events.ScreenUpdated>(x => x.Has<Booklist>(bl=>!bl.Has<Book>()));
}
[Test]
public void Search_for_term_with_wildcard_star()
{
When(new Messages.Queries.SearchForTerm("*om"));
Then<Messages.Events.ScreenUpdated>(x => x.Has<Booklist>(bl=>bl.Books.Count()==1));
}
}
}
public class AddABook
{
public string Author {get;set;}
public string Title {get;set;}
public IEnumerable<string> Keywords {get;set;}
public AddABook() {}
public AddABook(string author,string title,params string[] keywords)
{
Title = title;
Author = author;
Keywords = keywords;
}
}
public class BookHasBeenAdded
{
string Author {get;set;}
string Title {get;set;}
IEnumerable<string> Keywords {get;set;}
public BookHasBeenAdded(string author,string title,params string[] keywords)
{
Title = title;
Author = author;
Keywords = keywords;
}
}
public class ScreenUpdated
{
public IEnumerable<object> Models {get;set;}
public ScreenUpdated() {}
public ScreenUpdated(params object[] Models)
{
this.Models = Models;
}
}
public class GetRecentBooks { }
public class SearchForTerm
{
public SearchForTerm() {}
public SearchForTerm(string term)
{
SearchTerm = term;
}
public string SearchTerm {get;set;}
}
public class Book
{
public Book()
{
}
public string Title {get;set;}
public string Author {get;set;}
public IEnumerable<string> KeyWords {get;set;}
}
public class BookShelf
{
public BookShelf()
{
Books = new Book[]{};
}
public IEnumerable<Book> Books {get;set;}
}
public class BookShelfHandler : IHandlerFor<BookShelf>,
IHandles<Messages.Commands.AddABook>,
IHandles<Messages.Queries.GetRecentBooks>,IHandles<Messages.Queries.SearchForTerm>,
IHandles<Messages.Events.BookHasBeenAdded>
{
public BookShelf Root {get;set;}
public IEnumerable HandleMessage(Messages.Commands.AddABook e)
{
yield return new Messages.Events.BookHasBeenAdded(e.Author,e.Title,e.Keywords.ToArray());
}
public IEnumerable HandleMessage(Messages.Events.BookHasBeenAdded e)
{
Root.Books = Root.Books.Concat(new Book[]{new Book()});
yield break;
}
public IEnumerable HandleMessage(Messages.Queries.GetRecentBooks e)
{
yield return new Messages.Events.ScreenUpdated(new Booklist(Root.Books.Reverse().Take(3).ToArray()));
}
public IEnumerable HandleMessage(Messages.Queries.SearchForTerm e)
{
var re = new Regex(@"\s"+Regex
.Escape(e.SearchTerm)
.Replace(Regex.Escape("*"),"(.*)")
.Replace(Regex.Escape("?"),".")
+@"\s",RegexOptions.IgnoreCase);
var matches = (from b in Root.Books
where re.Match(
" "+b.Author+
" "+string.Join(" ",b.KeyWords.ToArray())+
" " + b.Title+" ").Success
select b).ToArray();
yield return new Messages.Events.ScreenUpdated(new Booklist(matches));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment