Thursday, February 10, 2011

Metadata Hell

I recently had the opportunity to attend JavaOne in San Francisco, which was a very great overall experience. One thing that I noticed, though, was the apparent love affair with annotations. It would seem that annotations are The Next Big Thing. In almost every session that I attended, there was some person going on and on about how great annotations are. Look, you can configure things on a single line! OOOH, you can configure properties in line with your code! Holy Crap, you can embed connection information into annotation tags directly in your java code!

No, I really was not kidding about that last one. Apparently, the new best practice in Java is to put all of your configuration information into annotations. By all, I really mean all configuration information, right down to your database connection strings. The very thing that I have been taught since I saw my first for loop, that which has been banged into me repeatedly as the worst danger in the world, is now best practice!

We are now hard coding this stuff in our code.

From what I can gather, this was put forth as the solution to what was commonly referred to as XML Hell. People didn't like all of the XML configuration that was having to occur to get applications running. I can understand this concern - XML files can be a pain in the rear end. I think, though, that the mark was missed a bit on this one. All we have really done is trade out one Hell for another.

My biggest concern with annotations is the unnecessary complication of the code files. Take the following example, taken from a Struts2 convention plug-in example:
package com.example.actions;

import com.opensymphony.xwork2.ActionSupport; 
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Actions;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;

@Results({
  @Result(name="failure", location="fail.jsp")
})
public class HelloWorld extends ActionSupport {
  @Action(value="/different/url", 
    results={@Result(name="success", location="http://struts.apache.org", type="redirect")}
  )
  public String execute() {
    return SUCCESS;
  }

  @Action("/another/url")
  public String doSomething() {
    return SUCCESS;
  }
}
Here is the exact same Action class, without the annotations:
package com.example.actions;

import com.opensymphony.xwork2.ActionSupport; 

public class HelloWorld extends ActionSupport {

  public String execute() {
    return SUCCESS;
  }

  public String doSomething() {
    return SUCCESS;
  }
}
That is a dramatic reduction in complexity, and that is just on a simple example application. What is more, it is now encouraged that every single third party library, framework, whatever, should now all use annotations. Look at the above code again: that is the added complexity from a single framework's configuration. What is going to happen when you have a framework and a handful of libraries and they all want to use different annotations?

The rub of it is, in my mind, that there was another solution available - simplify the XML. Having XML files isn't a problem; it provides a nice, isolated place to put the metadata of your application, keeping it separate from the logic of your application. However, most XML configuration is very complex, large, tree-like structures. Take, for example, the XML needed to configure a Java servlet:

    HelloWorld
    com.jspbook.HelloWorld


    HelloWorld
    /HelloWorld

Here is the annotation configuration version:
@WebServlet(name="HelloWorld", urlPatterns={"/HelloWorld"})
I can admit that the above configuration is more simple than the current configuration. However, here would be a proposed alternative in XML, which would also reduce it to a single line:
<servlet name="HelloWorld" urlPattern="/HelloWorld" class="com.jspbook.HelloWorld"/>
With that, you have the simplicity of a single line of configuration, but still safely tucked away in a separate XML file.

In fact, it is my theory that there is nothing that you can do with annotations that you can't do in just as few lines in an XML file. The only difference is that in the XML file you need to specify what class you are referring to. That is it.

In short, while I see the need for something to be done to reduce the configuration pains that we as developers currently experience, I absolutely do not think that the answer is to move that pain to a place where I have to stare at it and read through it every single day. There are other, better solutions out there, if we would but take the time to look for them.

9 comments:

  1. So sad that java is so far behind other platforms like ASP.NET MVC, ruby etc. Once there was a time when Java was the it language for creating web sites but not anymore.

    Just look at some common ports from java. They do support xml configuration but almost always there is a fluent interface (e.g. fluent nhibernate) which makes things so much simpler. Every other platform has figured out that where xml is nice it is just not worth it to use it for everything.

    All you really have to do is just compare the syntax. E.g. with C# anoymous methods vs. java. Or take a look ASP.NET MVC which has same kind of annotations. Except the syntax and the usage is so much simpler.

    Too bad java did not evolve. It would have been a great development platform.

    ReplyDelete
  2. It seems like everything new and shiny gets used for everything possible for a while. It is almost as if the only way people can learn what something is good for is by using it for all kinds of things that it is bad for.

    The same thing happened with XML several years ago. People got excited about being able to keep the configuration out of the code and put all kinds of things in XML that had no business being in XML.

    Annotations have been around for awhile, but developers are just starting to realize, "Hey, I can make these myself!" Expect to see a lot more of this for awhile.

    ReplyDelete
  3. I agree with Mark -- people are experimenting a lot with annotations and it's easy to get carried away. More useful patterns will remain and clumsy inventions will die.

    This post mentioned annotations as configuration means but I think they're most useful for more precise specification in cases where base language is not expressive enough, eg. for specifying nullability info in Java (see "pluggable types")

    ReplyDelete
  4. Jut use the Play Framework and all the headache with Java is gone.

    ReplyDelete
  5. There is no real need for the servlet name in a sane xml file and the url attribute name can be simplified, so the xml line can even be reduced to:


    Even a simple text file is better than the old xml:
    com.jspbook.HelloWorld /HelloWorld
    Format is classname and then a list of whitespace separated url patterns.

    ReplyDelete
  6. Comments are unexpectly html and not plain text. So here is the xml with html escaped:
    <servlet url="/HelloWorld" class="com.jspbook.HelloWorld"/>

    ReplyDelete
  7. There has to be some balance between what you want to use in an application.

    I mean overusing Annotations, Properties files or XML is definitely going to be painful.

    http://extreme-java.blogspot.com

    ReplyDelete
  8. Honestly, I think there's some virtue in annotations over XML hell. For starters, it groups related things close together. And it's strictly better than the crazy XDoclet comments as code, since the compiler and tools know about them.

    Where this stuff really shines though, is boiler plate reduction. It would be really swell if something like project Lombock were to become popular.

    ReplyDelete
  9. Another point that I would make against using annotations, specifically the @Action annotation, is that why would you explicitly lock your code down to a single, specific domain? What if your action code drives both a web application and a swing application? The annotation simply fails in that regard, while you could have many XML action configurations, each pointing to a different display technology.

    ReplyDelete