Humane Interfaces

Martin Fowler has posted a nice article on humane interface design (as opposed to minimal interface design). I am definitely on the side of right and good (read: humane interfaces) in this debate. Nothing takes the fun out of programming faster than having to write a bit of code that you know has already been written a bazillion times.Even if it is only a few lines code. When I program in Java, which exemplifies the minimal interface approach, I feel like this most of the time. I almost never feel that way in Ruby because humane interfaces are deeply ingrained in the community.

Minimal interfaces shift the maintenance burden to the clients. This is great for the library writer because they have less to maintain, but it is devastating for the community. Humane interfaces have the extra behavior because clients need them.It is rarely, if ever, appropriate to provide behavior that no one needs, regardless of the interface style style. The fact that a minimal interface does not provide an particular bit of behavior does not change the fact that clients need that behavior, it just means that that bit of behavior will be implemented independently in a significant subset of clients. This duplication of common but non-standard behaviors will, over time, significantly increase the total amount of code that a community has to maintain.

This is made worse by the fact that a well designed minimal interface requires fairly small amounts of addition code to implement each individual bit of common behavior. The fact that each of these common behaviors can be implemented quite easily means that they rarely get packaged and reused. For example, you are probably not going to add a dependency to Jakarta Commons IO to your project just to get RegexFilenameFilter, you will just implement it yourself because “it’s only 5-10 lines of code” even though someone has already packaged it for you. And you are definitely not going to package and publish that useful 10-15 line utility you wrote last week because cost far outweighs the value of that one utility. Each of those decisions are reasonable in isolation but put together pretty soon you and your community are stuck with a lot more code to maintain than if that behavior had been included in the core library to start with. (See: boiled frog syndrome)

