A few days ago i was adding some extra logic to one of the modules that i’m maintaining. Unlike the UI-related modules, this one has quite a few test cases that test various rules (about 110-120). And so, as i was adding some code, i caught myself thinking this – instead of proofing the conditions in my head (or on paper) before writing the code, let me just go ahead and write something that looks like it’s a correct thing to do and wait for the test cases to tell me if the code is correct or not. This is wrong on so many levels, and thankfully the test cases that went through this path failed. But this just underscores the imaginary safety in the test-driven development.
Going back about 20 years, the programming practices were much more robust (this doesn’t necessarily mean that there were fewer errors in the resulting code). In most development environments, you had one big mainframe computer and you had your “slot” every few hours to run the latest version of your code. And so, you had to be pretty sure that you ironed out all the obvious bugs before your slot came up, because the next time to check the fixes would only be in three or four hours. The end result is that even with the “harmful” goto statements, spaghetti code and lack of formally defined design patterns, the developers just sat in front of their hand-written (or printed) code and traced all possible execution steps before sending the code to the computer.
Since then, the hardware has become so cheap and powerful that the present generation doesn’t even think about “save-compile-run” cycle anymore. With incremental compilation in Eclipse, you don’t even notice that the code is being compiled (unless you touch code that affects a lot of other places). And so, you might find yourself rushing to code before properly thinking about the design and all the flows. This is especially painful with the test-driven development and agile practices that encourage this style, that i call lazy programming.
I previously referred to this as the imaginary safety in the test-driven development. As long as all the tests pass, the software is working as it should be. Don’t worry about the dynamic typing and the problems that could only be found at runtime – if you have good test coverage, you’ll never get these problems. Which brings me to the question – what is a good test coverage?
Of course, we have these nice tools such as Clover and Emma that produce visually appealing coverage reports. Once you get 100% of the lines covered by your unit / integration / … tests, you’re done, right? Not so fast, and this brings me back to the topic that i studied for quite some time during my last two years in the university – formal verification.
This is quite an interesting and challenging field – given the definition of a problem and a solution, decide whether this solution really solves the problem. This works really nice on hardware (especially VLSI), and is in fact an indispensable tool for verifying the hardware chips (in fact, the FDIV bug is pretty much the only significant commodity hardware bug i heard of in the last ten years). While some of the techniques work on finite-state automata, others have been extended to handle parametrized and infinite domains. However, this still doesn’t scale well from hardware to software.
Unless we’re talking about primitive programs, the problem domain is infinite. And this is especially magnified nowadays with the shift to multi-core systems and distributed faulty environments. Just having 100% line coverage doesn’t mean anything. Not only that, but for more complicated systems you might have a hard time coming up with the correct test cases (expected results); while this is true for the traditional upfront design, it is even more so for the agile “refactor as you go while we can live without explicit business behavior” techniques). “All my tests pass” means exactly that – “all your tests pass”. Nothing less and nothing more. You can cover only so much of the infinite domain with a finite set of test cases.
Not all is lost, of course. Don’t blindly rely on unit tests and code coverage. Think about the code before you start pounding on the keyboard (and hopefully, before you start pounding out those test case skeletons). An interesting approach has been explored in the last few years which tries to address the “state explosion” of real-world programs (applied successfully to the Firefox Javascript engine to find 280 bugs). This, of course, places even more burden on the test layer; since the test cases are randomly generated, it needs to provide a way to save failed test cases and rerun them later for a reproducible scenario.
While the Wikipedia entry on duck typing is quite thorough, Dave Thomas has a much more succinct and simpler definition:
In Ruby, types are defined as the capabilities of objects.
And that is a very interesting definition. Unlike with strong statically-typed languages (such as Java), Ruby doesn’t care about the actual type of the object being passed to a method, as long as it has all the methods that are used in that specific context. Leaving the relative merits and shortcomings of this approach aside for another entry, is this something that can be used in Java? Or, more interestingly, is it something that is used in Java? The answer is quite simple – yes. And not in third-party code; in the JDK itself.
The first example will be the Serializable
interface. This is an odd duck (quack quack :). On one hand, it is a marker interface since it has no methods. On the other hand, classes that require special handling during the serialization / deserialization must define implement special methods with these exact signatures:
private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException;
private void writeObject(java.io.ObjectOutputStream stream) throws IOException;
private void readObjectNoData() throws ObjectStreamException;
At runtime, the ObjectStreamClass
uses reflection to query the actual object to see if it has these methods. If it does, they are used (once again, using reflection) instead of the default (field by field) behavior. The reason behind having the Serializable
interface empty and the method signatures “magic” is, quite frankly, not apparent (you’re welcome to shed more light in the comments). What would happen if these were defined publicly in Serializable
(and had empty implementation in a hypothetical SerializableAdapter)? It’s not that suddenly anybody would gain access to the internals of the specific object. Calling writeObject
directly is the same as creating an OutputObjectStream
and calling writeObject
on it. Not only that, even with the current “duck” implementation you can use reflection to query these methods, set them to accessible and call them. A minor annoyance in having all these methods in the Serializable
interface would be that you would have to implement all of them if you already extend some other class.
The second example is the UIManager.getUI
method. This is where it gets even more complicated than the serialization. To create a UI delegate for a specific component, the implementation first looks up the classname of the UI delegate in the table set up by the current look-and-feel. Then, it uses reflection to call the “magic” static createUI
method that must have a single JComponent
parameter. This method is then called to create an actual UI delegate. Interestingly enough, this elaborated lookup is not really necessary. The code can be made compile-type safe by using a simple factory that returns UI delegates based on the passed component; just as the look-and-feel fills the lookup table (UIDefaults
), it can use the same “switching” to create the UI delegates. The issue with handling third-party component suites such as SwingX or JIDE can be easily addressed by providing an API on the look and feel class that allows installing lookup extensions. This example is a little further from the “pure” duck typing in that it returns a ComponentUI
object. This is, of course, not strictly necessary since the relevant code can use reflection to call the methods declared and implemented in this class (which could be quite tiresome, but certainly doable).
There are a few other places throughout the JDK code that use reflection – notably for beans, JMX, a few XML parsers and even the <a href="http://java.sun.com/javase/6/docs/api/java/lang/Class.html">Class</a>
class itself (in the <a href="http://java.sun.com/javase/6/docs/api/java/lang/Class.html#getEnumConstants()">getEnumConstants</a>
) method. And so, the next time you hear somebody mentioning duck typing, know that this technique is not restricted to dynamically typed languages.
What thoughts go through your mind when you look at the code that you have written a few years back? I don’t know about you, but for me it’s mostly unease. Over the time, as we refine our coding style, learn new techniques or even new languages, we tend to view our current coding practices as the best it can get. Objectively speaking, this can hardly be true.
First of all, if you’re looking at the code that you wrote five years ago and smile condescendingly, how can you be so sure that the same won’t happen five years from now? Just because you’re using the best development techniques du-jour (be it agile, scrum, iso, cmm, web services, …), the best languages du-jour (erlang, ruby, factor) or the best design patterns du-jour (inversion of control, …), does it mean that they are really the best? Hardly, especially given the volatile state of software development. Sure, you can say, back then i was this wide-eyed fresh-out-of-college junior dev, but now i’m an experienced developer with tens or hundreds of thousands of lines under my belt. Does that mean that you’ll be standing still over the next five years? Will you be using the same development techniques, tools, languages or even hardware in 2012? It works the same even for language theorists that find the existing concepts dated and inconsistent.
Second, you will always have bugs. And this is a Good Thing™ and you should make it as easy as possible for your users to report them to you. And if Neal Gafter can blog publicly about a bug in the core JDK code, it only means that nobody is perfect. You can have all the experience in the world, and you will still write buggy code. And as time goes by and simpler bugs are found, it means that the bugs that are left are much harder to detect and reproduce. The code you’re writing today has bugs. As did the code you wrote five years ago. As will the code that you will write five years from now. The only way your code will not have bugs is when you don’t write any code at all.
Now, the only real advice i can think of is simple – don’t get attached to your code. It might be clever, it might be beautiful and it might even work the first time you run it (and this is a Bad Sign™). Once you get attached to it, it becomes much harder to objectively respond to bug reports filed against it. It becomes much harder (especially when you’re working with a team) to argue about its deficiencies or even agree for it to be replaced / removed altogether in favor of some other implementation. It is especially painful when junior developers have to maintain the pile of code that you have written a few years ago, and your current architect / senior dev ego doesn’t let you acknowledge a simple fact – that it is completely unmaintainable, impossible to understand and very painful to extend.
Instead of projecting yourself on the code, project the code on its users. Does it do what the users want? If it does, who cares about how it does it? If it doesn’t, nobody will use it and nobody will care how clever / beautiful / smart it is.
You should really be careful when you’re using anonymous stock models to promote your product. Take, for example, Sun Java Composite Application Platform Suite (don’t even get me started on the name that says absolutely nothing). Here is the banner that greets potential customers:

I don’t know about you, but instead of thinking about that miniature tree growing in what looks like a soup bowl, all i can think of is the following dialog from Seinfeld:
Jerry: Oh, volunteer work!. See that’s what I like about the holiday season. That’s the true spirit of Christmas. People being helped by people other than me. That makes me feel good inside. Look at what we have here. A Christmas card from Laine. You didn’t have to go to all that trouble.
Elaine: It was no trouble. My assistant did the whole thing.
Jerry: I didn’t even see the picture. How did it come out?
Elaine: Well, you know. It’s a picture?
Jerry: Oh yeah. Look at that. Looks good. Kramer did a good job.
Elaine: Yeah, well. How hard is it to take a picture?
Jerry: … um …
Elaine: What?
Jerry: Did you look at look at this picture carefully?
Elaine: Carefully?
Jerry: Because I’m not sure and and and correct me if I’m wrong but I think I see … a nipple.
Elaine: What?
Jerry: Here. Take a look. What, what is that?
Elaine: Oh my God! That’s my nipple.
Jerry: That’s what I thought.
Elaine: That’s my nipple. My nipple’s exposed. I sent this card to hundreds of people! My parents. My boss. Uh, Nana and Papa.
Jerry: DIDN’T YOU LOOK AT THE PICTURE?
Elaine: Oh God I didn’t notice. Oh, what am I going to do? You know your whole life you go through painstaking efforts to hide your nipple and then BOOM, suddenly hundreds of people get their own personal shot of it.
Really, a headless torso with a couple of fake tattoos and a hairy nipple? For more examples of stock model goodness click this link (warning, it’s rude and hilarious).