Friday, August 31, 2007

10 Commandments for Java Developers

There are many standards and best practices for Java Developers out there. This article outlines ten most basic rules that every developer must adhere to and the disastrous outcomes that can follow if these rules are not followed.

1. Add comments to your code. – Everybody knows this, but somehow forgets to follow it. How many times have you "forgotten" to add comments? It is true that the comments do not literally contribute to the functionality of a program. But time and time again you return to the code that you wrote two weeks ago and, for the life of you, you cannot remember what it does! You are lucky if this uncommented code is actually yours. In those cases something may spark your memory. Unfortunately most of the time it is somebody else's, and many times the person is no longer with the company! There is a saying that goes "one hand washes the other." So let's be considerate to one another (and ourselves) and add comments to your code.

2. Do not complicate things. – I have done it before and I am sure all of you have. Developers tend to come up with complicated solutions for the simplest problems. We introduce EJBs into applications that have five users. We implement frameworks that an application just does not need. We add property files, object-oriented solutions, and threads to application that do not require such things. Why do we do it? Some of us just do not know any better, but some of us do it on purpose to learn something new, to make it interesting for ourselves. For those who do not know any better, I recommend reaching out to the more experienced programmers for advice. And to those of us that are willing to complicate the design of an application for personal gains, I suggest being more professional.

3. Keep in Mind – "Less is more" is not always better. – Code efficiency is a great thing, but in many situations writing less lines of code does not improve the efficiency of that code. Let me give you a "simple" example:

if(newStatusCode.equals("SD") && (sellOffDate == null ||
todayDate.compareTo(sellOffDate)<0>
todayDate.compareTo(lastUsedDate)>0)) ||
(newStatusCode.equals("OBS") && (OBSDate == null ||
todayDate.compareTo(OBSDate)<0))){
newStatusCode = "NYP";
}

How easy is it to figure out what this "if" condition is doing? Now imagine that whoever wrote this code, did not follow rule number 1 – Add comments to your code.

Wouldn't it be much easier if we could separate this condition into two separate if statements? Now, consider this revised code:

if(newStatusCode.equals("SD") && (sellOffDate == null ||
todayDate.compareTo(sellOffDate)<0>
todayDate.compareTo(lastUsedDate)>0))){
newStatusCode = "NYP";
}else
if(newStatusCode.equals("OBS") && (OBSDate == null ||
todayDate.compareTo(OBSDate)<0))
{
newStatusCode = "NYP";
}


Isn't it much more readable? Yes, we have repeating statements. Yes, we have one extra "IF" and two extra curly braces, but the code is much more readable and understandable!

4. No hard coding please. – Developers often forget or omit this rule on purpose because we are, as usual, crunched for time. But maybe if we had followed this rule, we would not have ended up in the situation that we are in. How long does it take to write one extra line of code that defines a static final variable?

Here is an example:

public class A {

public static final String S_CONSTANT_ABC = "ABC";

public boolean methodA(String sParam1){

if (A.S_CONSTANT_ABC.equalsIgnoreCase(sParam1)){
return true;
}
return false;
}
}

Now every time we need to compare literal "ABC" with some variable, we can reference A.S_CONSTANT_ABC instead of remembering what the actual code is. It is also much easier to modify this constant in one place rather then looking for it though out all of the code.

5. Do not invent your own frameworks. – There are literally thousands of frameworks out there and most of them are open-source. Many of these frameworks are superb solutions that have been used in thousands of applications. We need to keep up to date with the new frameworks, at least superficially. One of the best and most obvious examples of a superb widely used framework is Struts. This open source web framework is a perfect candidate to be used in web-based applications. Please do not come up with your own version of Struts, you will die trying. But you must remember rule number 3 – Do not complicate things. If the application that you are developing has 3 screens – please, do not use Struts, there isn't much "controlling" required for such an application.

6. Say no to Print lines and String Concatenations. – I know that for debugging purposes, developers like to add System.out.println everywhere we see fit. And we say to ourselves that we will delete these later. But we often forget to delete these lines of code or we do not want to delete them. We use System.out.println to test, why would we be touching the code after we have tested it? We might remove a line of code that we actually need! Just so that you do not underestimate the damage of System.out.println, consider the following code:

