Message Oriented Programming

Man­aging com­plex­ity with­in an applic­a­tion is one of the key chal­lenges for any soft­ware developer. Cleanly recon­cil­ing new fea­tures with exist­ing archi­tec­tures is some­thing we strive for.

After work­ing on a size­able Xamar­in app for the last two years, the single most power­ful tool that I’ve dis­covered is​“Mes­sage Passing”, also known as Message Oriented Programming (MOP). MOP is a fla­vour of object-ori­ented pro­gram­ming (OOP) with the core idea that your objects shouldn’t dir­ectly call each oth­er, but com­mu­nic­ate by passing mes­sages via a mes­sage bus. Mes­sages have a spe­cif­ic type and can con­tain as many argu­ments as required. For example, if your view mod­el object needs to call your API accessor object, instead of the view mod­el dir­ectly call­ing a meth­od belong­ing to your API accessor, it will send a mes­sage of a spe­cif­ic type to the mes­sage bus. The bus will for­ward the mes­sage to oth­er objects which have sub­scribed to receive mes­sages of that mes­sage type.

It may ini­tially seem like unneeded over­head, but the bene­fits are huge…

Coup­ling between callers and respon­ders is removed. This makes life much easi­er when we want to refact­or our code, since objects don’t dir­ectly ref­er­ence one another. Depend­en­cies can be changed on the fly. Because objects can sub­scribe to and unsub­scribe from mes­sages whenev­er they like, we can dynam­ic­ally change beha­viour as required. Mes­sages can be dis­patched to mul­tiple sub­scribers. Mul­tiple objects can sim­ul­tan­eously listen for mes­sages of the same type. This means when an event occurs that requires updates to sev­er­al dif­fer­ent parts our sys­tem, so long as all parts are sub­scribed to the cor­rect mes­sage type, we don’t need to noti­fy each part individually.

For example, a user goes into the user pro­file page of our app and updates their name. The app now needs to update…

The name dis­played on the dash­board page. The name stored in the loc­al SQL­ite database. The name stored in backend data­base of the app. The name stored in the mail­ing list ser­vice used by our app. Etc, etc…

From a coup­ling stand­point, this could poten­tially be a night­mare. How­ever with MOP, we can cre­ate small, cohes­ive classes which each handle one of these respons­ib­il­it­ies. They just need to sub­scribe to a UserNameUpdated mes­sage and per­form their respons­ib­il­ity appro­pri­ately. When the pro­file view mod­el receives the update to the user’s name, it can dis­patch a UserNameUpdated mes­sage and know that everything will be sor­ted out elsewhere.

Classes can be deprec­ated easily. If tomor­row I wanted to replace MyOldAndBuggyClass.cs which handled all Foo mes­sages, it would be easy. I simply cre­ate MyBetterClass.cs , instruct it to sub­scribe to Foo mes­sages and assum­ing MyBetterClass.cs prop­erly handled all Foo mes­sages, we could safely remove MyOldAndBuggyClass.cs . Test­ing is easy. Using MOP , classes essen­tially become func­tions which receive mes­sages as input and dis­patch mes­sages as out­put. There­fore to test a class, we can dis­patch mes­sages with spe­cif­ic para­met­ers and assert that the code in ques­tion out­puts the cor­rect mes­sages in response. Often a spe­cial test­ing mes­sage bus is used to record any mes­sages that are sent. This allows our test cases to determ­ine if the class being tested fired the mes­sages we expec­ted it to.

Like most things the pros come with cons:

Memory and pro­cessing over­head. Send­ing mes­sages comes with a memory and pro­cessing cost, depend­ent on the size of data being passed around inside your mes­sages. Since objects com­mu­nic­at­ing via mes­sage passing shouldn’t share their encap­su­lated state, data added to mes­sages needs to be copied to avoid any side-effects occur­ring if the mes­sage data, for some reas­on, get mod­i­fied by subscribers. Mes­sage types can get out of hand. Because objects com­mu­nic­ate with one anoth­er in many dif­fer­ent ways, the num­ber of mes­sage types you need can bal­loon rap­idly. Some imple­ment­a­tions of MOP require a unique class for each type of mes­sage, which depend­ing on the lan­guage used, can really muddy up your code­base. Oth­ers use unique strings to rep­res­ent a mes­sage type. Whatever the imple­ment­a­tion, the num­ber of mes­sage types can become very large and needs care­ful management. It’s harder to reas­on out pro­gram flow. Because of the dynam­ic nature of objects sub­scrib­ing and unsub­scrib­ing from mes­sage whenev­er they like, it can be much harder to fig­ure out the exact flow that your applic­a­tion will take. This can make debug­ging some­what trickier.

Is MOP worth it? #

Des­pite it’s cons, I abso­lutely think it’s worth it. Your applic­a­tions will be loosely coupled, way more extend­able and primed for testing. 👌