Summary
A colleague of mine, Peter Grogono, brought to my attention recently the overlooked backside of interfaces.
Advertisement
The following quote was from a talk given by Peter Grogono, and surprised me something solid. Because I thought there wasn't anything I was fundamentally overlooking about software engineering :
Interfaces and calling out the back Another thing that all software engineers
and many other kinds of engineers seem to agree about is the separation of interface and
implementation. Of course, thats closely related to encapsulation. I hope we all agee that
the data members of an object should be private. So the interface of the object is defined
by the methods it provides. Right? Well, up to a point.
Electrical engineers work with boxes. What comes out of the box is the interface. Whats
inside the box is the implementation. Heres a box. Is this its interface?
No, not quite. It has a back as well as a front, and heres the back. The interface consists of both the front, with the user controls, and the back, with all the wires going to the rest of the world.
How does this relate to objects? The public methods of an object are just the front view:
the user controls. The interface consists of the public methods provided to users and the
methods of other objects that the object calls. But in design we tend to ignore the back
and worry about the front only. UML encourages this, by the way.
Grogono gives credit to Brian Shearing for this "calls-out-the-back" problem. Peter went into more depth in his talk, but this idea alone is something which rocks my world.
Cognitively I feel a Boa constrictor which just swallowed a goat. I am going to have to go away and digest it a bit. Maybe you care to tell me whether or not this is obvious, and if it is why don't more programming / specification languages address it. Or you can try to convince me why we shouldn't be considered about what dangles out the back of the boxes.
"No, not quite. It has a back as well as a front, and heres the back. The interface consists of both the front, with the user controls, and the back, with all the wires going to the rest of the world."
I think this is a flawed analogy. The wires don't just go out into the ether shocking random animals. They plug into the interfaces of other boxes.
Yes, this is important and often overlooked. However, I think a better name would be the back interface of an object. An object usually has multiple interfaces and the front panel is only one of them.
Usually the back interface is important in the construction phase. When you install the box, you're plugging in all the wires on the back. Once it's installed, the users only care about the front panel.
You might be interested in the Inversion of Control paradigm that's popular in Javaland. The basic idea is that we can make object construction more flexible by exposing the wiring as parameters to the object's constructor, or alternately as setters.
> "No, not quite. It has a back as well as a front, and > heres the back. The interface consists of both the front, > with the user controls, and the back, with all the wires > going to the rest of the world." > > I think this is a flawed analogy. The wires don't just go > out into the ether shocking random animals. They plug > into the interfaces of other boxes.
I think the question is "which other boxes?". This is usually not clearly specified in code, documentation or specification. Besides for a few import or using clauses, which may or may not be meaningful.
> I think this is a flawed analogy. The wires don't just go > out into the ether shocking random animals. They plug > into the interfaces of other boxes. I think that's the point that Christopher (and his colleague) were trying to make: an object has a "front" interface from where it can be used by other objects, and a "back" interface from where it uses other objects (and uses the front interface of the aforementioned other objects).
In electrical schematics and such this is usually fairly well documented, you know where your internal/back wires go and how the back interface works, usually not so in computer engineering (best you can get are usually mere hints via imports, other than that you have to dwelve into the code to see what exactly is used and how it is used).
> I think the question is "which other boxes?". This is > usually not clearly specified in code, documentation or > specification. Besides for a few import or using clauses, > which may or may not be meaningful.
I don't know about that. An object with two distinct and public interfaces is called an adapter. It's also common to allow components to be set at runtime but in this case, the object isn't creating another interface, coupling itself to another type's interface. Then you have some wiring that is all done by hand.
This is exactly how wiring works, say, in my house. When I replace a lightswitch, there's no interface other than two wires which need to be twisted to the proper partner wires and wrapped up with electrical tape. The you have a lamp which has an interface (on-off switch) and is coupled to another interface (the wall outlet.) Then you have boxes with two interfaces say like a fuse-box or a transformer. My dishwasher and disposal connect directly to copper wire from the wall with screw-down connectors, while the stove has a plug. There's no one way to do it. The approach depends on what you are doing.
> In electrical schematics and such this is usually fairly > well documented, you know where your internal/back wires > go and how the back interface works, usually not so in > computer engineering (best you can get are usually mere > hints via imports, other than that you have to dwelve into > the code to see what exactly is used and how it is used).
There's no reason that documentation couldn't tell you this level of detail. In a strongly typed language it's easy to automate this.
But I didn't get the idea that this was about documentation.
This is a known and quite well understood principle of OO and dependency management. It is reflected in the Dependency Inversion Principle and is quite well covered here: http://www.objectmentor.com/mentoring/OOPrinciples
I recall reading an interesting article here on Artima that discusses differences between public and protected interfaces also.
The 'calls-out-the-back' problem sounds like a nice way of describing the issue.
I've been trying to get this across (on some other site of mine) for quite some time now. I called them outgoing interfaces. This is the key to reusability and is the foundation of my new project. Codecs are known to use this methodology. They call them "filters" mostly. It's a better way to stream data because you can link multiple components together. And even if the parts don't fit, you can easily write a converter to mold the data so that it does fit. I believe it to be the missing link (pardon the pun) of OOP. However, I believe that functionality should not be inside an object, but inside these black boxes independant of the data they act on.
Not only this, but independant components (on a slightly larger scale), can make threading much easier as there's no coupling at all. Not only that, but pipelining increases runtime even more in multi-cores.
It can be a strange way to look at things though if you're used to OOP. Instead of the object deciding what it calls, it only published what it needs (resources required) and it's up to the larger encompasing object (or application) to link these objects together. Right now, we're just plugging switchboard into switchboard without regard to what they connect to.
I'm SO glad you brought this up. I was worried this would never get recognised.
I also think that the "back interface" of a class is an important, and often overlooked point. It's necessary for true component softeware that goes further than the monolithic API's we mostly have today. There's a paper about this in OOPSLA 2005. See:
Is this really about the 'backside of an interface' and not about the provided and required interfaces of an object or component? I've seen a good reference to the DIP come by already, and Clemens Szyperski already wrote about required interfaces in 1997 (Component Software - Beyond Object Oriented Programming). If this is the case, I don't like the analogy made here, but I do agree that software designs and documentation (in any form, from full models, simple documents to code comments) pay far too little attention to the required interfaces.
> I've been trying to get this across (on some other site of > mine) for quite some time now. I called them outgoing > interfaces. This is the key to reusability and is the > foundation of my new project. Codecs are known to use > this methodology. They call them "filters" mostly. It's > a better way to stream data because you can link multiple > components together. And even if the parts don't fit, you > can easily write a converter to mold the data so that it > does fit. I believe it to be the missing link (pardon the > pun) of OOP. However, I believe that functionality should > not be inside an object, but inside these black boxes > independant of the data they act on.
This sounds interesting, can you provide any references that give more detail and/or examples? Is there not a widely accepted name for this? If not maybe this needs to be described as a pattern and named.
You are not suggesting this as a general solution for all problsms, are you?
> Is there not a widely accepted name for this? It reminds me of the Eclipse plug-in architecture. Eclipse plug-ins are those black boxes and are wired together in XML files. Other names may be plug-ins (in a broader sense), or service provider interfaces (SPI).
You may be interested to check out the Koala Component model, developed in Philips. Last time I heard about it they used it at a large scale in their consumer electronics products.
In Koala, components need to specify both types of interfaces. They are called 'provides' (front end) and 'requires' (backside).
Systems are composed by aggregating modules and resolving both kinds of interfaces at compile time. The designer must specify what components hook to what other components inside the aggregate. Unresolved interfaces become interfaces of the aggregate itself. A completed system has no unresolved interfaces.