public class BadCode {
public static void calculationWithPrint(){
double someValue = 0D;
for (int i = 0; i <>
System.out.println(someValue = someValue + i);
}
}
public static void calculationWithOutPrint(){

double someValue = 0D;
for (int i = 0; i <>
someValue = someValue + i;
}

}
public static void main(String [] n) {
BadCode.calculationWithPrint();
BadCode.calculationWithOutPrint();
}
}

In the figure below, you can observe that method calculationWithOutPrint() takes 0.001204 seconds to run. In comparison, it takes a staggering 10.52 seconds to run the calculationWithPrint() method.

(If you would like to know how to produce a table like this, please read my article entitled "Java Profiling with WSAD" Java Profiling with WSAD )

The best way to avoid such CPU waste is to introduce a wrapper method that looks something like this:

public class BadCode {

public static final int DEBUG_MODE = 1;
public static final int PRODUCTION_MODE = 2;

public static void calculationWithPrint(int logMode){
double someValue = 0D;
for (int i = 0; i <>
someValue = someValue + i;
myPrintMethod(logMode, someValue);
}
}

public static void myPrintMethod(int logMode, double value) {
if (logMode > BadCode.DEBUG_MODE) { return; }
System.out.println(value);
}
public static void main(String [] n) {
BadCode.calculationWithPrint(BadCode.PRODUCTION_MODE);
}
}

String concatenation is another CPU waster. Consider example below:

public static void concatenateStrings(String startingString) {
for (int i = 0; i <>
startingString = startingString + startingString;
}
}

public static void concatenateStringsUsingStringBuffer(
String startingString) {
StringBuffer sb = new StringBuffer();
sb.append(startingString);
for (int i = 0; i <>
sb.append(sb.toString());
}
}

In the following figure you can see that the method that uses StringBuffer takes .01 seconds to execute where as the methods that use string concatenation takes .08 seconds to execute. The choice is obvious.

7. Pay attention to the GUI. – No matter how absurd it sounds; I repeatedly observe that GUI is as important to the business clients as functionality and performance. The GUI is an essential part of a successful application. Very often IT management tends to overlook the importance of GUI. Many organizations save money by not hiring web designers who have experience in design of "user-friendly" applications. Java developers have to rely on their own HTML skills and their limited knowledge in this area. I have seen too many applications that are "computer friendly" rather then "user friendly". Very rarely I have seen developers that are proficient in both software development and GUI development. If you are this unlucky Java developer who has been assigned to create an application interface, you should follow these three rules:

1. Do not reinvent the wheel. Look for existing applications that have similar interface requirements.
2. Create a prototype first. This is a very important step. The clients like to see what they are going to get. It is better for you also because you are going to get their input before you go all out and create an application interface that will leave the clients cold.
3. Put the user's hat on. In other words, inspect the application requirements from the user's perspective. For example, a summary screen can be created with paging and without. As a software developer, it might be temping for you to omit paging from the application because it is so much less complicated. But, from the client's perspective, it might not be the best solution because the summary results can hold hundreds of rows of data.

8. Always Prepare Document Requirements. – Every business requirement must be documented. This could be true in some fairy tale, but it is far from that in the real world. No matter how time-pressed your development is, no matter how tight the deadlines, you must always make sure that every business requirement is documented.

9. Unit-test. Unit-test. Unit-test. – I am not going to go into any details as to what is the best way to unit-test your code. I am just going to say that that it must be done. This is the most basic rule of programming. This is one rule that, above all, cannot be omitted. It would be great if your fellow developer could create and execute a test plan for your code, but if that is not possible, you must do it yourself. When creating a unit test plan, follow these basic rules:

1. Write the unit test before writing code for class it tests.
2. Capture code comments in unit tests.
3. Test all the public methods that perform an "interesting" function (that is, not getters and setters, unless they do their getting and setting in some unique way).

10. Remember – quality, not quantity. - Do not stay late (when you do not have to). I understand that sometimes production problems, urgent deadlines, and unexpected events might prevent us from leaving work on time. But, managers do not appreciate and reward their employees because they stay late on regular basis, they appreciate them because they do quality work. If you follow the rules that I outline above, you will find yourself producing less buggy and more maintainable code. That is the most important part of your job.

No comments: