Limit your abstractionsApplication Events–event processing and RX

time to read 5 min | 875 words

In my last post, I mentioned that this is actually an event processing system, so we might as well use actual event processing and see what we can gain out of this. I chose to use RX (reactive extensions), which can turn a series of events into a linq statement. This is incredibly powerful, and has some interesting implications when you combine this with your architecture. In particular, let us see what we can get when we set out to replace this with RX based event processing style.

image_thumb3_thumb_thumb

We can get to something like this very easily:

public class CargoProcessor : EventsProcessor
{
    public CargoProcessor()
    {
        On<Cargo>(cargos =>
            from cargo in cargos
            where cargo.Delivery.Misdirected
            select MisdirectedCargo(cargo)
            );

        On<Cargo>(cargos =>
            from cargo in cargos
            where cargo.Delivery.UnloadedAtDestination
            select CaroArrived(cargo)
        );
    }

    private object CaroArrived(Cargo cargo)
    {
        // handle event
        return null;
    }

    private object MisdirectedCargo(Cargo cargo)
    {
        // handle event
        return null;
    }
}

We use RX to handle the linq processing over the events, and in EventsProcessor we have very little code, probably just:

    public class EventsProcessor
    {
        private readonly List<Func<IObservable<object>, IObservable<object>>>  actions = new List<Func<IObservable<object>, IObservable<object>>>();

        protected void On<T>(Func<IObservable<T>, IObservable<object>> action)
        {
            actions.Add(observable => action(observable.OfType<T>()));
        }

        public void Execute(IObservable<object> observable)
        {
            foreach (var action in actions)
            {
                action(observable).Subscribe();
            }
        }
    }

Elsewhere in the code we setup the actual Obsersable that we pass to all the EventsProcessors. The major advantages that we have with this style is that we have a natural syntax to do selection on the events that interest us, including fairly complex one. We still have easy time of creating new EventsProcessors if we want, but because the code for defining the selection is so compact, we can usually put related stuff together, which is going to be very helpful for making sure that the codebase is readable.

And, naturally, this method extends itself to handling events of multiple types in the same place. For example, if we want to also handle the HandlingEvent, we can do it in place, because it is very much related to the Cargo, it seems.

More posts in "Limit your abstractions" series:

  1. (22 Feb 2012) And how do you handle testing?
  2. (21 Feb 2012) The key is in the infrastructure…
  3. (20 Feb 2012) Refactoring toward reduced abstractions
  4. (16 Feb 2012) So what is the whole big deal about?
  5. (15 Feb 2012) All cookies looks the same to the cookie cutter
  6. (14 Feb 2012) Commands vs. Tasks, did you forget the workflow?
  7. (13 Feb 2012) You only get six to a dozen in the entire app
  8. (10 Feb 2012) Application Events–event processing and RX
  9. (09 Feb 2012) Application Events–Proposed Solution #2–Cohesion
  10. (07 Feb 2012) Application Events–Proposed Solution #1
  11. (06 Feb 2012) Application Events–what about change?
  12. (03 Feb 2012) Application Events–the wrong way
  13. (02 Feb 2012) Analyzing a DDD application