46

In Rich Hickey's thought-provoking goto conference keynote "The Value of Values" at 29 minutes he's talking about the overhead of a language like Java and makes a statement like, "All those interfaces kill your reuse." What does he mean? Is that true?

In my search for answers, I have run across:

  • The Principle of Least Knowledge AKA The Law of Demeter which encourages airtight API interfaces. Wikipedia also lists some disadvantages.

  • Kevlin Henney's Imperial Clothing Crisis which argues that use, not reuse is the appropriate goal.

  • Jack Diederich's "Stop Writing Classes" talk which argues against over-engineering in general.

Clearly, anything written badly enough will be useless. But how would the interface of a well-written API prevent that code from being used? There are examples throughout history of something made for one purpose being used more for something else. But in the software world, if you use something for a purpose it wasn't intended for, it usually breaks.

I'm looking for one good example of a good interface preventing a legitimate but unintended use of some code. Does that exist? I can't picture it.

7
  • 1
    Haven't watched/read the stuff (I've added "Stop Writing Classes" to my to-watch list :) ), but maybe they are arguing from a dynamic vs static typing angle? ...again?
    – Andres F.
    May 23, 2013 at 22:56
  • o.O Application programming interface interfaces May 23, 2013 at 23:02
  • Thanks for the links! I didn't find Jack Diederich's talk particularly illuminating (watch how he fails to answer the audience's genuine questions convincingly.. "uh, yeah, maybe in that case...". I did like he seems to be arguing for Functional Programming without even noticing it ;) ), but the "Imperial Clothing Crisis" is very good and insightful.
    – Andres F.
    May 25, 2013 at 18:44
  • 1
    MPO is that people who don't believe in reuse don't break things down into small enough units. A big thing that is built for one specific purpose can't be reused. However, small things usually have a small enough purpose that the small purpose is useful in more than one context. May 26, 2013 at 1:45
  • 2
    @AmyBlankenship I found the "Imperial Clothing Crisis" linked above to be insightful. The author considers "reuse" a false idol (something which hasn't been proven useful in practice, and also most people don't even understand it even though they use the word). He also doesn't consider libraries "reuse"; you use a library, you don't reuse it. He also considers designing something for reuse "a double-edged sword"; something that people usually consider a win-win situation but which really isn't: when you design something for reuse, it's always a compromise (e.g. you may lose in simplicity)
    – Andres F.
    May 26, 2013 at 23:23

5 Answers 5

34

Haven't watched the full Rich Hickey presentation, but if I understand him correctly, and judging from what he says about the 29-minute mark, he seems to be arguing about types killing reuse. He is using the term "interface" loosely as a synonym for "named type", which makes sense.

If you have two entities { "name":"John" } of type Person, and { "name": "Rover" } of type Dog, in Java-land they probably cannot interoperate unless they share a common interface or ancestor (like Mammal, which means writing more code). So the interfaces/types here are "killing your reuse": even though Person and Dog look the same, one cannot be used interchangeably with the other, unless you write additional code to support that. Note Hickey also jokes about projects in Java needing lots of classes ("Who here has written a Java application using just 20 classes?"), which seems one consequence of the above.

In "value-oriented" languages, however, you won't assign types to those structures; they are just values which happen to share the same structure (in my example, they both have a name field with a String value) and therefore can easily interoperate, e.g. they can be added to the same collection, passed to the same methods, etc.

To sum up, all this seems to be something about structural equality vs explicit type/interface equality. Unless I missed something from the portions of the video I haven't watched yet :)

11
  • 3
    BTW, Jack Diederich's talk "Stop Writing Classes" seems unrelated to this topic, and is more about YAGNI and "don't write code until you need it, and then only write simple code".
    – Andres F.
    May 25, 2013 at 22:47
  • 17
    ERROR: Object doesn't have a property called "name" is often the result of value-oriented languages, and the other problem is when you want to no longer call that property name. Good luck refactoring because there are likely hundreds of objects with a property name but not all are Person or Dog.
    – Reactgular
    May 25, 2013 at 23:18
  • 2
    @MathewFoscarini Yeah, I don't necessarily agree with it, it's just my interpretation of what I think Hickey was saying :) I like types and static typing; I'm just starting to dislike Java. And my dislike is unrelated to interfaces but to the mess that is the typical Java project.
    – Andres F.
    May 25, 2013 at 23:24
  • 1
    Java is the programming language for those who prefer to think too much. It's one of the few languages that allows a developer to easily hide his attempts to over engineer a project.
    – Reactgular
    May 25, 2013 at 23:34
  • 1
    I did watch the whole talk, many times, over the past 6 years. His statement goes far beyond this answer and I cannot summarize it here; "all those interfaces kill your code reuse" is a theme running through the entire talk. In addition to this answer: copying the value is trivial; serializing the value is easy; sharing the value with other languages or programs is easy; comparing values is easy. When using interfaces, special code must be written for each interface to copy, serialize, share, compare, etc.. Hence, code reuse is killed.
    – Jason
    Aug 8, 2020 at 18:25
