Tuesday, September 13, 2011

Communicate code intention I: Nulls

It's all about communication... Really!

As programmer one thing you do is to communicate with the computer so it does whatever you want.
However the computer isn't the only one you interact with. Your code is is something you tell to the computer and the team. Is communication of actions and intentions what makes the computer do things.
And this is the key part of the communication: intentions.

While the language of your choice may be able to communicate some intentions very explicitly, some others don't. This is where you should put your effort. Communicating your intentions is essential for your team and for your future self. Yes, you think you will remember but you won't.
The more you code, the lesser the probabilities are you will remember what was the intention of each line.

So, how do you manage to communicate all the implicit decisions and knowledge that is used on the code? You don't! Because you cannot reflect all the implicit decisions. But at least, you try to express as much as is useful for you and your team.

Use annotations to communicate expected behavior with nulls

I use two extra annotations just for the purpose of communication. They don't change the behavior of the program nor are compiled. They are discarded on compilation but they help me and the team know what we should expect when using a method or passing parameters.

@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({ ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.PARAMETER, ElementType.METHOD })
public @interface CantBeNull {

}

@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({ ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.PARAMETER, ElementType.METHOD })
public @interface MayBeNull {

}
As you can see these annotations are only retained on the source level and can be used on parameters, methods, variables and class fields.

Of course, you can live without these, or make your own. The idea here is to communicate what your code expects as input and how it will behave as output. Communicating this information on the code has proved to be valuable for others and myself after months of coding.

Don't overuse
Remember the goal: communication. If you use them everywhere and without a second thought they will become noise, and people ignore noise. So all your extra effort will be in vain. Just use it when the code isn't clear or can be prone to errors.
If you use Hibernate or other frameworks that have similar annotations just use those. Don't add these mechanically as they are redundant in presence of similar annotations.

Uses
These are the main use cases

  • On methods: Indicate whether is safe to use the return value as null-impossible, or you should do extra checks
  • On method arguments: Indicate whether the method can handle null values or you may provoke a NullPointerException if careless.
  • On class fields: Indicate whether the class is designed to handle null on that field, or some parts of the class rely on the assumption of not null.
  • On local variable: This case is rare and I don't use it very much because I try to make short methods. But just in case, you can indicate whether or not a local variable can be made null during a loop or similar.