Act like a pessimist and call CanHandle from Handle (again)?

You have multiple Worker classes that can each handle a one or more types of command. Your IWorker interface offers two methods: CanHandle and Handle.

    interface IWorker
    {
        public Boolean CanHandle(IWork work);
        public void Handle(IWork work);
    }

Perfect.

Anyone with work to be done can now find a worker that says “yay, I can handle this” and then pass off the work to that worker.

What if someone doesn’t call CanHandle first?

But what if someone offering work just throws work at the Handle method of any Worker they happen to know?

You could face all manner of exceptions when someone sends KitchenWork to a BathroomWorker. The BathroomWorker stands no chance treating KitchenWork as BathroomWork. Exceptions could be flying high and low, or worse, you could end up with a very clean instead of a cooked chicken.

Just try to figure that one out when you receive the bug report as you are about to go home…

Act like a pessimist and call CanHandle from Handle (again)?

The simplest solution is to call CanHandle from Handle and throw a very specific exception when that returns false.

    class BaseWorker : IWorker
    {
        public Boolean CanHandle(IWork work) { return false; }
        public void Handle(IWork work) 
        {
            if (!CanHandle(work))
                throw new CanHandleNotCheckedError("You should call CanHandle before calling Handle");

            // ... snip ...
        }
    }

The advantages are obvious. When someone blatantly ignores the CanHandleHandle pattern, you now get a very specific exception of the root cause and program execution wouldn’t even get into the territory where other exceptions would be caused.

And punish the good guys with double execution?

The disadvantage is that every polite client of your Workers is punished with double execution of the CanHandle method.

That’s not very nice.

And it can add up, especially if CanHandle is a bit more involved than just a type check or two.

So, should you act like a pessimist and call CanHandle from Handle again?

If you like to go home earlyish: Yes, but…

Do you like to go home earlyish?

Or do you like being the “hero” and spending hours on some hard to debug errors?

If you are like me and like to go home on time, then yes, you do want to call CanHandle from Handle again.

When you can’t enforce that everybody behaves as good guys, it’s the only way to guarantee that the actual “handling” code is protected from being given something it can’t handle.

… you don’t need to punish the good guys

You can still be nice to the good guys too.

The contract for Handle is violated when someone doesn’t call CanHandle first. Looking at it like that tells you that you could put the “extra” CanHandle call in an Assert statement.

In C# assert statements come in two flavors.

    Debug.Assert(CanHandle(work), "You should call CanHandle before calling Handle");

and

    Trace.Assert(CanHandle(work), "You should call CanHandle before calling Handle");

The difference is that Debug.Assert automatically gets thrown out for Release builds, while Trace.Assert stays in. So in this particular case you want to use the Debug.Assert version.

Using a Debug.Assert, the bad guys get slapped with an assertion failure when doing it wrong, while the good guys don’t incur the overhead in release builds.

Sounds like the best of both worlds…

That’s it. Enjoy!

Can you think of another alternative? Let me know in the comments below or by email.
My own alternative will be out in a couple of posts.



Leave a Reply

Your email address will not be published. Required fields are marked *

*

Show Buttons
Hide Buttons