techvanguards.com
Last updated on 1/25/2016

Growth, Flexibility, & COM
by Binh Ly

In COM, interfaces are the key to server flexibility and growth. An interface has one important characteristic: Clients see an interface as simply a list of methods, not how the methods are implemented. Because of this,

  1. A server object is free to implement the methods in however way it wants. More importantly, an object that implements a method today can come back a year later and re-implement that method in a different way. As an example of how this feature is useful: consider a server object that's used to retrieve information from a mainframe database. A year later, you decide to move all your database information from your mainframe database to a desktop database. You now have to rewrite parts of your server object to retrieve data from the desktop database instead of the mainframe database. If, in all of this, you never change the server's interface, the client would still work with the server as if the server never changed. Since the interface is the client's view of the server and if the interface never changes, the client's friendship with the server is never broken.
     
  2. Two (or more) objects can implement the same interface in different ways. Consider the above example with a different twist: You only copy information from the mainframe to the desktop because some clients might still want to access the mainframe information at the same time other clients are accessing desktop information (this example might seem rather contrived but is a very common scenario in legacy migration projects). Given this, it's very reasonable to create 1 server object that gets data from the mainframe and another server object that gets data from the desktop database. These 2 objects can expose the same interface so that to the client, there is absolutely no difference in retrieving data from the mainframe or from the desktop. All the client needs to do is create the correct server object and then use the one interface common to both objects.

In many respects, an interface is a "contract" between the client and the server. Once the server says "This is my interface and this is what it looks like", the server is giving its word to clients that:

  1. It will always support and uphold the interface to the best of its abilities. This means that a server can not just one day decide to not support the interface anymore. If it did this while there are existing clients that are dependent on that interface, the server would quickly make a list of enemies.
     
  2. It will never change the interface. Change means removing a method, changing a method, or switching the order of methods. Why is this important? If a method is removed from an interface while existing clients still expect to use that method, that's a sign of war. Same goes if the server changes a method such as changing the method's parameters or if the server reorders methods.

At first, not being able to change an interface seems to be a severe limitation. What if we want to change some methods? What if we want to add new methods? No problem! We simply create a newer interface and add it to the list of interfaces that the server supports. Clients who want (and know about) the new functionality simply query for the newer interface. At the same time, old-time clients who have no interest nor knowledge in the new functionality can still use the same object through the older interface. The important idea here is that servers can continue to grow and evolve without leaving old clients behind - a key to maintaining long-lasting friendships.

Evolution also sometimes requires that servers build themselves on top of other servers. If a server wants to implement some functionality that is already implemented in another server, why not just make friends with that other server? A server can even build itself on top of several smaller servers not unlike a house built on top of bricks and iron. 

As an example let's consider our contact manager (C) and messaging (M) applications from the previous chapter. If you recall, C uses M's Messenger object to send email and fax messages out to its contacts. Assume that we are now interested in developing a Scheduler application (S) in which we want a feature where  we can send an email greeting to a contact on his birthday. Since C has the ability to find out the birthdays of each contact and already uses M to send messages out to contacts, why don't we just make C a server to S. 

So C is now a server built on top of another server (M).

Figure: Scheduler as a client of Contact Manager; Contact Manager as a client of Messenger

If C exposes an object, ContactManager, we can define and implement ContactManager's interface as follows:

IContactManager = interface
  procedure SendGreetingMessageToTodaysBirthdayCelebrants;
end;

procedure IContactManager.SendGreetingMessageToTodaysBirthdayCelebrants;
begin
  Find all contacts whose birthday is today;
  Create Messenger object from M;
  For each contact whose birthday is today
    Send birthday greeting to contact using Messenger's IEmail.SendMail method;
end;

Client S would now be very happy to use the ContactManager object from C:

Figure: Scheduler using the ContactManager object, which in turn uses the Messenger object

Where Are We?

COM clearly distinguishes between an object's interface and implementation. Interfaces rule when it comes to server flexibility, growth, and evolution. When we dig more and more into COM, you'll find interfaces everywhere so before taking the next step, it's very important that you understand everything I've said here.

Further Reading

  • Understanding ActiveX and OLE by David Chappell
  • Inside COM by Dale Rogerson
  • Inside DCOM by the Eddons
  • Essential COM by Don Box
Copyright (c) 1999-2011 Binh Ly. All Rights Reserved.