Back to Basics – good comments are targeted comments
The simple reason for this is that a) interfaces should be explicit, and b) implementations should be self-documenting.
The reason for this blog post is that I’m seeing a lot of code at the moment that falls into one of two traps – either everything is documented, or nothing is documented.
Everything is documented
Spot what’s wrong with this code:
/** * The foo class represents blah blah blah...and so on, describing the * class in such detail it's a pity the code couldn't be generated from it */ public class Foo { /** The name */ private String name; /** * Do something with this instance. */ public void doSomething() { // Get the name String localName = this.getName(); // munge the local name localName.munge(); } /** * Get the name. * @return the name */ public String getName() { // return the name return this.name; } /** * Set the name. * @param name the name */ public void setName(String name) { // set the name this.name = name; } }
Or, to put it another way, spot what’s right with it. That’s a much shorter answer. The code is full of unnecessary comments – e.g. getName() gets the name – and code that seems to have been written just so it could be commented – e.g; String localName – this.getName(); The names have been changed to protect the guilty, but this is real code I’ve seen in a live codebase.
As as I’m concerned, implementations don’t need code-level comments because that’s what the code does anyway.
Nothing is documented
At the other end of the scale is this little gem:
public interface Parser { void parse(InputStream is) throws IOException, SQLFeatureNotSupportedException }
Interfaces, on the other hand, should have clear documentation that defines what goes in, a generic description of what should happen, and a clear description of what comes out and what exceptions can be thrown. Information at this level should state if, for example, null arguments are allowed, if a null value can be returned, the circumstances in which certain exceptions can be thrown, and so on.
Interfaces should be explicit
Interfaces, to my way of thinking, are contracts, and contracts – as any blood-sucking lawyer can tell you – exist to be honoured. They can’t be honoured if the terms are not explicitly set out.
There are no Burger Kings in Belgium, so if I’m in the UK or the Netherlands I am generally tempted to have one. On my most recent visit, I noticed this at the bottom of the receipt:
“ Free drink with any adult burger with this receipt Excluding Hamburger, Cheeseburger or King deal or any promotional offers”
Or, to put it another way…
/** * Get the free drink promised by the receipt. This is valid for any burger. * @param burger the burger * @param receipt the receipt * @returns the free drink * @throws InvalidBurgerException if the burger doesn't qualify for a free drink */ public Drink getFreeDrink(Burger burger, Receipt receipt) throws InvalidBurgerException { if (MealType.HAMBURGER == meal.type() || MealType.CHEESEBURGER == meal.type() || MealType.KING_DEAL == meal.type() || meal.isPromo()) { throw new InvalidBurgerException(); } return new Drink(); }
To my simple brain, this is confusing and contradictory as hell. Your API should be clear and (as my university teachers beat into me) unambiguous – for example, the words “any” and “except” should not appear in the same sentence. Strive for clarity – if you find your API is too hard to clearly document, there’s a good chance it will be annoying to use. In the case above, an improvement would be something along the lines of
/** * Get the free drink promised by the receipt. Not every burger qualifies for a free drink. * @param burger the requested burger. This may or may not qualify for a free drink * @param receipt the receipt containing the offer * @returns the free drink. May be null, depending on the burger */ public Drink getFreeDrink(Burger burger, Receipt receipt) { // implementation }
Note that I’ve also got rid of the exception as a result of being more explicit.
Conclusion
Annoying as it is, documentation is extremely important in the correct place and completely useless everywhere else. Done correctly, they will make your API easier to use and easier to maintain, which is generally a good thing.
Reference: Back to Basics – good comments are targeted comments from our JCG partner Steve Chaloner at the Objectify blog.
Some times the IDE puts that comments not the coders or (wt i think they should) the designers, and maybe can be usefull for that the documentation is not empty (it just seems ugly :S).
Comments are part of the code, so if your IDE inserts them automatically, they should then be
– removed, if not used
– completed, if they are useful
For example, generated getters and setters in IntelliJ have stub comments added. If I’m not going to complete them (and personally, I think comments for getters and setters just add insult to the injury of Java not having real property support), then I delete them.
First off, those comments on the get and set methods are for the sake of the javadoc. Second, saying that implementation code doesn’t need comments is ridiculous. Sure, this example is so trivial that the comments look stupid, but in a real implementation comments are extremely important for the longevity of your code. I have written every line of my 50k line codebase, and if it wasn’t as well commented as it is, I would have a tough time maintaining the code.