The coding blog of Alastair Smith, a software developer based in Cambridge, UK. Interested in DevOps, Azure, Kubernetes, .NET Core, and VueJS.
I’ve been running a couple of coding projects at home over the last couple of months, one of which is a personal finance program. I’ve used this as an experiment in new technologies (mainly .Net 3.0/3.5 stuff, including LINQ and WPF/XAML), as well as one in architecture and design patterns. The program is based around a plug-in architecture and the time has come to consider message-passing between plug-ins; for example, I need non-storage plug-ins to inform storage plug-ins when their data has changed, and what data has changed, so that the storage plug-ins can schedule these changes for serialisation to their storage format (be it an SQLite database, an XML file, or whatever). The plug-in framework enables the loading of different classes of plug-ins, each with their own interface; for example, there is a class of plug-in for accounts, one for reports, two for file type support (import and export), etc. The framework provides the environment for loading and interacting with plug-ins, the necessary interfaces etc. for coding plug-ins against, managing of preferences and logging, etc., etc., etc., ad nauseam. It is a mediator and arbitrator between the plug-ins which provide the real meat of the application.
The project has now got to the point where I need to be able to pass messages around the framework, between plug-ins. The immediate solution that sprung to mind was the classic publish/subscribe model, so I duly looked into the Observer pattern, a manual implementation of publish/subscribe. This feels wrong in that it doesn’t seem to provide a way for plug-ins to register new notification types (e.g., BeforeDataChange => “if you need to do something before you update your data, now is your chance”) under defined categories of events, let alone define new categories. Solution #1 scrapped.
I thought I’d cracked it with my next possible solution, the Blackboard pattern, which is based around the idea of cops solving a crime; the policemen post different bits of information and evidence on a central blackboard and infer further information in the form of links and relationships between the items. This approach has historically been used to great effect in AI systems, such as OCR, speech recognition, etc., but didn’t feel quite right for this scenario. However, I didn’t like the idea of posting up all these changes for the entire application to see, when the message was intended for a particular set of recipients. Solution #2 scrapped.
So I revisited publish/subscribe, this time with .Net events. A .Net event is just a special case of the .Net idea of a delegate, or callback, method; it is an analogue to a function pointer for those of you in the C++ world, although it has to be said that this metaphor quickly breaks down as delegates also have an object representation that makes the more than just pointers. They give you multi-casting for free, as callback methods are assigned to delegates using the “+=” operator, building a list of methods invoked by calling the delegate. I thought maybe I could leverage the object-ness of delegates to implement categories via inheritance, but it turned out this wasn’t possible (probably A Good Thing™).
Events don’t seem to play nicely with my proposed model of using a broker class to mediate the publications and subscriptions. The broker should store a list of published actions, and plug-ins should be able to retrieve the list of published actions in order to subscribe to a subset of them. I may need to go down the path of a custom solution (such as porting the Message Manager from my fourth-year project), which is not very DRY, but should give me a greater level of decoupling in the architecture than I think an events-based model will give me.