Saturday, July 9, 2011

Lets learn java api programming

A piece of good code is as good as a good book

Since java is very easy to learn, expressive language. Reading good code is the best way and probably the shortest and hassle free way to adapt a good coding style. Java programmers read many java books before they consider themselves as fluent as their PHP counterpart. There are many good reasons to choose java as your primary working language and continue your profession using this language, but the theme of this post is not what java offers, but how to adapt a universal or general approach of programming, so that we can share good piece of code that everybody (including yourself) can reuse and read like a book. Lets start with an example.


// HelloWorld.java
public class HelloWorld {
   public static void main(String[] args) {
      System.out.println("Hello World");
  }
}

Make your code flexible no matter when you write it
Do you consider above code flexible and reusable? If you do, then you are missing a great feature of java's ecosystem. The bottom-line is, unless you are writing code for a (very * 500) times memory critical device or project, you want to make your code flexible enough for always, unless you find a better solution. Open source project gurus have a saying.



Open source projects die when people stop writing code for that project.
A well crafted java code can however go from a okay to a matured library. Java code matures at a certain stage instead of dying. Everyone's code is crappy at first. I said everyone, that means neither you, nor I not even the creators of any programming language. Even for small library, they work (fix the error), work and work for many months until they can say it's enough, lets release it. Shortly after their release, they realize they suck, and release the first +0.1 version of that code. This +0.1 version at most cases is the previous internal version that worked. So the bottom line is your code always sucks at its first release, some way or the other. So in software engineering and agile programming we say it's enough after we feel we have done 90% of the planned work. So lots of things are out of your hand. Having said that, you should always try to improve yourself and try to be as good at the first place. A good code even with less feature has higher acceptance rate than a mountain of crappy code. If you have a habit of writing code as we showed in above code, then you will miss the great opportunity of learning and improving. To learn you have to use a code that is better than what you have at your display. If that code is fine then it should be ready to use for similar solutions. You should not re-invent the wheel. If a piece of code repeats (even 1 time) push it in a method. How do programmers say this in a phrase.
Don't write everything inside main method

Lets improve above code for first release.


package pkg.util.log;

/**
 * <code>Logger</code> method to log messages. Methods here can be used directly
 * to log messages on the terminal
 *
 * <pre>
 * import static pkg.utl.log.Logger.*;
 *     ...
 *     log(...);
 * </pre>
 *
 * @author <My Name> <My@email> <Today's date>
 * @version 0.1
 */
public class Logger {

    /**
     * Log a message to the terminal.
     *
     * @param message
     *            message to be logged
     */
    public static void log(String message) {
        System.out.println(message);
    }
}

Now, let's write the test


import static org.junit.Assert.*;

import org.junit.Test;

public class LoggerTest {

    @Test
    public void test() {
        Logger.log("Hello World");
    }
}


What are the changes, and what are its benefit?


First of all, our code can be now exported to a jar file and can be used as a library to log all of our strings into the terminal. We don't have to write System.out.println() every time from now on. We now have a serious documentation that tells the intent of our class and it's methods. We have not cluttered the method by anything other than it's purpose i.e logging. So first lesson to learn is "do as little as possible to get the job done efficiently". Before going any forward let me describe some of the keywords I used in the comment above. We have written javadoc style comment. These comments appear as our documentation in javadoc file. Here <code> is what it is in html. We can use many html syntax to format our file. E.g. img, b, br etc. Some of java specific keyword are @author. It tells who wrote the code. The @version tells what is the version of this code. If we later change this file, then we change the version number. Later we can write @since to specify from which version we have this file in the API. We must even write the date of creation, to specify when we first created the file. {@link JavaClass} helps user browse java documentation. Similarly, we can use @see to help user reference other related code in addition, to get a deeper knowledge of this class. The @param tag is used to specify intent of each parameter used in our method, similarly @return is used to specify the intent of return type.

We completed our first version. We wrote a unit test to test our behavior. Here unit test does not do any thing other than what we did in main method.

Can we improve our class?
Yes, since our intent is to use static methods, and will use only this class to do all logging functions in this project. If that is the case then, why in the world are we leaving the class for future extension and initialization. Two possible improvements to this code would be to write a private constructor to disable initialization, and make the class final to disable extension. In the future if we intend to put other behaviors and variables in this class, then we would use static factory method to initialize it rather than using a constructor, that is why we seriously want to disable the initialization.


...
public final class Logger {

 private Logger() {}
 
 /**
  * Log a message to the terminal.
  * 
  * @param message
  *            message to be logged
  */
 public static void log(String message) {
  System.out.println(message);
 }
}

What did we do? What is it called?
It is called refactoring. We did not change the core behavior (might be some performance in the future). We improved two things i.e we specified that we don't anyone using this code to extend logger, and we said we want all our interface (public methods) or say API to be static. If you don't know what an API is then API is collection of interfaces (public methods or interface types) that other people can use.

Conclusion : Now its up to you to extend this class and learn from it, daily. Can you improve it? The intent was clear. I wanted to show how easily we could transform a clumsy code that could be used only once to a general purpose api. We simplified the code. Yes we made the code simple (simple might not always be the easiest). And the rule stays the same. You learn by programming, improving your code everyday. When you realize the changes you make to a code is diminishing or the frequency of changes is low its time to call it a mature code. Take some time to think, can you improve your existing code. Can you improve a more complex program than the hello world program we did above. Can you do it? Is there a library or code I can learn coding style?
One class that I would suggest is junit's Assert.java. It is very easy code. It is as easy as our hello world program. Download the source code and read Assert.java class. Learn how comments are written. I too used it to write this post. It is a pretty sized code, but by just looking at top 5 and bottom 2 methods you can see how people write codes. I won't suggest the indentation and spaces used in that class to be your reference. There is a better guideline I think I follow to make the code more readable. We write codes for other programmers to read, that computers can also execute. Keep this thing in mind. That is the reason why you should not write, at least clumsy javadoc comment. If we only had to write code for computers, then machine language would be our first language and we would never learn any other language(including java). We could write whole project in just one line and use other low level details. Choose what ever style of indentation and spacing you want. However I follow some guidelines. I always format code using eclipse or other IDE like netbeans or intellij idea. In eclipse I frequently run Ctrl + F. Eclipse does not suggest white lines so I put it myself. I don't place any empty line after the method brace "{". if the code inside the method is only one-liner, else I put a blank line after the brace. It looks very easy on eye. I put together related syntax of code at single place. I follow similar guidelines for defining variables inside a block. I don't extend any code line over 80 characters. Enable that feature on eclipse editor to show a vertical line at 80 characters. I always insert an empty line after a method block before starting another. I don't place any empty line between method's comment and method's definition. While using control structures like if and while, I use a space before starting {, and if the condition does not extend one line I don't put a brace to enclose the block ({}).
E.g

if (condition)  // It is linux kernel style commenting. Not putting {} here
   statement;

if (condition) {
                 // Put white space here
   statement1;
 
    statement2; // We don't have to put any white line after this
}

Same rule applies for methods and control structures (if, while).

While using operators I always insert a space.

int a = c + d; // space between = and +


One exception to this rule is to not insert an empty line at the start of a method  block, if it is only one line statement. E.g

public static assertTrue(String message, boolean condition) {
  if (!condition) // Although it is two line statement we don't put empty line
    fail(message);
}


Finally if you have any suggestions, please suggest me. I want to learn. Cheers!!

No comments:

Post a Comment