preload
Feb 27

One part of reviewing and refactoring code is finding and removing code smells. An example, which I encounter quite often is the outmoded manner of coding Enumeration-like behaviour using int-constants. Or worse: String constants. The java.util.Calendar-class serves as a great example for this former best practice, before the Enumeration-Type was introduced with Java release 1.5.

Imagine you want to get a java.util.Date object pointing to the 1st of January 2009, midnight. This is one way of doing it:

Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 2009);
cal.set(Calendar.MONTH, Calendar.JANUARY);
cal.set(Calendar.DAY_OF_MONTH, 1);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
Date myDate = cal.getTime();

This has been a clean way of implementing and “imitating” enum-like behaviour in pre 1.5 times and of course in projects that require a lower java version.

Since we’re passing ints to the set method, it is possible to do something like this, without having the compiler complain about it (seen it done before):

cal.set(Calendar.MONTH, 1);

And due to the fact that the number of the months in the Calendar class starts with 0 this would create a Date object pointing to the 1st of February. Ouch.  An even more evil way of misusing the Calendar class could be this:

cal.set(2, 1);

I’ve never seen this done before, but looking at it, I must say it really hurts.

Since the release of Java 1.5 there is a much better way of programming that kind of behaviour using the Enumeration type. This is how a simple Month enumeration could look like:

public enum SimpleMonthEnum {
        JANUARY, FEBURARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER,OCTOBER, NOVEMBER, DECEMBER;
}

But we can add a little more brain to the implementation:

We’ll add member variables for the name, index and number of days, a constructor with arguments for each of these values and we’ll provide getters for retrieving them. Additionally we’ll add a method for calculating the correct number of days depending on a given year, considering leap years.

package com.coredump.enumTest;

public enum MonthEnum {
       
        // define the items of the enumeration
        JANUARY("January", 1, 31),
        FEBRUARY("February", 2, 28),
        MARCH("March", 3, 31),
        []
        NOVEMBER("November", 11, 30),
        DECEMBER("December", 12, 31);
       
        // member variables
        private String name;
        private int index;
        private int numberOfDays;
       
        // constructor
        private MonthEnum(String name, int index, int numberOfDays) {
                this.name = name;
                this.index = index;
                this.numberOfDays = numberOfDays;
        }

        public String getName() {
                return name;
        }

        public int getNumber() {
                return index;
        }
       
        public int getNumberOfDays() {
                return numberOfDays;
        }
       
        public int calcNumberOfDays(int year) {
                // check for leap years:
                // year modulo 4 is 0
                // if year modulo 100 equals 0
                // and year modulo 400 is not 0, it’s not a leap year
                if (this.equals(MonthEnum.FEBRUARY) && year%4 == 0
                                && !(year%100 == 0 && year%400 != 0)) {
                        return this.numberOfDays +1;
                }
                return this.numberOfDays;
        }
}

And here’s an example of how the enumeration can be used:

public class MontEnumClient {
        private static void printMonthDetails(MonthEnum monthEnum) {
                System.out.println(monthEnum.getName());
                System.out.println(monthEnum.getNumber());
                System.out.println(monthEnum.getNumberOfDays() );
        }
       
       
        public static void main(String[] args) {
        System.out.println(MonthEnum.FEBRUARY.calcNumberOfDays(2008));
        System.out.println(MonthEnum.FEBRUARY.calcNumberOfDays(2009));
        System.out.println(MonthEnum.FEBRUARY.calcNumberOfDays(1700));
        System.out.println(MonthEnum.FEBRUARY.calcNumberOfDays(1600));
       
        printMonthDetails(MonthEnum.DECEMBER);
        }
}

I warmly recommend the use of this great feature of the Java language. It definitely adds more type safety, ease of use and security to your application. But unfortunately it seems to me, that it still hasn’t reached the popularity that it really deserves, yet.

Tagged with:
Feb 23

Whether you’re part of an agile team using methods like XP or Scrum, or processing your projects in a more classic way with RUP or even waterfall, in most cases you’re part of a team of developers. Chances that someday you’ll have to work with or (worse) debug code someone else has written are 100%. And who of us hasn’t complained about having to deal with “the mess” someone else has made. And probably some of our co-workers have been scratching their heads with both hands looking at some piece of code we’ve written after midnight with a numb mind in shipping hell. Nobody’s perfect.

