The Humane Interface Discussion Continues
John Mitchell makes some assertions in his post about this discussion (my previous post on this is here). The assertion?
However, Elliot is completely right that having 78 methods in any class is an atrocity. Something that has that much surface area is way too complicated for humans to keep manageable. In addition, it also sets a bad example for coders learning the recommended ways of doing things -- i.e., "just throw anything you feel like in there."
I like the way he baldly asserts that 78 methods is "an atrocity". So what's the magic number? Is 22 methods ok, but 23 - heck no, that gets into atrocity range? There's absolutely no way to look at the raw number of methods and make that statement. He's assuming that there must be fluff in there - but that's an assumption, not evidence. The rest of his post is actually quite reasonable - it's just that one thing I object to.





Comments
[Daniel Berger] December 7, 2005 19:25:18.883
What a bizarre psychological hangup. This weird obsession over the number of methods per class is even stranger than their obsession with interfaces. And by "they" I mean Java programmers, who seem to make up the bulk of this crowd.
The API for classes in an open source language is generally community driven, not decided by a corporation. Which is better? Gosh, let me think about that.
Huh?
[murphee ( http://www.jroller.com/page/murphee )] December 7, 2005 20:31:52.399
This weird obsession over the number of methods per class is even stranger than their obsession with interfaces. And by "they" I mean Java programmers, who seem to make up the bulk of this crowd.
What's *your* problem with Java interfaces? I don't see much difference between Java Interfaces and Smalltalk/ObjectiveC/... protocols. They're just a named list of methods; if a class conforms to that protocol/interface, then you know that it can do a certain kind of thing. (Let's not get into the whole discussion how method names don't describe behaviour...).
If you like: protocols/interfaces are like the much fame "duck typing"... except that you don't have to watch how the duck quacks and waddles and guess what it is... instead the duck carries a name tag that says, "Hi, I'm Scrooge. I'm a Duck".
The API for classes in an open source language is generally community driven, not decided by a corporation. Which is better? Gosh, let me think about that.
Huh? Which "open source language" are you talking about? Neither Java nor Smalltalk are "open source languages"...
Oh... and tell me: how is a "community" driven process better than "design by committee" (I guess that what allude to by "decided by a corporation")? The only way to get a proper language + APIs is to have a small team (or even better: one person) who does it, instead of a vast group of individuals that throw in their opinions and decide by consensus.
Open Source...
[ James Robertson] December 7, 2005 20:46:57.976
Comment by James Robertson
Well, Squeak is open source - and with Cincom Smalltalk, we ship all the Smalltalk sources - with commercial or non-commercial (which is free). Commercial customers get VM sources as well.
It's open, but not OSS
It's just an utterly false comparison
[Isaac Gouy] December 7, 2005 21:39:57.126
that's an assumption, not evidence
I agree, I agree, I agree.
As for evidence, let's go back to the source. Martin Fowler states "A good way of looking at the difference between humane and minimal interfaces is to compare the list components in Java and Ruby".
He goes on to note that "Ruby has an Array class (which is a list not an array)" but doesn't mention that Ruby's Array class is Ruby's Array and Ruby's Stack (pop/push) and Ruby's Set (intersection,union,set-difference) and Ruby's Queue (shift,unshift).
Martin Fowler then chooses to equate the instance methods declared in java.util.List interface with both class methods and instance methods implemented in Ruby's catch-all Array class, plus the 16 methods implemented in Ruby's Enumerable mixin. He mentions Ruby's "aliasing method names" but then includes the 5 alias names in his count of methods.
Is it reasonable to equate a Java interface with a Ruby class- why wouldn't we choose a Java class, java.util.ArrayList implements 23 methods and inherits 10 more from AbstractList and AbstractCollection.
Is it reasonable to equate a single Java class with Ruby's catch-all Array / List / Stack / Set / Queue class - when there are separate Java classes which provide Array, List, Stack, Set and Queue methods?
Martin Fowler writes "Both components offer the basic same service, but Ruby's array includes a lot of additional functionality." Is that true?
- Can you create instances of java.util.List?
- Is java.util.List intended to provide Set functionality or is that declared in java.util.Set?
- Is java.util.List intended to provide Queue functionality or is that declared in java.util.Queue?
Martin Fowler writes "Humane interfaces do more work so that clients don't have to" and then ignores the 19 classes that implement java.util.List or java.util.Queue (and the 7 that implement java.util.Set).
[John M McIntosh] December 7, 2005 23:49:53.457
Mmm open source smalltalk? Last time GNU Smalltalk http://www.gnu.org/software/smalltalk/smalltalk.html was "open source software" by any standard you wish to apply "GNU Smalltalk is a free implementation of the Smalltalk-80 language"
Bald silliness :-)
[John D. Mitchell] December 8, 2005 1:14:26.813
James, thanks for ending your comment with: "The rest of his post is actually quite reasonable - it's just that one thing I object to."
Yes, I elided plenty of examples and pointers to evidence that I could have added. Why? Frankly, I didn't see any need... Elliotte already pointed out one example and I linked directly to the documentation to those two classes for people to look at and see for themselves. For more why's, I've already added a comment to my original piece.
Another reason is that, as I tried to emphasize in my original piece, one of my main points is exactly that there is no a priori "right" answer. Everyone has to figure out that line for themselves and deal with the lines that others have drawn. Heck, that's the entire third act of my blog.
-
[Varoa] December 8, 2005 8:57:32.343
It's simply an elementary question about OO programming. An object represents ONE thing, not five million. Having a class that represents a stack a list and a queue is simply nonsense. Of course it can be argued that this powerful class will be more useful than Queue, ListX and Stack by itself, but following that argument we should compress java.util.* in a single class, ultimately we'd have a single class containing the whole java API, and someone might argue well, it'd be great to have the whole apache libraries added to it. Plain nonsense. That's the most elemental principle of OO programming. An object is an entity with its defining data and operations. A tree is a botany with branches and leaves, it can grow, it can move with air, it can die. That's it. It doesn't run, it doesn't, and it doesn't have wheels. If you need the Fintsones car, define your own class for it, but don't ask Tree to contain things that are NOT inherent of trees. The 78 method issue is nothing else than a consequence of this. When you have a 78 method class it's very likely (though not necessary) that your class it doing too much, and when something does too much means it's not a bit of information and its behaviour, it's not a single class.
Java Lists are from Mars, Ruby Arrays are from Venus
[erickson] December 9, 2005 16:20:44.037
I agree that part of humane programming is making it easy to understand coder's intent. In Java, that should be done by identifying the semantics of a collection with it's type -- unfortunately, too many people choose not to and use an ArrayList for when they really mean Set, Stack, Queue, Collection, etc.
In Ruby (sorry for the digression, Smalltalkers), how do you indicate that the Array is acting as a List rather than a Set? Is there a property that modifies behavior to be consistent with a particular subtype of collection? They do act differently; you can't be a correct list and a correct set simultaneously.
What I'm getting at is, IMO it's easier to see, "Oh, he's got a Stack here," than "arr.add(foo)... arr.remove(bar = arr.last())... okay, maybe he's using arr like a stack?"
Ruby Sets
[Piers Cawley] December 10, 2005 2:30:12.149
Personally, whenever I want a set in Ruby, I use the Set class. I get bored of using uniq all the time. Why is everyone obsessing on the Array class though?
Ruby Array was the example Martin Fowler chose
[Isaac Gouy] December 10, 2005 16:07:57.058
Piers, Ruby Array was the example Martin Fowler chose to support the contrast he wished to make between Ruby and Java.
He made the case that Ruby Array provided convenience methods where Java provided just a minimal interface. Martin Fowler chose Ruby Array "first" and "last" as examples of convenience methods - because we could use indexed-access instead of defining those methods.
I would agree with him, if Ruby Array was only intended to provide Array behaviour - in that case "first" really would do nothing more than alias "anArray(0)".
afaict Ruby Array is also intended to provide Stack behaviour (and Queue and Deque) - it provides pop and push. These are abstract operations, we don't care whether the "top" of the stack is physically the first or last item, we just care that pop and push both work the same end of the data structure.
One operation we might expect in a minimal Stack interface is missing - Ruby Array doesn't provide "peek" - and I think that reveals a simpler explanation for "first" and "last".
When we use Ruby Array as a Stack, "last" let's us "peek" at the top of the stack - "last" is part of a minimal "Stack" interface.
When we use Ruby Array as a Queue, "first" let's us "peek" at the head of the stack - "first" is part of a minimal "Queue" interface.
Java provides corresponding methods - java.util.Queue declares peek() and java.util.Stack implements peek() - so this example doesn't support the contrast that Martin Fowler wishes to make.