Top Tips for Coding With CurrencyAs anyone who's ever made an E-Commerce system knows, money is everything. No, really if you don't get your financial sums right then you can't hope to build a successful online business (and may find yourself creating potential legal issues with the tax man).
So here's a rundown of the top tips I can give for making your financial calculations that bit easier.
Always Work In Minor Units
I can't stress enough how much this helps in terms of accuracy, rounding and speed. Working in major units may look better to you as you don't have to reformat the numbers to display them but I hope I can make the case here for minor units.
Integer arithmetic is much much faster than floating point arithmetic
Remember that even a single decimal place makes a number a float as far as your computer is concerned and all the processor overheads that go along with them suddenly arrive. I know it's not a lot slower but in a complex financial system it all adds up believe me.
Floating point arithmetic can get it's sums wrong.
Don't believe me? Then pull up a Ruby console and try this:
%% a = "69.54".to_f b = a * 100 b.ceil %%
Gives 6955 instead of 6954. This is because the limitations of floating point arithmetic have caused something like 0.0000000000000000000000000000000000000000000000001 to be added to 69.54. I spend a good 4 hours chasing this bug which manifested itself as a 1p discrepancy.
Trailing zeros can cause problems for major units.
Think of trying to pass round £10.00 or £1.10 in major units. Storing it as a float you would keep losing the trailing zeros and would find yourself having to sprintf all over the place. I've seen plenty of systems in my time that store prices as decimal strings to get round these issues! There are of course various decimal formats that can be used (decimal is a data type in MySQL and BigDecimal has been introduced in Ruby on Rails) but when it comes down to it, these are just wrappers around either floats or stings and majorly sub-optimal for the other reasons given.
Freeze the Exchange Rate
If your business works in pounds but you allow payments to be made in Euros then with every payment you need to store the current exchange rate with it. Exchange rates change by the day and if you don't know exactly what rate you get for your transactions then you can kiss goodbye to any sort of accurate profit calculations.
Rounding - Pick a Direction and Stick With It
Often you will need to apply discounts, add markup etc and have to perform percentage calculations. If you are working in minor units this should be the only time (in normal day to day operations) that you ever have to handle fractions of pence. You will make your life so much simpler if, for all these calculations you decide the direction to round and stick with it. Do you want to keep the extra for yourself or be a nice guy and let the customer keep it? That's what the decision comes down to.
If you don't have consistency in this you really will find yourself spending days chasing 1p discrepancies.
From a coding point of view I tend to round down as preference because (as I demonstrate above) floating point arithmetic can get it wrong sometimes and, as it just wipes out everything after the decimal point, a 'floor' function is much more reliable that a 'ceil'.
Use a Pre-Filter on your Data Submissions
Of course your customers are always going to want to work in major units - no-one wants to see prices in pence splashed all over your website and it's much more intuitive to type major units into form fields.
What I like to do is put a pre-filter on all input coming into my back end system (so in Rails you would run the filter on 'params' or in PHP you would run it on '$_REQUEST') which pattern matches any string monetary amount (remember, all form submission values come through as strings) in a major unit and converts it to an integer minor unit.
In Rails it's in the application controller and looks like this:
%% def filter_units (input)
if [Array, Hash, HashWithIndifferentAccess].include?(input.class)
input.each do key, value #recurse through the data structure input[key] = self.filter_units(value) end
#match the string format for a major unit elsif not input.nil? and input.match(/^d+.dd)$/)
#convert to a minor unit integer (input.to_f * 100.0).to_i
#return the value unchanged input
This also has the added benefit of validating monetary amounts - if a monetary field doesn't hit your back end as an integer then you know it has failed validation.
The Benefits of RESTful DevelopmentREST or Representational State Transfer development is quite simply web development with controller functions geared around the four HTTP request types (or verbs) - POST, GET, PUT and DELETE, equating these (classically but by no means exclusively) to the CRUD operations Create, Read, Update and Delete respctively. Once you start developing in REST the advantages of this quickly become clear:
* Restricting your controller functionality in this way naturally prevents you from building bloated controllers
* It ensures that the layout of your code doesn't become too obfuscated
* It allows you to make calls without having to specify your controller action explicitly in the request (as you do in a normal HTTP GET request).
Basically RESTful development is all about nouns, and a complete RESTful design will have the entire functionality of the website broken down into nouns that can be manipulated exclusively by CRUD operations. Each noun will be a controller (and often but by no means always it will also be a database model) and each controller will have up to four functions to represent each CRUD action.
For example take very simple online CMS with a database of users who can log in and change the text on various pages. A RESTful design might look something like this:
Noun - 'user'
POST - Create new user
GET - Read user details
PUT - Update user
DELETE - Delete user
Noun - 'page_text'
POST - Create new text
GET - Read text
PUT - Update text
DELETE - Delete text
As you can see, RESTful design where the nouns are models is very very straightforward and logical. But what about allowing the users to log in? We don't have a 'login' model in the same way as the users and page_texts, but we can represent the action in a very similar way:
Noun - 'login'
POST - Log a user in (create a 'login')
DELETE - Log a user out (delete a 'login')
And if we wanted the ability to preview new text before saving it:
Noun - 'preview'
POST - Show (create) a 'preview'
Now everyone knows how to send GET and POST requests but what about PUT and DELETE. Despite being part of the HTTP protocol since day one they are surprisingly under-used. All modern server-side languages should accept these as valid HTTP methods but in practice the PUT method is rarely used for an update operation as this can be distinguished from a create operation simply by the presence of a key relating to the noun that will be updated:
POST request with no key - Create
GET request with key - Read
POST data with key - Update
DELETE request with key - Delete
It really is that simple. It doesn't take much thought to break down any operation into one or more nouns with one or more of the CRUD operations being performed on it. Simply remember that a noun does not necessarily have to represent a database model and it does not necessarily need all the CRUD operations to be defined in its controller and you'll be off programming RESTfully in no time.