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.