seeing the light about abstractions

What a fantastic post this is: Limit your abstractions: And how do you handle testing?

I’m big enough to hold my hands up and say that I have often fallen foul of the needless abstraction.
To some extent, I did realise this when redesigning my site to work with fubuMVC –previously I had encapsulated logic in something I called controller messaging for some time (and had planned to blog about but never got around to it).

The original version was in an ASP.NET MVC controller and was used in a similar vein to domain events:

    public class ReportController : AuthorisedController
    {
        public ActionResult Create(int id)
        {
            var reportTreeData = ControllerMessage.Initiate<NewReportToBeCreated, ReportTreeData>
                (new NewReportToBeCreated() {ReportTemplateId = 1, PupilId = id});

            return View(reportTreeData);
        }
    }

When I came to do my fubuMVC implementation I thought there was a code smell about having almost exactly the same construct as domain events, but for controllers to hook into domain logic.
So instead I wanted it baked into the actions on fubuMVC - the actions/controllers in my fubuMVC application derive from a base that has an invoker:

    public class ControllerThatCanInvoke
    {
        public static ControllerMessageInvoker Invoker { get; set; }

        protected TResult Invoke<T, TResult>(T item)
        {
            return Invoker.Invoke<T, TResult>(item);
        }
    }

It has a static invoker that is set up at the bootstrapping stage and the invoke call is delegated to the invoker.

The invoker comes from the IOC container and this is injected with handlers:

    public class ControllerMessageInvoker
    {
        readonly IEnumerable<IHandle> _handlers;

        public ControllerMessageInvoker(IEnumerable<IHandle> handlers)
        {
            _handlers = handlers;
        }

        public TResult Invoke<T, TResult>(T item)
        {
            return _handlers.OfType<IHandle<T, TResult>>().Single().Handle(item);
        }
    }

With the handler interfaces:

    public interface IHandle<T, TResult> : IHandle
    {
        TResult Handle<T>(T item);
    }

    public interface IHandle { }

So this enables me to invoke straight from my controller :

    public class ReportController : ControllerThatCanInvoke
    {
        public CreateReportViewModel Create(CreateReportInput input)
        {
            var reportTreeData =
                Invoke<NewReportToBeCreated, ReportTreeData>(new NewReportToBeCreated
                                                                 {
                                                                     ABC = input.MMM,
                                                                     XYZ = input.Id
                                                                 });

            return new CreateReportViewModel(reportTreeData);
        }
    }

This allows me to test that the controller initiates the invocation and with the right inputs on a POCO class and I can test the handler independently.
What that obviously means is I need a handler that answers to the invocation:

    public class NewReportToBeCreatedHandler : IHandle<NewReportToBeCreated, ReportTreeData>
    {
        public ReportTreeData Handle<T>(T item)
        {
            DoSomething();
            return xxxx;
        }
    }

This works well, I have separation of concerns, this handler comes from the IOC container and can have session and other dependencies injected, and I've been rolling along very happy with myself until I read the blog post I referred to.

It poses a question: Do I really need this IHandler<T,TResult> abstraction?

The only friction I have at the moment is that I need two POCO classes and a handler class for every action that requires this invocation style. It ends up being a lot of classes.
I’ve managed it so far with some good folder and namespace arrangement, but I now see the light:

I do not need this abstraction and its trappings at all.

It is a concept I carried over from an ASP.NET MVC implementation and I just don’t need it.
So I’m in the process of reworking / stealing the ideas from Oren’s post and I’ll put up how I’ve reconsidered this for fubuMVC in my next post.



0 comments: