picture home | pixelblog | qt_tools

David Van Brink // Sun 2008.11.9 18:11

Basics: Where To Put A New Method

In “Where to Put A New Method” we’ll consider the question: “Where should I put a new method?” We’ll be considering several different collaborative topologies. Although I’ll describe this in terms of Java methods, the dynamics — both technical and social — are, perhaps, of general interest.

Basics: Where To Put A New Method

I Wish The Platform Had [Feature X]

Here’s a perfectly reasonable idea for a bit of functionality: “Please write out this file unless the file already exists and has the same contents.” This is so you can write out a file, but not bump the timestamp if it’s going to be identical to the existing one.

In Java, you might reasonably wish that the File object had that method. That would be neat.

  /**
   * I wish we had this!
   * Write the file unless the existing one is the same.
   * @param String new contents for file.
   */
  public void writeIfDifferent(String newContents) {
    //...
  }

Sure, you think, everyone would love that. But the fortunate fact is that you can’t add it to File. That class is part of the platform and because you’re not one of the authors of Java, you just don’t have access to alter it. And this is probably a good thing. Someone owns the design of that class, and they have a vision for it, better considered than yours or mine. This proposed new method should only be added if they accept it. So put your request on a postcard, mail it to the North Pole, and wait.

Meanwhile, you need this functionality today. It’s really quite simple to implement. Create a class like so:

import java.io.File;
public class ThingsIWishJavaHad {
  /**
   * Write the file unless it would stay the same.
   * @param file
   * @param newContents
   */
  public static void writeIfDifferent(File file,String newContents) {
    //...
  }
}

This is an easy choice because it is no choice at all. Altering File simply isn’t an option. In the next section there is a more challenging moral dilemma.

(Hopefully, it’s clear that the static method is preferable to extending File. If we created our own class, BetterFile, we would have to use it throughout our code base to get these small additional features. The static method can be used directly. If you gave that static method to your friends, they could use it without changing their variable types.)

I Wish Your Library Had [Feature X]

Now let’s turn our attention to typical corporate software development. If you’re developing some software it’s quite likely that you rely on some in-house software libraries. Just because you can call up the owner doesn’t mean you can get everything you want! I have it on good authority that most employees at Sun can’t just go and add a method to File.

(Corporate cultures are wildly diverse. I’ve seen environments where anyone was allowed to change anything, and there was a presumption that, well, I guess everyone’s a professional, and if they typed commit it must be OK. In small organizations this may even work, but generally it is dysfunctional.)

Let us concoct an example. Let’s say you’re working at SmogCo, maker of SmogBooks, a publishing system. You are developing a processing tool for SmogBook documents, for a special Florida-based client. Naturally you’re building up your specialized tool using the SmogBook Java library from the main development team. The special client needs a feature to add oranges to every page. (Look, it’s just a f’rinstance, OK?) Naturally, you realize that smogbook.addOrangesToEveryPage() is too limited. What you really want, of course, is:

  public enum Fruit { ORANGE, APPLE, CHERRY } // we'll add more later!
  public void addFruitToEveryPage(Fruit pageFruit)
  {
    //...
  }

Brilliant, you think! Every SmogBook developer can leverage this; we do deal with agricultural clients a lot, come to think of it.

Now comes the moral dilemma. In many corporate settings, the revision control system is wide open. Furthermore, in many corporate settings the boundaries of code-ownership are not well-specified. So what do you do?

(Truly, in matters like this, there is great opportunity to witness, and participate in, classic social dominance games. And indeed, we should be grateful that our species has, largely, found an outlet for these tendencies in such harmless pursuits. But that is a topic for a different essay.)

You could just check the method in and hope that either everyone likes it or nobody notices. If your change is good, and you pull it off a few times, you could just wind up on the core development team as a result. But it’s far more likely that, even though it consumes your working hours, this “add fruit to every page” feature just isn’t of general interest. It’s human nature to see our immediate goals as globally important, but it’s good architectural sense to realize that they aren’t.

So I’ll have to advise that, instead, you create a tiny local implementation of the fruit feature, like so:

public class SmogBookFruitUtils {
  public enum Fruit { ORANGE, APPLE, CHERRY } // we'll add more later!
  public static void addFruitToEveryPage(SmogBook book,Fruit pageFruit) {
    //...
  }

By all means, show it to the core development team. They’ll be pleased to see their API and classes understood and used. Naturally, they don’t want to add just any old thing into their precious libraries: adding something in is a permanent support burden! But now they’ll know that at least one client needed the fruit feature; and if it’s a truly necessary feature, they’ll want to add it to the core library. And you might yet end up on their team.

I Wish My Library Had [Feature X]

And now we come to the third and penultimate challenge. We’ve covered Man Against Nature, and Man Against Man. Now we’ll examine Man Against Self.

If you yourself are maintaining a library, and you need a new feature, where do you add it? You have to ask yourself very carefully: Is this feature consistent with the vision of the library? If you add strangely asymmetric features to your library, it will become messier and harder to use. It may even feel less professional to others who are evaluating and using it.

Maintaining architectural clarity while developing and using your own libraries requires you to play both roles, that of invader and defender. As with libraries written by strangers and by peers, the safest place to add a new feature is somewhere else. If it proves out, promote it into the library.

They Wish My Library Had [Feature X]

And eventually, inevitably, you yourself will be providing core libraries, and you will have fans of your library, which I’ll here call users. And now they want features. Oh, how they do go on about how they wish things were different. What can you do? I can offer several bits of advice.

First, accept that these users, as troublesome as they are, are your friends. When you hear complaints you know you’re on to something useful. Trust me.

Keep an eye on the revision control system. Your users mean well, but that doesn’t mean they know what they’re doing. If they change your code, look at what they’ve done, and decide if that’s how you would do it. If not, you have a professional obligation to roll out their changes and advise them of a preferred solution. If the change is good, put a little gold star next to their name on the secret score sheet. Bring them into your team when you can.

Listen carefully to your users. They’ll ask for many things. What you should give them is almost never what they ask for. It’s your job to tastefully refashion their requests into beautiful elegant solutions.

To do this, you must know where to put things.


(c) 2003-2011 omino.com / contact poly@omino.com