So what can we do about this situation? Whining, complaining and pointing fingers won’t make the code any better.

Just recently I read “Clean Code” by Robert C. Martin. Zillions of blog entries were recommending this book, so I had to get it myself. I was probably one the last people on earth who hadn’t read it. It’s a great piece of programming literature. Reading it I found myself nodding my head a lot, agreeing with many of the points made and regretted I hadn’t read it earlier. There are some aspects I do not agree with 100% but they were very few.

One thing that impressed me a lot because of its simpleness is the “boy scout rule”: “Leave the campground cleaner than you found it”. When working with a piece of code, make your changes and commit it a little cleaner to your version control system. Let me give you an example.

I was debugging a class for creating financial charts. The following piece of code was scattered in it with slight variations about 20 times.

domainAxis.setTickLabelFont(new Font("Arial Narrow",Font.BOLD,11));

The reason I was debugging the class was that the font sizes within the charts did not look right when run on the production environment. Simple change made: remove the hard coded String and the numeric font size, and replace them with constants.

domainAxis.setTickLabelFont(new Font(CHARTFONT,Font.BOLD,FONT_SIZE_NORMAL));

No big deal, but improving the readability and maintainability of the code a little bit. Imagine a whole team following this simple principle. More productivity, less rotten code, better team spirit. And the best thing about it: it’s absolutely free!

Happy coding!
Alex

Tagged with:
Feb 20

Anyone who ever seriously started writing unit tests will sooner or later have come to the conclusion, that it helps isolating small testable chunks of code resulting in a clean structure of methods within a class and forcing the developer to write cleaner code. This is easy as long as the tested code does not work with data or configurations that might change depending on the environment in which the test are run.

My two favourite basic rules for writing tests (Thanks uncle bob!) are

  • tests must run anywhere. (e.g. on a continuous integration server)
  • tests must run fast, so they’re fun running them.

As soon as your tests depend on a database containing specific data or a file system with a certain directory structure you’re in trouble. In my experience many programmers write test for methods that are easy to write tests for, and avoid the more complicated cases requiring setting up test data and such like.

A really cool way for decoupling tests from dependencies like this, speeding up their execution time and finally leading to a much better code coverage are mock objects.

A mock library I really enjoy using is easymock. Let me show you an example of how easy easymock (http://www.easymock.org) really is.

First include this library to your classpath: easymock.jar

In case you want to mock classes that do not implement an interface, additionally add this library: easymockclassextension.jar

Now you can start writing your isolated test making use of mock objects

Add this include to your test class:

import static org.easymock.classextension.EasyMock.*;

or this if you’re mocking interfaces:

import static org.easymock.EasyMock.*;

This is how a test could look like (example code)

@Test
public testMyServiceMethod() {

/* create a mock object of the class that has dependencies on the environment in which it’s used */
ClassToMock mock = createMock(ClassToMock.class);

/* In this example we’re going to call a method of the mocked class that returns an Object of the type ResultObject. Create a dummy object, that the method call should return later */
ResultObject resultObject = new ResultObject();
resultObject.setXyzProperty(“test”);

/* let the mock object know which method is going to be called later with which parameters. Also define the result of the method call. */
expect(mock.methodToMock(testParam)).andReturn(resultObject);

/* the class you’re testing and that’s going to make use of the mock object, ideally holds it in an instance variable, accessible by means of a setter method. It can easily be replaced with a mock. If you’re using the Spring framework for dependency injection, your classes will usually be structured this way already. */
objectToTest.setTheObject(mock);

/* GO! */
replay(mock);

/* in the object to test, call the method which is going to make use of the mocked object. */
String result = objectToTest.methodToTest();

/* some asserts which are the essence of our test */
assertEquals(“expected”, result);

/* optionally check if the mock object was used as defined before. If the method was not called as expected, verify will fail. So in addition to the asserts this enables us to test if the expected calls to the mocked object were done */
verify(mock);
}

Mock Objects will definitely help you decoupling your tests from platform dependencies. They will make your tests faster and more fun to run.

Alex

Tagged with: