Monday, February 27, 2006

TestDrivenDesignPhaseShift

This is rather belated news, but I am kind of proud of the fact that I've added a new term to the XP lexicon: Phase Shift. See the c2 wiki:

http://www.c2.com/cgi/wiki?TestDrivenDesignPhaseShift
.
The notion came out of some discussions in the xp newsgroup. The basic idea is that even if you develop your code incrementally using test-driven development, it is possible that your approach may have to fundamentally change at some point. In my opinion, that's OK and does not confute xp and tdd as reasonable appraoches to develop software. Anyway, I was quite happy when I found out that someone had edited my initial posting to sound more definite and authoritative, and phase shift may well be a legitimate part of the xp lexicon now! :)

Monday, February 13, 2006

Simple Refactoring

Refactoring doesn't have to be, and generally should not be, a complex and time-consuming activity. By using some simple refactoring practices it is possible to greatly simplify code and save time for other people reading the code in question. Here is an example:

Here is the refactored code for calculating the number of hours remaining in the month:


public static int calculateNumberOfRemainingHoursInMonthFromDate(Date fromDate) {
return hoursBetween(startOfNextMonth(fromDate), startOfDay(fromDate));
}

And here is the original code:

public static int calculateNumberOfRemainingHoursInMonthFromDate(Date fromDate) {
Calendar startCal = Calendar.getInstance();
startCal.setTime(fromDate);
int startDay = startCal.get(Calendar.DAY_OF_MONTH);
int maxHoursInMonth = 0;
Calendar calendar = Calendar.getInstance();
calendar.setTime(fromDate);

calendar.set(Calendar.SECOND, calendar.getMinimum(Calendar.SECOND));
calendar.set(Calendar.MINUTE, calendar.getMinimum(Calendar.MINUTE));
calendar.set(Calendar.HOUR_OF_DAY,
calendar.getMinimum(Calendar.HOUR_OF_DAY));
calendar.set(Calendar.DAY_OF_MONTH, startDay);
Date startDate = calendar.getTime();

calendar.add(Calendar.MONTH, 1);
calendar.set(Calendar.DAY_OF_MONTH, 1);
Date endDate = calendar.getTime();

long milliseconds = endDate.getTime() - startDate.getTime();
maxHoursInMonth = (int) (milliseconds / 1000 / 60 / 60);

maxHoursInMonth = correctHoursForAprilTo720(maxHoursInMonth);

return maxHoursInMonth;
}

Below are the utility functions used in the refactored code:

private static int hoursBetween(Date endDate, Date startDate)
long millisecondsRemainingInMonth = endDate.getTime() -
startDate.getTime();
int hoursRemainingInMonth =
(int) (millisecondsRemainingInMonth / 1000 / 60 / 60);
hoursRemainingInMonth = correctHoursForAprilTo720(hoursRemainingInMonth);
return hoursRemainingInMonth;
}

private static Date startOfNextMonth(Date date) {
Date initializedDate = startOfDay(date);
Calendar toDateCalendar = Calendar.getInstance();
toDateCalendar.setTime(initializedDate);
toDateCalendar.add(Calendar.MONTH, 1);
toDateCalendar.set(Calendar.DAY_OF_MONTH, 1);
return toDateCalendar.getTime();
}

private static Date startOfDay(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(Calendar.SECOND, cal.getMinimum(Calendar.SECOND));
cal.set(Calendar.MINUTE, cal.getMinimum(Calendar.MINUTE));
cal.set(Calendar.HOUR_OF_DAY, cal.getMinimum(Calendar.HOUR_OF_DAY));
Date startDate = cal.getTime();
return startDate;
}