Contrived Interfaces

Some interfaces are unwieldy to use because they are heavily contrived.

Try this: write what you want to do. Write it simply, ignoring the actual services of your environment, as if you were free to write it however you'd like to do it.

Now, underneath that, write the code to actually do the job. If you find that you have to create a bunch of objects whose only purpose is to act as parameters (Is this an example of a CurriedObject?), that you have to chain member dereferences and/or type casts, that you have to look up constant values, etc, in order to the work, include these things.

Look at the difference between the thing that you want to do, and the things that you have to do in order to call the methods which do the thing you want to do. Then look at all of the things you have to do in order to find out if you've done the thing you want to do.

The difference between what you'd write in an ideal implementation, and what you have to write in your current implementation is the contrivance.

A small amount of contrivance is necessary sometimes, but when you look at what should have been a simple function, and well over 50% of it is contrivance, you start to wonder if maybe you're WorkingTooHard?.

I'd started to catalog these kinds of problems years ago, before I heard of CodeSmells, and now I'm delighted to have a place to document it.

-- TimOttinger


A classic example would be programming directly to COM in C++. --CurtisBartley


The initial remark looks like it's talking about Java interfaces, so here I go...I guess the question is why you define an interface. According to XP, YouArentGonnaNeedIt. The answer is because someone is using it. The Swing widget models are a good example of this. The question they ask is: "What method do I need in an object so I can show it as a tree?". If it's foo and bar, I define my TreeModel? as having the methods foo() and bar(). The point I'm trying to make is that it's the tree (the client) that defines what the interface has to look like. You are sure that the interface is right, because the client knows what it needs. If you end up writing a lot of code to implement this interface, either you really have a large conceptual distance between client and implementor of the interface (and in this case there's no way around writing adapter code) or your implementor is not well designed (because if the concept its implementing is just like a tree, but the implementation is not, the implementation is probably bogus). --ThomasMaeder

Indeed. CodeUnitTestFirst may help. -- DaveHarris

Personally, I find that if you CodeUnitTestFirst, you put a lot of pressure on the interfaces before the implementation, which results in much nicer interfaces. (I'm using the word "interface" in the generic OO-sense, not the Java-specific sense.)

Probably so. I really didn't have Java in mind at all. I was looking at MFC and other ill-conceived code written by OO novices on deadlines and realized that a lot of programming is only hard because people accept interfaces that are contrived. I see blocks of code where you have to create a half-dozen or more temporary variables just so you can pass pointers to these variables to a function, and of course the caller never uses the temporaries in any way. They pass them to satisfy a contrived interface.

Then I realize that I can write functions to replace these, and the functions may have one or two overloads, and they're smaller and simpler, and all the values you pass are actually used.

I also saw a lot of Ingres 4GL code where one parameter would be the actual function to perform, and some subset of the remaining parameters would apply depending on what the sub-function really required. So the interface was really a bunch of interfaces munged together for some unknown reason, and it was heavily contrived also in the 'requires much research' sense.

I've never seen anything like these in good C++ code, in good Ada, or in any python that I've ever read. I realize that's because "good" means that none of these silly things are being done. It's by definition, not coincidence.

TimOttinger


I think MechanismRichPolicyFree is a prime cause of ContrivedInterfaces. Sometimes people try hard to provide just mechanism, and they also try to avoid redundancy (for example, if you have Foo() and Bar() don't provide FooThenBar?()), and you end up with a class that can be made to do anything but you have to do masses of work outside of it to get it to go.

What I've seen of COM fits this. It tries to be very general, language independent and usable by a wide range of application domains. So the common cases take a lot of code, to specify all that policy which the COM interface left out. -- DaveHarris

See also PrematureGeneralization.


Should this be extended to also apply to the amount of manual/reference search and reference necessary for calling a function? I have in mind a function that has over 9 parameters (MFC, of course) several of which you must create variables to pass ("normal" contrivance).

You end up having to look up the special #defined values for most of the parameters, and make sure you pass pointers or pointers to pointers for others, and some scattered through the parameter list are reserved and have to be set to zero. So every call is unlikely to be correct.

And of course, nothing is defaulted.

That's heavily contrived?


CategoryCodeSmell CategoryInterface


EditText of this page (last edited February 8, 2006) or FindPage with title or text search