29

He is likely referring to the basic fact that an interface can not be instantiated. You can not reuse an interface. You can only implement code that supports it, and when you write code for an interface there is no reuse.

Java has a history of providing frameworks of many API(s) that take an interface as arguments, but the team who developed the API never implement a wide range of classes for you to reuse with those interfaces.

It's kind of like a GUI framework that has an IWindow interface for a dialog box, and then you can add IButton interfaces for controls. Except, they never gave you a good Button class that implements IButton. So you're left creating your own.

Abstracted frameworks that have a wide range of base classes providing core functionalities are more reusable, and that works best when those abstracted classes are accessible to those using the framework.

Java developers started doing this thing where their API layers exposed only interfaces. You could implement those interfaces, but you could never reuse classes from the developer that implemented those interfaces. It's kind of like a cloak and dagger style of API development.

5
  • 4
    Thank you for this answer. I now feel like I understand the question and the answer :)
    – MetaFight
    May 24, 2013 at 7:59
  • 2
    +1 I really appreciate your answer and it adds a fascinating layer of interesting information to this question. But I think Andreas F.'s answer is likely closer to the heart of what Mr. Hickey meant, so I accepted his instead. May 27, 2013 at 18:00
  • @GlenPeterson no problem, I think he might be on the mark as well.
    – Reactgular
    May 27, 2013 at 18:01
  • 1
    Well this and the accepted answer highlight two slightly different, but equally interesting, interpretations. I'm curious which one Mr. Hickey had in mind when talking about this.. May 28, 2013 at 22:12
  • You cannot reuse an interface , but you can extends it (and give valuable version number) without changing old classes. You can also inherit from many interfaces to add new job for new classes, or do add new inheritence in old recompiled classes . You can also extends the class that implements this interface for new job.
    – cl-r
    Jun 13, 2013 at 13:21
15

I think slide 13 at his presentation (The Value of Values) helps to understand this:

http://i.stack.imgur.com/LVMne.png


Values

  • Don’t need methods
    • I can send you values without code
      and you are fine

My understanding is, Hickey suggests that if I need to, say, double the value you sent to me, I simply write code looking like

    MyValue = Double(YourValue)

You see, above code is the same, no matter what kind value you sent - sort of a perfect reuse.

Now, how this would look like in the language having objects and interfaces?

    Doublable MyValue = YourValue.Double()

oh wait! what if YourValue doesn't implement Doublable? not that it can't be doubled, it may perfectly be but... what if there's just no method Double? (what if there's a method called say TwiceAsMuch?)

Uh oh we've got a problem. YourValue.Double won't work, it can't be reused anymore. Per my reading of above slide, this is about what Hickey meant when he said, "All those interfaces kill your reuse!"

You see, interfaces assume that objects are passed around "along with their methods", along with code that operates on these. To use objects, one need to understand how to invoke that code, what method to call.

When expected method is missing, there is a problem, even though semantically, desired operation makes perfect sense for an object. As stated in the presentation, values don't need methods ("I can send you values without code and you are fine"), allowing to write code dealing with them in a generic manner.


Side note: notion of passing around code-less values somehow reminds me of a Flyweight pattern in OOP.

an object that minimizes memory use by sharing as much data as possible with other similar objects; it is a way to use objects in large numbers when a simple repeated representation would use an unacceptable amount of memory... Flyweight objects are by definition value objects. The identity of the object instance is of no consequence therefore two Flyweight instances of the same value are considered equal...

Flyweight usages I've seen typically followed the same approach of stripping off the code (methods, interfaces) from objects and passing stuff around around as, well, code-less values, expecting that receiving code has means necessary to operate on these.

This feels pretty much as at the slide, "values don’t need methods. I can send you values without code and you are fine".

