Sunday, May 1, 2011

C++ Design Pattern for a Messaging System?

I'm tasked with implementing a messaging system for a real-time simulation. There are several different kinds of messaging objects that need to exist in this system, and more might be added in the future. These objects represent the primary means of communication between the players in the sim. Assuming I fully understand my requirements, the messaging objects can be defined by the following attributes:

  • Send protocol (what messages a player can send and when)
  • Receive protocol (what messages a player can receive and how often)
  • Message format (structure of the data being sent)

The simulation code currently only supports one send and receive protocol and one message format. My job is to make the code more extensible so it can support future changes/additions to protocols and message structure. A first-cut approach to this would be to define abstract base classes for each of the attributes and have each messaging object be composed of handles to them. Every messaging object can then be written as different combinations of protocol and format objects. My concern is that this design can quickly become over-generalized and thus a maintenance nightmare. I cringe at the thought of sifting through a dozen files just to figure out how the heck a FooMessaging really works.

I'll be writing this in C++, but I think this is really more a general design question. Are there any "standard" patterns or best practices I can apply here?

From stackoverflow
  • Okay, I suspect you're doing an A to Z process starting at about G.

    First of all, what are your use cases? What are you trying to do? What kind of "messaging system" are you building? EMAIL? IM? Telepathic?

    Second, what is the domain that you get from those use cases?

    Now, having thought that through, then yes, you often find it convenient to make an ABC for the basic classes. Consider making an interface instead (although the distinction between interfaces and ABCs in C++ is less well defined than other languages.) Over the last 20 years, inheritance-based OO has turned out to impose a lot of problems, so that interfaces and aggregation are now favored. Not always better, but you should think of them first.

    Now, tell me what the physical thing corresponding to the "protocol" is? Do you mean to model something like a message stream? Is it a communications medium?

    Format in particular sounds suspicious, if not immediately wrong: message formats tend to be tied intimately to the protocol.

    Basically, back up a bit and tell us more about what you're trying to do, first.

    Update

    Aha. Okay, see, we get a lot of help from this. First, you mean "protocol" in the sense of the available operations — a perfectly reasonable usage, but confusing when you confound it with TCP vs UDP, that sort of thing, as I did.

    Now, that said, you do indeed have a couple of options at least. In the following, I use the term "Player" for any entity in the sim that can send or receive messages.

    The key notion here is to design around the loci for change, and around nonfunctional requirements. The obvious loci of change are

    • you can have several "protocols" in your sense, and if you have as many as three, you should just plan that there can always be more. If you expect more than two, plan that you can have arbitrarily many.

    • you can have several different ways of formatting messages, ie, JSON, XML, or YAML, say. AGain, if you expect more than two, plan that you can have arbitrarily many.

    • You can have several transport mechanisms. From the sounds of things, you can at least use UNIX-domain sockets×shared memory×named pipes, but then my intuition says you also have the option of local and remote, which means you also have the option of UDP or TCP. Definitely more than two, plan for extensibility.

    Option 1:

    Use a Proxy pattern, where each protocol defines an interface that must be implemented in one of several ways, depending upon the messaging format underneath. Players advertise what messages they're willing to receive; at the time they are prepared to receive a message, they construct something that invokes their code for any specific operation message they receive. To send, they construct an object implementing the appropriate interface for their receiving partner Player.

    Under the covers, these objects can have several realizations, each for a different messaging format and transport mechanism.

    Examples of a system like this include SOM/DSOM a/k/a CORBA, and Java RMI using the Remote interface.

    Option 2:

    You can build something around the Command pattern. Each protocol has a specific implementation of "send me", and your receiver simply knows how to reconstruct an object sent. The command objects have a mix-in (multiply-inherited, or passed as an object at run time) that knows how to marshall and serialize the Command object; you can have a second one that understands the transport mechanism.

    You send a message on a particular protocol by serializing the object and using your transport mechanism to move the serialized form to the receiver. The receiver "rehydrates" the object, and invokes the appropriate methods based on the actual type sent.

    An example of this is Java RMI with the Serializable interface instead of using Remote.

    Kristo : I've reworded my question to hopefully make it clearer. I am *not* designing the messaging system itself. Rather, I am looking for a good way to make it easy to add new send/receive protocols and message formats in the future. And yes, in our case, the message format does vary independently from the protocol being used. Sorry for being vague, but I'm not allowed to provide specific details.
    Ori Pessach : The question is still very vague. I've worked on a number of projects that included something that could fit your description, and they were all very different. That tells me that your description of the problem is still not specific enough to let anyone give you a useful answer. Things that would change your design radically but you haven't talked about are whether the messages are sent between processes running on the same machine, on a network, between threads, or in a single thread. Whether any object can message any other object, or do objects are expected to do something specific
    Ori Pessach : in order to receive messages. Will a message loop be acceptable design? Will the messaging layer be expected to call methods on the objects in response to messages? Would that even be acceptable? Are messages synchronous or asynchronous? Is there guaranteed delivery? Is the messaging layer expected to store and forward messages to objects that aren't there yet, aren't listening or unreachable? The fact that someone proposed Apache ActiveMQ as an answer should tell you how bad your question was.
    Kristo : The transport layer is already fixed in stone for this project and can effectively be treated as a black box from my point of view. Also, a player can attempt to send messages at any time, but the send protocol will hold them until they're allowed to go. Likewise, players will physically receive messages every frame, but the receive protocol won't let them be processed until the right time.
  • I believe you should take a look on Apache ActiveMQ. Actually, it is written on Java, but has option to use C++ clients and well documented also.

    Cheers.

    Ori Pessach : I can't see this without warning people NOT to use ActiveMQ.
    Artyom Sokolov : Why not? Please, comment. Thanks.
    Ori Pessach : I've seen it used in a project. It failed to scale to a moderate number of clients and had severe stability issues that were never resolved. To add insult to injury, its performance was rather poor. In my opinion, it is a ridiculously over engineered solution to a problem that doesn't need a solution that suffers from overgeneralization to this degree.

0 comments:

Post a Comment