it should be obvious how to use it

I just thought of this, as I sat contemplating an issue I’m having at work. The issue, without getting too much into detail, is about the best practices for designing a certain pluggable component of a larger framework. As with much of the OO C-descendant world, the component is defined by an interface that someone implements, and the question has arisen, “How do we tell somebody to write one of these?”

The problem is, really, a few things. These apply in a very general sense, so you’ll have to forgive my letting the details escape.

First off, the interface is really abstracted. It’s one of these things where you, say, think of all the many ways you would want this piece to supply information to the rest of the world. Then, you make generalizations on top of that. Then some more, and more, and finally you are left with one method.

Now, I’m not saying that boiling the functionality of a piece of, well, whatever, down to a function is an entirely horrible thing. I’m sure there are many cases in which that would be useful and all, but, in this case, the manner in which the piece responds to and supplies information to the rest of the world really cannot be abstracted to “well, it does something. yeah.”

The problem we are having is that there is a certain way we want people to write components, or at least we think there is a certain way it should happen. By should, I mean the sensible default, as in you really could do it in a much different way, but we think this way is the best combination of efficiency/simplicity/asynchronicity/etc. The problem is that, in reference to the interface, it is entirely non-obvious.

I’m pretty sure that in Joel Spolksy’s book on UI design, he describes how things should be obvious to use, in a couple of ways. In terms of interfaces, they should look like people expect, and the paradigms should make their use obvious. This is really sensible design in the most general case of designing, whatever that is. I do remember an example of a camera that he gives, explaining that a certain camera was constructed in such a way that it begged for your left thumb to be placed just like this, which had the wonderful side-effect of keeping your left hand out of the way of the picture (I wish Canon had been thinking of this when they designed my PowerShot A530).

This type of advice applies to designing interfaces as well. When I look at an interface, it should be immediately obvious just what the intended use case is. Specifically in the case of computer science, it should be a combination of how this piece interacts with the world (and how I would interact with it), and also how I would write this piece. In our case, this is where I am struggling with the best-practices stuff.

You see, there should be no such thing as a best-practices document. Really. I mean it.

Take this example: most linked list implementations, the most obvious for me (at this late hour) being C#’s LinkedList, don’t have an index operator.

But why? It’s not like it is impossible to find element i. It isn’t horrible, and it can be computed. So why not?

The problem here is related to the idea of IEnumerable or Iterable or whatever-you-call-it and for-each type loops: in most cases, people just want to go through a collection from beginning to end. In fact, most people use a list or array or some other type data structure when really they don’t need random access. You may not realize it, but you can end up paying a lot for that when you don’t need it.

So why not provide random access for linked lists? Because people would use it, that’s why. And because it doesn’t have the same semantic meaning as it does for an array-type list.

If C#’s LinkedList had an operator[], I guarantee that somebody would put it in a for-loop. And why would they think otherwise? Why not? It looks and acts like the same thing on a list? Should I not use that one?

And so we create a best-practices document, that says, “Well, this method is really bad, so you shouldn’t use it. I mean, it was convenient for us at this juncture in time, but you should really steer clear.”

But you know what says “don’t use this” better than any document?

Not including it at all.

And that’s the message here. It should be obvious, just by looking at a thing, how you should use it. When I look at LinkedList, I see that it is enumerable and I see that I cannot get random access. I know that I could write it myself, but I see how intolerably slow that would end up being. If I need random access, I find a different data structure to provide that.

The point is that each and every interface you write as a programmer or as a designer should be meticulously created to be, more than anything else, obvious. If you add extra methods on there for convenience of a special case in a special time, you lost the right to tell anybody else not to use them. In fact, you never, never, never have the right to create an interface but then say, “well, but don’t use this part. Please.” “Deprecated” isn’t a magical word that gets you out of the doghouse when you failed design school.

I mean, we all do make mistakes. I can think of things I’ve written in haste, for my own use , more rationalizations, etc., that aren’t well designed. But it doesn’t matter, right? Nobody else is gonna see it or use it or whatever.

You can’t always guarantee that, though, especially if you are writing framework code that will be used by millions. You don’t have the luxury of “I’ll just fix it later”, and nor should you. The second corollary here is that you should always take the time to do it right the first time, just as you should always take the time to do it the first time.

Code isn’t something you shit onto a computer. It is something you create, like a craftsman creates a beautiful piece of furniture, or a dreamer creates an articulate piece of poetry. You shouldn’t treat it like anything else.

I don’t know where this came from, but if you come up with a good attribution, please, let me know:

I once had a chance to speak to a blacksmith as he carried on his daily work. A horseshoe here, some other, sharper acoutraments there. At one point during the day, I watched as he slaved over a small, curved piece of metal, intended to be placed on the undercarriage of a wagon.

I said to him, “Why do you take so much time on a piece the goes underneath? Does it matter if it isn’t exactly straight, exactly flat, pristinely made? Nobody will ever see it!”

He smiled sadly towards me, saying only, “But I will know it is there.”

  • http://gatacoma.wordpress.com Stump

    I see your point here, and I also believe that code should be intuitive and obvious to the developer using said framework/collection/whatever.

    I also find a good bit of truth in the likening of coding to other arts. I’ve always thought that, but I couldn’t really articulate the thought in the manor that I wanted.

    However.

    I have an issue with this bit of text here (I don’t know if HTML tags work here, but I’ll try it):

    You can’t always guarantee that, though, especially if you are writing framework code that will be used by millions. You don’t have the luxury of “I’ll just fix it later”, and nor should you. The second corollary here is that you should always take the time to do it right the first time, just as you should always take the time to do it the first time.”

    This seems to me that you’re saying that people always have the time to do it totally right the first time.

    While this would be ideal, I don’t think many developers are given the chance to do it totally right the first time. Deadlines come and go, and sometimes you have to let something sub-par go. It’s crappy, and it happens, but I doubt that anyone would do it intentionally.

    Maybe I’m naive and think people as a whole would like to make their projects and work as of high a quality as possible.

    Like you said, the things I code are my craft. I sincerely hate to let anything lacking in any way be released from me. The sad part is, which I’m sure you’re familiar with, is that sometimes it’s just impossible. Given enough time, I could take most any of my projects (at school or work) and make it better. However, that whole time thing is just so damn elusive.

    I’m sure I’m preaching to the choir on this, and I’m completely sure it’s all stuff you’ve heard and gone through before. I just felt that this should be said.

  • http://noahsmark.com noah

    You are absolutely correct that occasionally we are forced, via deadlines, to act more quickly than we would like. However, the problem is much more insidious than this, as it really does apply to more than just software.

    We (as humans? as Americans? who knows) are traditionally bad at making cost/benefit analyses that span more than 20 seconds. Most managers get about a factor of 10 past that, not because they are stupid people, but just because they are bad managers (i.e. have not read Peopleware).

    The extra 20 minutes you would spend thinking through an interface the first time will save you plenty of time down the road, plenty of time that you can use to make other decisions correctly. In the long-run, by which I mean a week or longer, you end up taking less time, even on the same product in the same product cycle, because you decided at the outset not to make stupid decisions in the name of short-term gain. We are a culture of immediate result, and it may be hard to escape that, but we, as good designers, must always take the time. Always.