12
  • 6
    Generics would pretty much take care of that problem. Doubling makes sense on some objects, but not on others. In the Go language, there is implicit interface implementation (a form of duck typing), so you don't have all those interfaces to worry about. On the other hand, you sorta have to know which object is going to be hit by your method signature; otherwise, you might get unexpected results. There are always tradeoffs. May 23, 2013 at 23:09
  • 1
    An interesting take. Good answer!
    – maple_shaft
    May 24, 2013 at 0:57
  • 2
    The flyweight pattern is not what Rich is talking about. As the second sentence of the article states, the purpose of the flyweight pattern is to conserve memory. Rich's approach does not seek to do that.
    – user39685
    May 24, 2013 at 12:41
  • 7
    MyValue = Double(YourValue) doesn't make sense if YourValue is a String, an Address, a User, a Function, or a Database. Otherwise, your missing-method argument is a strong one. OTOH, accessor methods let you enforce various constraints so that your Values are valid, and that only sensible operations are used to produce new Values. If you later decide to separate the Address from your User and Company, accessor methods mean that you don't break all the clients of your code. So they can help reuse in the long-term even if they sometimes hinder it in the short-term. May 24, 2013 at 13:24
  • 5
    (On the other hand, I do agree that in Java-land, the explosion of classes, interfaces and frameworks is a nightmare. The simplest "enterprisey" solution in Java is a mess of code. So I do take a valuable lesson from this question & answer, without necessarily agreeing with the dynamic typing stuff)
    – Andres F.
    May 24, 2013 at 15:23
3

In an (i.e. my) ideal world classes and interfaces would always describe behavior, but the fact is that all too often they really just end up describing data. Only yesterday I watched video of someone build a so-called BankAccount class that was nothing more than a glorified int (indeed it was much less useful than an int, thus 'killing' the reuse I would've had had it simply been left as an int), all in the name of 'good' design. The amount of code, sweat and tears wasted on continually reinventing convoluted representations of data is staggering; if you're not using the data in a meaningful way then please just let it be.

Now, this is the stage where Rich Hickey is content to throw the baby out with the bathwater and say that we should all go live in the land of values (a neighbor to the kingdom of nouns). I think, on the hand, that OOP can and does promote reuse (and importantly discoverability, which I find lacking in functional programming) when employed judiciously. If you're looking for an OOP principle that best captures this tension I think it might be http://c2.com/cgi/wiki?TellDontAsk (which of course is a close cousin of Demeter)

2
  • What do you mean by discoverability? Is it similar to this?
    – user39685
    Jun 27, 2013 at 15:20
  • 1
    Yes, I think that touches on a lot of the main points. It's a subtle point but discoverability is a balancing act, making things too transparent is undesirable as well because you'll get a bad signal to noise ratio.
    – CurtainDog
    Jun 28, 2013 at 3:51
1

I know this is an old question, but I feel like I have to provide an answer because even the accepted one is not what Rich Hickey meant. What he is talking about is broader than types. For example, a String is a type in Java, but it would qualify as a value under what Rich is discussing because it is immutable (among other things).

Consider instead the idea of a Bob object created using a Person class in say, Java. It has methods like getName, getAge, getAddress etc. It may implement some interfaces as well, who knows. How do you deal with the Bob object in another system written in Java? How do you deal with it in a system written in another language? You would literally have to recreate the same methods, class, and interfaces in that language or system, and even then, those systems would not be interoperable.

You cannot hope to comprehend what the Bob object is except by poking it with methods one by one to glean some details, but never understanding the whole or being able to perceive it. When Rich Hickey was talking about "operational interface", he did not mean literal interfaces that classes adhere to, but how you interact with the thing itself, which in the case of objects would be methods like getters.

Now compare this with Bob in the form of a map like so (we'll use Clojure):

{:name "Bob", :age 45, :occupation "Software Engineer"}

That's actual data. You can see the whole of it instantly. You can pass it into various functions, you can alias it (with objects you would need to snapshot/lock/copy in case it changes), you can do comparisons to see if it's equal to some other data, you can send it over the wire, other languages can easily manipulate it because they all have some notion of ints, strings, maps, etc. If you stick to data like this, you can use generic functions that operate on it instead of methods which are specific to your type or interface. (and which don't exist in other languages or systems!)

He followed up with an example, asking you to imagine that instead of asking for a web page and getting the value itself (the html string and assets) you had to individually ask for each thing (getHeader, getBody). How do you know that in the end you are receiving the page exactly as the author intended? What if something changes in between calls?

This is the problem with place oriented programming and imperative languages, where things are mutable. To sum up Rich's talk, information systems should be focused on values rather than implementation specific constructs like objects, because values are universal and easy to extend, share, and preserve. Erasing and overwriting made more sense when resources were limited.

Not the answer you're looking for? Browse other questions tagged or ask your own question.