3

I've been tasked with refactoring a console application, which is constantly running on a server and receiving messages from a service bus.

Right now, it just parses the incoming message, and based on a property, will use a switch statement to call one of many different functions (about 70 at the moment, always growing). One problem is that if a function fails, it's not retried. Not to mention just the ugliness of one giant switch statement.

I'm leaning towards using the Command Pattern to rectify this (https://scottlilly.com/c-design-patterns-the-command-pattern/), but have also considered a pub/sub pattern to handle these functions.

Anybody know what the best architecture pattern might be for this situation?

Steven
  • 139

3 Answers3

4

Since you have tagged this question with C#, I'll offer the language-specific answer to your question. C# and the BCL offer a built-in version of the command pattern: a dictionary of delegates. Rather than have, for example:

SomeType Foo(MessageType message)
{
    switch (message.Id)
    {
        case "Id1" : return HandleId1();
        case "Id2" : return HandleId2();
        ...
    }
}

You replace it with

private readonly Dictionary<string, Func<SomeType>> _handlers =
    new Dictionary<string, Func<SomeType>>
    {
        ["Id1"] = HandleId1,
        ["Id2"] = HandleId2,
        ...
    };

...

SomeType Foo(MessageType message) => _handlers[message.Id]();
David Arno
  • 39,599
  • 9
  • 94
  • 129
1

Given that you are using a service bus already I would split the app into many apps and the message queue into a queue per type.

That way you your app handles only one type of message, enabling you to scale them separately and add new types without redeploying.

You can use the service bus error queues for retrying failed messages

Ewan
  • 83,178
1

The answer given by @David Arno is what I would do, with one difference. I would not use delegates, but would rather go with Command objects. So, you would have something like this:

Dictionary<string, ICommand> _handlers = new Dictionary<string, ICommand>();

where

public interface ICommand
{
    void Execute();
}

Then, you could implement a null object like this:

public NullCommand : ICommand
{
    public void Execute()
    {
    }
}

and your code would look like this:

ICommand GetCommand(string id)
{
    ICommand retVal = null;
    if (!_handlers.TryGet(id, out retVal))
    {
        retVal = new NullCommand();
    }
    return retVal;
}

This way, the ownership is clear and testability is greater.

Vladimir Stokic
  • 2,973
  • 17
  • 26