Monday, August 25, 2008

Checked exceptions exposes implementation?

I've read and heard the phrase Checked exceptions are evil! They expose implementation details! a couple of time (last time was an entartaining read for several other reasons...). I really don't understand this statement (hey, you, explain to me please).

How can the EncodingException part of the code below expose implementation details when void encode() does not? The first say I can fail to encode, the latter say I can encode. What's the difference?
interface Encoder {
  void encode(Object o) throws EncodingException;
}

For me, checked exceptions are vital to enforce proper error handling. But this can (probably) only be achieved if the exceptions fits the problem domain. For instance, throwing an IOException in the interface above would be really really bad because it exposes details of the Encoder, e.g., that is uses the network, or whatever. On the other hand, the only thing EncodingException exposes is that an Encoder can fail to encode the provided object. That's not an implementation detail, I think, that's the Encoder being honest and not hiding it flaws.

One of the most important lesson I've learnt from using exceptions is the importance of doing try-catch-wrap-throw. For example, if an implementation of Encoder uses a method that throws IOException then the proper way of handling such exception is to catch it, wrap it in a EncodingException and throw it to the client of the Encoder. This cleans up ugly interfaces that throws many exceptions, resulting in clear description (with semantics, yeay!) of what can go wrong when a method is called. Exceptions that fits the problem domain is the key.

A couple of times I've let domain exceptions inherit from each other to define that, for example, a RangeException is a ConfigurationException. This seemed like a good idea to me at the time, however, it seldom helped the design (it didn't make it worse either, though). In fact, the only time I find it useful is when you need to distinguish between thrown exceptions in one place but handle them in the same way in a nother place. For example (where LeftException and RightException inherits from BaseException):

interface Something {
  void doIt() throws LeftException, RightException;
}

class HandlesExceptionsSeparately {
  void method(Something s) {
    try {
      s.doIt()
    } catch(LeftException e) {
      // handle it
    } catch (RightException e) {
      // handle in another way) {
    }
  }
}

class HandlesExceptionsTogether {
  void method(Something s) {
    try {
      s.doIt()
    } catch(BaseException e) {
      // handles both
    }
  }
}

But as I said, this is not very common for me. Although if you are developing a library and wish the user to have the ability to handle the different error-cases separetely, then could be useful.

Well, these are some of my thoughts on checked exceptions. In summary: I think they're good stuff if done well. :)

Sunday, August 3, 2008

Fear and Loathing in Parse Vegas

Martin Fowler writes about parser fear and I have to say "guilty as charged". I've done a few DSL but all have be so simple that I could hand-write a parser using regular expressions and other string manipulations. To be honest, the resulting parser would probably be easier to understand, maintain, etc, if it was developed using a proper grammar and a parser generator. Despite (knowing) this, I kept writing those convoluted hand-written parsers.

I did the compiler class at the university and I'm intressted in most things programming langage related, e.g., compilers and parsers. Despite this I never actually done a parser (with proper grammar) by my self. Why? I had parser fear.

Fowler writes:
So why is there an unreasonable fear of writing parsers for DSLs? I think it boils down to two main reasons.
  • You didn't do the compiler class at university and therefore think parsers are scary.
  • You did do the compiler class at university and are therefore convinced that parsers are scary.

I think the last bullet explains why I never did a proper-grammar-parser by my self.

However, the last time I had to write a parser I (finally) realized that a proper-grammar-parser was a better idea than trying to hand-write something convoluted. The parser should be implemented in Ruby, so I googled (is that a verb now?) and found a generic recursive decent parser -- all I had to do was to write the grammar, which was straight forward.

There were several resons that finally made me take the step to use a proper parser:

  • The language was complex enough to make my old approach unsuitable
  • The parser was really easy to integrate with my other Ruby code
  • No separate step for generating the parser (i.e. short turn-around time, and less complexity because there is no code generation)
In essense: it was easy to use and test. That was the cure for my (irrational) anxiety towards parsers.

Thursday, July 3, 2008

Lessons from a debugger

