Tuesday, December 11, 2007

Annotations, the Good the Bad and the Ugly

I'm a little late jumping on to the Java5/6 bandwagon. I'm one of those big strong typing / type safety advocates. It comes from spending a lot of time on big projects where tracking down trivial errors is a process unto itself.

Naturally, I find the new generics to be a blessing. When you are in favor of type safety, casts always make you cringe.

I must admit that I basically ignored the annotation system for a while. When I did start using it, I saw things like @Override, "hey this is good to protect code while refactoring." I saw the Spring framework's @Required (ensure classes are properly configured). These seem like good things, communicate with the compiler, communicate with the frameworks. This establishes a rule in the first case and a requirement in the second.

Then things start to go grey. The @SuppressWarnings mostly finds itself being used when using code that does not support generics (J2EE : request.getAttribute()). Ok it's a necessary evil, I admit.

Then EJB3 starts down a darker path. @TransactionAttribute(TransactionAttributeType.REQUIRED)
do we really want to define this in the class?
What about JNDI lookups @Inject(jndi-name="java:comp/env/jdbc/test") ?

Finally, it gets down right ugly
@Resource(name="myDB", type="javax.sql.DataSource.class")
@Table(name="CUST", schema="RECORDS")

Finally, we start to see annotations with SQL in them
@SQL(statement="SELECT * FROM USERS WHERE {sql: where}")

Finally, there's the ultimate abuse (from Google Guice):
@ImplementedBy(ServiceImpl.class)
public interface Service {

This one is so bad it doesn't need explaining.

Like many things, I think annotations can be very useful when used correctly. What bothers me most is when Sun is the one promoting obviously bad practices. Really, what's the difference in using annotations with SQL in them or just writing plain old JDBC? not much. If the configuration is in the code being configured, then what's the point of an annotation?

To be fair, I could agree with doing this if it was contained to configuration classes. By this, I mean a handful of classes that sit in a package all to themselves and serve to replace XML configuration. Configuration classes benefit by providing compile time type safety, and can exploit tools for auto-completion. But, sprinkling these kinds of annotations around the code base is going to make for maintenance nightmares.

The way I see it:
annotations to make code easier to configure : Good
annotations to enforce local policies : Good
annotations to define requirements (contract) : Good
annotations to configure : Bad

Update: I've just received an email about Loom and how it uses annotations for validation on beans (value objects to the rest of us). The idea being that the logic can exist in one place instead of at every tier (web, middle, data access). It can read the annotations to generate javascript for page level validation, and use the same annotations to validate the beans in the other tiers.

I haven't looked at Loom myself so, I'll reserve judgement but, on the surface this appears to be an interesting (read innovative) way to use annotations.

Update: while talking to a colleague, he mentions that much of the 'bad' use of annotations looks like C macros in sheep's clothing.

Update: reference to this post on DZone
.
.

Labels: , ,

permalink
Links to this post

9 Comments:

At 11 December, 2007 14:06, Anonymous Anonymous said...

What strikes me most is when an interface would be the perfect way to describe the necessary contract but nevertheless annotations are used.
Examples:
JBoss Cache
@CacheListener
public class MyListener
{
@CacheStarted
public void cacheStartStopEvent(Event e)
{
}
Just imagine the complexities to check that the class fulfills the contract (and invoke the correct method) where a simple method invocation on the interface would be a perfect fit ...

or EJB3's @AroundInvoke Annotation, where any POJO having coincidentally a method that returns an Object and takes InvocationContext parameter can be used.

Annotations are poor for contracts e.g. when a single method or a specific signature is required and shouldn't be used for such cases IMO.

Yours,
Stefan

 
At 11 December, 2007 14:10, Blogger doyle said...

Yeah ... and the frigin vendors with there custom apt processors. Talk about some vendor lock-in! If you drink the Seam juice it's great and wonderful and then you want to take that somewhere else. Have fun. But hey I'm a Seam fan ... I know the hole I'm digging. I'm sure IBM can't wait for you to use EJB3 ... like their extended EAR ... hahahhahahaha

 
At 13 December, 2007 10:47, Anonymous Sakuraba said...

Yeah right like defining that stuff in five different XML files is gonna make it better.

 
At 13 December, 2007 15:53, Blogger willCode4Beer said...

Sakuraba, if your "configuration" is in the class being configured, is it really configuration?

 
At 13 December, 2007 23:00, Blogger Solomon said...

@WillCodeForBeer and @Sakuraba

I like Guice, but I do find @ImplementedBy to be problematic. I actually didn't think of the obvious reason when I formed that opinion... but the obvious reason to not like it is now glaringly obvious.

I'll take the middle road:

Programmatic configuration via annotations: Good
ImplementedBy: Bad

IMHO, the following is elegant:

@Service
public class MyService{...}

 
At 14 December, 2007 02:54, Blogger Azrul said...

Correct me if I'm wrong but annotation can be overridden with an xml configuration. Perhaps, the annotation is there to facilitate programmers but once it is time to deploy, the configuration should be put in an xml file (i'm just too lazy to look it up but I think there's an extractor somewhere that takes annotation config and put it in xml).

 
At 14 December, 2007 03:29, Anonymous Sakuraba said...

I agree with Solomon.


I just dont want to go back to the XML configuration days.


"ImplementedBy" destroyes the sense of interfaces, I agree. But please dont get me back to synchronizing 5 different XML files. Annotations have code completion at least.

 
At 15 December, 2007 11:17, Blogger JAlexoid said...

Annotations are good for explaining, where comments are duplicated. Since there are annotations present only in source.

And let us not forget that Java is no less of a revolver with witch you are free to shoot yourself in the foot. Though less of a revolver than C++.

 
At 16 December, 2007 10:16, Blogger klimek said...

With regards to things that make a language safe or enable you to shoot yourself:
Before I started to TDD I was a "static typing" and "make your code safe to be used by other developers" advocate myself.

In the meantime I learned that with TDD dynamic typing works quite well for me and I don't have fundamental problems with C++ as a project language anymore.

I also learned that you can never make a language so safe to use that developers won't just mess up - copy the worst code available and use it.

So I'm more in favor of "educate your coworker" instead of "try to make the code / language so safe that you can't mess up. Use whatever fits your team and problem.

Cheers,
Manuel

 

Post a Comment

Subscribe to Post Comments [Atom]

<< Home

Links to this post on:

Create link here by posting on Blogger