Comments 8

  1. Devon Jones wrote:

    I suppose this would make me a minimalist on interface design. While it’s really nice to have a good api, an interface is supposed to be a set of operations that make it easy to code something that replacably works with other implementers of that interface. If you have a giant interface (say 78 methods for a list/array instead of 23) you make is substantially less likely that people are going to bother to use that interface when coding a new class because it’s 3 or 4 times the code to implement the much larger interface.

    Are we not better off with people actually *using* the interfaces when they write new code that fits with the idiom instead of shirking it because the interface imposes so much extra work on the coder?

    Perhaps a half way idea – a minimialist interface with an extended humane interface for those that have the time to implement the extra 250%

    Posted 07 Dec 2005 at 1:29 pm
  2. Peter Williams wrote:

    Replacabilty sets off my “you’re NOT gonna need it!” alarm. When is the last time you swapped implementations of an interface? I am not sure I have ever done it, at least not late enough in a project for it to matter.

    But you do make a point that Java interfaces make this problem a lot more complicated than it needs to be. In my experience the vast majority of behaviors on a humane interface are mostly just mixing a series other, more primitive, behaviors together. If Java interfaces were more like abstract classes you could define a couple of abstract primitive methods and provide default implementations of the other 70 or so useful behaviors in terms of those few primitive behaviors. This gets you the best of both worlds.

    An extended “humane” interface would the feasible but I think that it suffers from all the issues you see with humane interfaces in general. Personally, I find that using a language that does not penalize providing humane interfaces quite so much a better choice. :)

    Posted 07 Dec 2005 at 3:04 pm
  3. Jacob Fugal wrote:

    Devon:

    “While it’s really nice to have a good api, an interface is supposed to be a set of operations that make it easy to code something that replacably works with other implementers of that interface. If you have a giant interface (say 78 methods for a list/array instead of 23) you make is substantially less likely that people are going to bother to use that interface when coding a new class because it’s 3 or 4 times the code to implement the much larger interface.”

    I think you’re confusing an INTERFACE (capitals = abstract concept) with an interface (lowercase = Java keyword). Martin Fowler and Peter are referring to the former. The INTERFACE of the class MyArray is the set of methods that are exposed to the User. The NiftyArray interface is the collection of method signatures that the class MyArray must provide in order to “implement” NiftyArray. They are related: the INTERFACE of MyArray must necessarily be a superset of the NiftyArray interface. But they are not the same.

    Now, let’s take interfaces out of the equation all together (Ruby doesn’t have them, nor does it need them). Left only with INTERFACEs we have only the methods provided. Fowler’s article get’s at the point that this set of methods shouldn’t necessarily be minimal. Providing that extra method which encapsulates a common 3 line use of the other functions within the INTERFACE — that’s GOOD, because now that’s 3 lines of code maintained in one place, rather than three lines repeated throughout many projects.

    If you’re defining an interface that is expected to have several implementations, you probably do want it to be minimal while still being convenient. However, if you’re writing a definitive class, such as a class in a core library, splurge. Expand that INTERFACE and make life easier on your users.

    Posted 07 Dec 2005 at 6:34 pm
  4. Brian Slesinsky wrote:

    I think the point here is that java.util.List probably should have been an abstract class, so that default implementations of convenience methods like first() and last() can be provided. (Generally I think having a Java interface with more than a half-dozen methods is a sign that it should have been an abstract class.)

    Posted 07 Dec 2005 at 8:30 pm
  5. Peter Williams wrote:

    Brian, I think you are correct. However in Java this would be unacceptable because you often have class that want to act like a list, in addition to being some other type.

    Posted 08 Dec 2005 at 10:35 am
  6. Donald Marino wrote:

    I would add that from a practical standpoint, the difference is that the large number of convenience interfaces suit Ruby very well, because they allow a programmer to use language that is natural to them. For me one of things that contributes to the fahrvergnugen of Ruby is using natural language in your code a lot. It may simply be more pleasant to say ‘ if myarray.first.is_a ?(thingy)’ vs. ‘ myArray(0).Class.getName(), etc,etc; it is more natural to humans like a programming lang should be (after all, what’s the point?). Also you can state that conditional many ways if that is more natural to you, using one of the 78 available methods. Is it really that difficult to scan an rdoc for a method that suits you? Besides, once you develop your Ruby style, you’ll find those kinds of methods by feel in other classes before you know it. Not everything is about cleanliness. Sometimes you just want to write the code the way you want to write the code, without having to ovverride or implement a bunch of interface methods.

    Posted 08 Dec 2005 at 10:54 pm
  7. truth machine wrote:

    The bottom line of this debate nearly 2 years ago /should/ have been a recognition that Java is badly designed and a vow to reject its design principles — in the long run Sun did, as seen in its addition of numerous missing language features.

    Posted 04 Aug 2007 at 8:16 pm
  8. kuri wrote:

    if myarray.first.is_a ?(thingy)’ vs. ‘ myArray(0).Class.getName(), etc,etc; it is more natural to humans like a programming lang should be (after all, what’s the point?). Also you can state that conditional many ways if that is more natural to you, using one of the 78 available methods.

    Posted 29 Apr 2008 at 3:46 am

Trackbacks & Pingbacks 3

  1. From Tucows Services » Tucows Developer Blog > Blog Archive » Monkey Knife Fight! (or: Not Much Has Changed) on 27 Sep 2007 at 11:07 am

    […] Peter Williams: “Each of those decisions [to keep an interface minimal and let developers write a little extra code] are reasonable in isolation but put together pretty soon you and your community are stuck with a lot more code to maintain than if that behavior had been included in the core library to start with.” […]

  2. From Tucows Services » Tucows Developer Blog > Blog Archive » Monkey Knife Fight! (or: Not Much Has Changed) on 27 Sep 2007 at 11:07 am

    […] Peter Williams: “Each of those decisions [to keep an interface minimal and let developers write a little extra code] are reasonable in isolation but put together pretty soon you and your community are stuck with a lot more code to maintain than if that behavior had been included in the core library to start with.” […]

  3. From Global Nerdy » Blog Archive » Monkey Knife Fight! (or: Not Much Has Changed) on 27 Sep 2007 at 11:13 am

    […] Peter Williams: “Each of those decisions [to keep an interface minimal and let developers write a little extra code] are reasonable in isolation but put together pretty soon you and your community are stuck with a lot more code to maintain than if that behavior had been included in the core library to start with.” […]