Repeat after me, COM is just an interface layer

| 5 Comments
I was reading this the other day and I recognised Past Mozilla Mistakes: two as something that quite a few (if not all) of my clients have made...

If you're writing in C++ then COM is just an interface layer. It's great for providing access to an object model to loads of non C++ consumers but, in my opinion, it's a lousy thing to base your entire system on. COM is a complex thing, considering how much work it does for you, the rules aren't that onerous, but they tend to corrupt nice, clean C++ code if you let them. I'm convinced that COM should stay at the edges, use it as an interface layer and write everything else as if COM didn't exist. As usual this means that you need to think a bit more; trust me, it's worth it.

All too often I've seen projects where every object is a fully fledged COM object; no matter how simple, or how 'internal' it is, it does IUnknown. Often the creators are proud of this; I'm a COM programmer, not a C++ programmer. Yeah, right... All that says to me is 'I can't decide where it's appropriate to use a technology and where it's inappropriate, so I'll use it everywhere'.

These 'single hammer' developers are making life hard for themselves. Once again a failure to make decisions that limit what you can do makes the resulting code more complex. Everything is a COM object because thinking about what should be a COM object is harder than just making everything a COM object. Once you head down this route you're saying goodbye to functions that can return results; you're saying goodbye to using const to specify that you aren't going to change this value that you just got by calling GetThing() because it has to return an HRESULT and return the thing you're interested in by reference... You're saying hello to the wonderful world of manipulating everything as variants and safe arrays and mostly using automation types (but not always, it's never always because there's usually someone on the team that slips in a quick hack here or there because they're lazy and doing it the COM way can be such a pain).

Of course there's always someone who has to say 'but it's the only way to do it'. They're wrong. It's not. Even if the thing you're writing exposes much of itself via COM you can still decide how far the COM influence needs to go. You can still use COM just at the borders. On the inside; you can wrap COM objects as soon as you use them (like a grown-up's version of #import that requires thinking) and, guess what, you only need to do this once... If you use the COM version of the MS XML Dom you can write some wrappers for the bits you use, they can do all the HRESULT checking, argument translation, etc and provide a nice clean interface that the rest of your code can use; if you're feeling clever this interface needn't ever expose the fact that it's using COM inside and you could switch to a non-COM version of the implementation if you ever needed or wanted to... On the outside; you can write most of your code in normal C++ and then write a COM layer to expose it to COM clients, and, perhaps, a managed C++ layer to expose it to .Net weenies and, if necessary, package it as a normal DLL or static lib for those legacy C and C++ folk. Even if you don't need to take all of these routes at the start, if you don't bet the farm on COM you can be flexible later on...

This may come across as a tad anti COM. It's not. I think I've done my fair share of COM programming in the past (I still have the scars from the OLE-DB providers they forced me to write); and the thing I've learned is that COM is good for what it's good for, and that is interfacing. It's a relatively expensive layer (in terms of complexity) and as such you should know where it's appropriate to use it and know the things you're giving up if you decide to go that way. Just as you don't want all of your code to be dependant on MFC, or managed C++, or the 'Reuters library' that you use in this one corner of the application but that happens to provide a 'nice' definition of a type that happens to be almost what you need over here; so you don't want all your code to be dependant on COM (and even less so on ATL).

Interfaces are important; decide where they stop.

5 Comments

You make a very good point. COM is good at interfaces and allowing sharing of objects between development environments and third party solutions.
Building large systems out of COM objects does add a lot of complexity. Further, you lose the power of object support within the language (implementation inheritance, operator overloads etc.)
However, to allow plug-in, bolt-on and framework solutions with third party or multiple language developments, COM is the only viable solution.
But if you have a clean slate and none of these issues then leave COM out. It will make your life much easier.

Completely agree re plugins but your whole app needn't be COM based, just the interface layer that talks to the plugins.

It's always a case of working out how far you need to allow COM to spread and my view is that you should try and make that smaller rather than larger. Allowing COM to take over the whole codebase is the easy option, it requires no thought. Deciding where to draw the lines is harder.

Interesting post, I must admit I'm quite surprised anybody would consider making every object in an app a COM object, maybe this is a symptom of too much reliance on the wizards to create classes.

I've been using COM for a couple of years now and I must say I quite like it, I have just implemented Active Scripting in our main app and we were able to provide a lot of functionality with just a couple of weeks work.

It's quite amazing what happens when someone in a company latches onto a single tool or approach and decides that it's the 'one true way'. Of course, often the marketing spin doesn't help deter people from these choices.

I think part of the problem is that often people think 'I need to write a COM object for this' rather than 'I want to do this, I need to expose it via COM'. If you go the later route you probably end up with lots of code written before you even think about creating the COM project and your first COM object; if you head down the former path then you're in a COM project from the start and there's a wizard that appears useful, etc...

Also you have to bear in mind that in many of the client sites that I visit the experience level of the developers is quite low; they often simply find a sample on the web and bend it rather than working out what they actually want to do and then working out how to do it... Add to that mix the, often unchecked, desire to learn new skills whilst writing production code and it's not that surprising that sometimes the wrong choices are made...

I agree totally. One part of StyleAdvisor uses COM to provide an external scripting interface. This scared me to no end as I imagined COM working its ugly fingers down into the core code. Luckily I work with smart people and that never happened, but I could easily see how a project could go that route in the wrong hands.

Leave a comment