Tuesday, August 28, 2007

Learning the hard way

Sometimes learning a simple well known lesson has to happen the hard way. That happened to me last week. My project (the one I'm part of a team for) was just about done and ready to deploy when an odd error that's never occurred before popped up. A user couldn't save a payment for the total amount due. That's a big deal.

I started looking into the issue and found that it was a pretty standard issue with using a double in Java to hold monetary values. So I thought, a quick find and replace would take care of it, but it didn't.

BigDecimal is an object and needs to be treated like an object. It also does not have the + operator implemented, or the comparison operators. So it was a lot more than just replacing all instances of Double with BigDecimal. To further compound the problem I was using double in many places and I had to convert all of those to BigDecimal as well. Finally the constructor for BigDecimal can take a double and all of my unit tests were written as
BigDecimal test = new BigDecimal(11.11);

However Java treats that as a double before putting it into the BigDecimal and that was causing the exact same floating point errors I had before. I had to change every one of my tests to use the String Constructor of
BigDecimal test = new BigDecimal("11.11");

All in all I modified about a thousand lines of code over two days because I didn't know ahead of time that I should have been using BigDecimal for money. This is a lesson I've learned and won't forget for the next time.