Java Best Practices and Standards

Contributers:Chris MullerMay13, 2010

1

Table of Contents

Why Standards?

Follow The JavaRanch Coding Style Guide At All Times

Reasoning

Call Things What They Are

Reasoning

Logging as part of code development

The alernatative form for static classes:

Reasoning

JUnit Test Cases As You Go

Reasoning

Reuse Code and Ideas Instead Of Rewriting Or Recreating Them

1

Why Standards?

Although it just all seems like giving up freedom for a form of fascism, it really isn’t about trying to create the perception of control. It is really about trying to make everyone’s job maybe just a bit easier. In other words, if your code doesn’t conform to some standard, you are just making everyone’s job harder.

Follow The JavaRanch Coding Style Guide At All Times

Read it, learn it, live it. If your code doesn’t conform to this standard, you are just making everyone’s job harder.

Reasoning

Having code in a standard format allows multiple programmers to work on the same code module and have it read as one consistent piece of code.

Call Things What They Are

This is a general philosophy, but one example would be the declaration of a variable:

Bad:SomeClassName scn = new SomeClassName();

Good:SomeClassName someClassName = new SomeClassName();

Reasoning

This makes project wide refactoring and moving/copying code a whole lot easier. Also allows multiple programmers to work on the same code module and be able to make very accurate assumptions about what an existing instance of an object is named for quick code changes.

Logging as part of code development

  1. Log anything meaningful at the debug level; verbosity is not a major concern; business logic execution is a primary target; important submit and return values (service layer would be an example).
  2. Log anything that would help with determining what is going on at a customer site at the info level; general traceability through the business logic; not too verbose as this will tend to just fill up the log with meaningless information.
  3. Log all conditions that would normally fall under the category of assertion failure (some assumption was violated) at the warning level. It can be easily configured to makethesemessages go into a separate warning and error log file.
  4. Log only exceptions at the error level. This way they can be easily extracted from the log. Again, it can be easily configured to make these messages go into a separate warning and error log file

Use the slf4j pattern for creating loggers. This gives additional flexibility in the back end logging framework that is used, although it probably will be log4j for the near future. Example:

private Logger logger = LoggerFactory.getLogger(this.getClass());

The alernatative form for static classes:

private static Logger logger = LoggerFactory.getLogger(MyClass.class);

Reasoning

This falls under the category of you can pay the price now, which is cheaper because it is amortized over the work on the entire project, or you can pay the price later, which is going to be laborious retrofitting of logging into the project after supportability at a customer site becomes a critical concern.

JUnit Test Cases As You Go

Write a JUnit test case for every class that is not a simple POJO or Entity Bean; however this is not to say that there should not be any JUnit test cases for Entity Beans, particularly when there are complex relationships involved. This might be considered unit testing.

Then there is the integration or end-to-end testing. Some standard framework for this type of testing should be created. This may include using random combinations of JUnit, mocking (e.g.: EasyMock, MockLib, jMock), dbUnit, Unitils, etc. Ideally each project should have an integration framework that will be specific to the details of the project and handle round-trip integration testing.

There is a standard set up for the JUnit test framework within a project. The JUnit class should be at the same package level as the class under test but in a separate source tree (by convention called test instead of src). There are standard annotations to use for marking a test method, for setup/teardown methods, and for create test suites. Each package should have all its test cases wrapped up into a test suite called AllTests.java. There should be at least one single “master” test suite that wraps up all the package level test suites and can therefore be run as the single test to determine if the project is broken.

The old standard for naming of JUnit test classes/cases still is best practice. This is to name the test class the name of the class it is testing with ‘Test’ appended to the end, e.g.: MyClassTest. Then each test method should be named testXXX.

It makes it a lot easier to follow an interactive test suite execution in Eclipse when this standard is followed. I have run across test cases which had names like testX191208. If this test case fails, how does anyone know what it was trying to test for? Does everyone really need to dig into the test code to find out what a test case named like this is actually trying to check is supposed to happen? This goes back to the idea of “calling things what they are”. Some number like a ticket number is not what the test method is testing; it is testing some functionality that was broken.

Reasoning

There are many reasons for doing automated unit testing; I won’t even start to get into all of them. Let it just suffice to say that the more test coverage a project has, the less likelihood there will be that the code delivered to a customer is broken. This is particularly true in the maintenance phase of a project when someone that doesn’t fully understand the design breaks a basic contract which affects multiple parts of the system. Automated unit/integration testing will catch that right away, before it ever gets delivered to QC.

Don’t Commit Code That Has Warnings

Right now most code relies solely on Eclipse’s ability to generate warnings, although there are other alternatives, likeFindBugs ( to look for additional issues. The following Eclipse settings (Window->Preferences->Java->Compiler->Errors/Warnings) are used for consistent warning generation and elimination (this is from the Galileo version):

Reasoning

This may seem obvious, trivial, or burdensome, but in the end it just makes the whole project look sloppy when this is not done.

Reuse Code and Ideas Instead Of Rewriting or Recreating Them

It is always a good idea (but one that never seems to work in the practice of trying to get things done fast) to look at code that has already been written to determine how to best implement something new. It is somewhat likely that the same problem that is trying to be solved right now has already been solved. So look at the existing code base when looking for solutions!

Reasoning

Wasn’t that the whole point of object-oriented programming and design patterns?

Leverage Boilerplate Tasks for Sprint Planning

Many tasks reoccur in each sprint and it is advisable to estimate for them each time to ensure an accurate picture of the work is captured. Examples include:

  • Unit Testing (jUnit)
  • Developing and refining build scripts
  • Working with the systems integration team
  • Creating auditing and logging entries in new code
  • Refactoring

1