A few days ago I got undefined method `some_method' for nil:NilClass when I executed a test-case I've just had written for a quite well-tested class. The test-case tested input that the class hadn't been designed to handled, but now I needed the class to handle it.

Knowing that there was a suit of test-cases making sure I didn't break anything, I just added return if (!thing) (where thing is the object the some_method was called on) and run the suit again. And gues what? All test-passed -- including the one I just written that didn't pass. I wrote another one testing a similar scenario and it also passed. I was satisfied.

Why did I add that nil-check? Well, the error appeared deep in a recursive call-chain, and I simply guessed that the recursion should be stopped if thing was nil. I didn't know -- I just guessed.

The point is that I didn't have to know, because if I was wrong any of the class test or multi-class tests would tell me I was. This is all good right? Well, it's not all good. Why? I'll tell you in a moment.

But first, think about a hard problem that you solved by putting in more effort than usual -- persuading someone to test more, parsing a proprietary file format, writing C++ or reading Perl -- any hard problem will do. I'm pretty sure you learnt something really valueable from that experience (even though it didn't feel that way while solving it...). I'm sure we learn a lot from solving any problem by putting in more effort than ususal.

Now, back to my story about the nil fix that made the test-case pass. What did I learn from fixing it by adding a line that I simply guessed should be there? Zip, nothing, ingenting. Of course, this shows that well-tested code is a Good Thing, but this isn't news to anyone. (By the way, note that a Good Thing isn't trademarked, registered, closed-sourced, or anything like that. Its free to use and I encurage you to do so as often as possible. :) Of course, any improvements you make to a Good Thing have to be shared with the community.)

On the other hand, what would I have to do if the class was poorly tested? I would have to understand what the code did by reading, test/run it by hand, debug it, etc, before I added the nil-check. Then I would have to repeate the process to make sure everything worked as before. What would the outcome of all this work be? Probably the same nil-check as before, but I would also understand the code much better. Also, I might picked up some good design ideas, learnt to use the tools better, etc.

Now, I'm not saying that poorly tested code is good. What I am saying is that working with poorly tested code that forces you to fire up the debugger and step through the program will make you debug programs better. I'm saying that working with deep inheritage hiearchies will make you realize that inheritance isn't always a good thing. I'm also saying that reading code with a lot a mutable instance variables and class variables will make you appreciate (and use) 'final' or 'const' more.

To take this a bit further, I think you actually get worse at debugging if you developing in an environment where the code is well-tested, because you never have to debug anything. This is true for me, at least.

I've completely stopped using the debugger. I write test-cases that narrow down the problematic code instead. This combined with a few print-outs is all I need. I think this is easier, and more valuable in the long-run because my efforts are mirrored in a few test-cases that document that there was a bug that was fixed. Would I simply had fired up the debugger and found (and fixed) the problem, there would be no (exectubale) documentation of the bug-fix.

So, one way of becoming a better developer is, I think, to improving quality of untested code because it'll forces you to reason about the program and it's control flow based on scarce information (e.g., logs and stack-traces) among other things. On the other hand, working with well-tested code is much easier: write a test, make the change you have to make to the production code and run all tests. Do they still pass? Great! Code is ready to be checked-in. Good for the project's progress. What have you learnt? Nothing! Bad for you. In some sense.

Wednesday, June 25, 2008

The Blub paradox

Yesterday I read someting interesting concerning how programming languages are compared:

«[T]o explain this point I'm going to use a hypothetical language called Blub. Blub falls right in the middle of the abtractness continuum. It is not the most powerful language, but it is more powerful than Cobol or machine language.

And in fact, our hypothetical Blub programmer wouldn't use either of them. Of course he wouldn't program in machine language. That's what compilers are for. And as for Cobol, he doesn't know how anyone can get anything done with it. It doesn't even have x (Blub feature of your choice).

As long as our hypothetical Blub programmer is looking down the power continuum, he knows he's looking down. Languages less powerful than Blub are obviously less powerful, because they're missing some feature he's used to. But when our hypothetical Blub programmer looks in the other direction, up the power continuum, he doesn't realize he's looking up. What he sees are merely weird languages. He probably considers them about equivalent in power to Blub, but with all this other hairy stuff thrown in as well. Blub is good enough for him, because he thinks in Blub.

When we switch to the point of view of a programmer using any of the languages higher up the power continuum, however, we find that he in turn looks down upon Blub. How can you get anything done in Blub? It doesn't even have y.

By induction, the only programmers in a position to see all the differences in power between the various languages are those who understand the most powerful one. (This is probably what Eric Raymond meant about Lisp making you a better programmer.) You can't trust the opinions of the others, because of the Blub paradox: they're satisfied with whatever language they happen to use, because it dictates the way they think about programs.»


Check this out to read more about how to evaluate programming languages.

Wednesday, June 4, 2008

LISP's mapcar for Java: onAll-collect

I've been working on a project were I need to iterate over a set of objects, get some property from all objects in the collection, and store that property in a new collection. This wouldn't be much if an issue if I did it in LISP or Ruby or some think similar... but this is done in Java with th the java.util.Collection framework. The Collection framework is nice and all, but when I have to write:


List<SomeProperty> allProperties(List<SomeClass> objects) {
  List<SomeProperty> properties = new ArrayList<SomeProperty>();
  for (SomeClass c : objects)
    properties.add(c.getProperty());
  return properties;
}

when all I really wish to say is:

(defun all-propreties (objects)
  (mapcar get-property objects))

I get a bit sad. Sure computer technology is progressing, but are computer languages? LISP appeared in the late 50-ies and Java in the mid 90-ties, but looking at the code above I can't really tell that there is almost 40 years between these two languages. Crazy...

Anyway, to make me a bit happier I started to think about how the Java code above could be improved to make it a little bit more terse. What I came up with was this:


List<SomeProperty> allProperties(Bag<SomeClass> objects) {
  return objects.collect(objects.onAll().getProperty());
}

which I honestly think is pretty neat. Then again, I'm just an ape-descended life form who are so amazingly primitive that I still think digital watches are a pretty neat idea too.

How does this work? Well, first of all the objects variable is not the same type in the two Java examples above. In the latter example, it is a class that I've implemented specially to deal with the scenario described. This class, which is called Bag<T>, has a method onAll(T) that returns an dynamic proxy implementing the T interface. That is, in the example above the objects.onAll() returns an instance of the SomeProperty interface.

This dynamic proxy handles every method call it receives by calling that method on each object in the Bag. Also, if the called method is non-void, then it returns whatever the last object in the Bag returned. This means that bag.onAll().someMethod() behaves just as thing.someMethod() if bag contains just the thing objects. This is a Good Thing in my book. :)

How about the Bag.collect method?, you ask. Funny you should ask that. I was just getting to that, I reply. Cut to the chase already!, you say. Cool it, I say, or there won't be any desert!.

(Ok, I'm getting a bit carried away.)

The Bag.collect simply returns the set of return values got when last calling a method on the onAll-object. Ehm, it a bit hard explain with words... but I think you understand. If you don't, look at the code and test-cases. :)



Note that the onAll method returns an object that can be used for more than what's described above. Whenever you need to treat a set of objects as if they were one object, for instance the Observer pattern, the onAll-object simplifies alot.

Tuesday, May 20, 2008

What makes a class?

A few days ago, when I was "merrily" washing my dishes, I started to think about what makes a class necessary. That is, how we could identify code that should be placed in a class. I came up with a few obvious cases, and some less obivous. Obvious:
  • a new domain entity is needed,
  • to simplify testing,
  • remove conditional logic and special cases,
  • remove duplicated code,
  • move private private methods of a class to a new class; and
  • split a class that has multiple responsibilities.

Yeah, I know, ob-vio-us... But as I said, when I joyfully made my forks and spoons clean and shiny, I found a couple of cases that are commonly ignored or missed (at least by me, until now):
  • there are recurring patterns in variable names and variable type, e.g., java.nio.ByteBuffer payload = ... indicates that there is a need for a Payload class,
  • circular dependencies between classes can be solved by introducing a new class, e.g., if Alice and Bob has references to each other for exchanging messages, then a Channel should be introduced that they both will use to send and receive messages;
  • an exception exposing implementation details should be replaced with a new exception mathing the abstraction level of the class/method throwing the exception,

A comment on classes that solves circular dependencies: it is possible to solve this kind of dependency by simply introducing an interface (e.g., Alice and Bob could implement a MessageReceiver interface), but this misses the point a wish to make. By introducing a new class instead of an interface, domain logic can be placed where it is more suitable (e.g., the Channel can take care of serializing the messages passes between Alice and Bob).

Anyway, these are a few ways we can use classes to simplify code by introducing additional classes. There are probably a lot more... :)

Oh, by the way: some exceptions in the packages java.... miss a SomeException(String description, Throwable cause) constructor. Why is this? It makes catch-wrap-rethrow really hard. This is very important for hiding imlementation details.

Furthermore, why are there no proper hiearchy for (example for) the exceptions thrown by the reflection mechanism? I hate to catch four-five exceptions every time I do something with reflection... NoSuchMethodException, SecurityException, NoSuchFieldException, InvocationTargetException?! Come on! Why can't I just catch ReflectionException and get it over with? Also, give me multi-catch so that I can catch more than one Exception in each catch-block. Please!

Well, who ever said Java was perfect? Or even close to perfect...

Wednesday, May 7, 2008

Do not write tests for your code!

I am of the opinion that developers should not write test for their own code. The reason is that the tests just test that the production code does what it does -- not necessarily that it does the right thing. That is, the tests just "mirrors" the production code. In fact, the test can actually test the wrong thing entirely!

On the other hand, if someone else writes the tests, then he/she does not know any details about the implementation, thus the tests do not mirror the production code.

Of course, there are problems with this... how does the tester know what the code is supposed to do? Good documentation? The trouble is that the documentation will (probably) describe what the code does, not what it is supposed to do. Why? Because it (probably) written after the code. Also, to use an understatement: documentation is boring.

The point I'm trying to make is that it is very hard to express what a piece of code is supposed to do when that code is already written. Unless, of course, there are a few test-cases for that piece of code. To my experience, test-cases describe what code is supposed to do very accurately.

Ok, I think you get where I'm going with this so I'm just going to cut to the chase. I hope you are of the opinion, like me, that developers should not write test for their own code. They should, however, write code passing their tests.