I have an application that needs to accept and output values in both US Custom Units and Metric system.
Right now the conversion and input and output is a mess. You can only enter in US system, but you can choose the output to be US or Metric, and the code to do the conversions is everywhere.
So I want to organize this and put together some simple rules. So I came up with this:
Rules
- user can enter values in either US or Metric, and User Interface will take care of marking this properly
- All units internally will be stored as US, since the majority of the system already has most of the data stored like that and depends on this. It shouldn’t matter I suppose as long as you don’t mix unit.
- All output will be in US or Metric, depending on user selection/choice/preference.
In theory this sounds great and seems like a solution. However, one little problem I came across is this:
There is some data stored in code or in the database that already returns data like this: 4 x 13/16" screws
, which means “four times screws”. I need the to be in either US or Metric. Where exactly do I put the conversion code for doing the conversion for this unit?
The above already mixing presentation and data, but the data for the field I need to populate is that whole string. I can certainly split it up into the number 4, the 13/16″, and the ” x ” and the ” screws”, but the question remains… where do I put the conversion code?
Different Locations for Conversion Routines
1) Right now the string is in a class where it’s produced. I can put conversion code right into that class and it may be a good solution. Except then, I want to be consistent so I will be putting conversion procedures everywhere in the code at-data-source, or right after reading it from the database. The problem though is I think that my code will have to deal with two systems, all throughout the codebase after this, should I do this.
2) According to the rules, my idea was to put it in the view script, aka last change to modify it before it is shown to the user. And it may be the right thing to do, but then it strikes me it may not always be the best solution. (First, it complicates the view script a tad, second, I need to do more work on the data side to split things up more, or do extra parsing, such as in my case above).
3) Another solution is to do this somewhere in the data prep step before the view, aka somewhere in the middle, before the view, but after the data-source. This strikes me as messy and that could be the reason why my codebase is in such a mess right now.
It seems that there is no best solution. What do I do?
Question
My goal is to figure out how to structure and where to place my unit conversion code within the system. Software system in question is MVC-like (Zend Framework 2 – like) LAMP system.
Specific Example
Right now I have some class that given an id
at creation time, has a method getValue()
, which returns 4 x 13/16" screws
. Depending on id
, different numbers can be produced, but they are still in inches. I should note that some numbers are written with the dividing bar (13/16"
) and some use decimal notation (0.8125"
). How could I set up my framework so that I can display such values in millimeters as well?
3
The best way to handle multiple conversions like that is to create a Unit of Measurement
type class for your application. The UoM
class will allow you to encapsulate all of those intricacies within a single area, and the rest of the code can simply call in and specify the units they need the value to come back in.
Essentially, what that does is it transforms a unit of measure into a first class object within your system. You’ll store the value as well as the units associated with the value. If you need to convert the original units to another type, then you make a conversion call against the UoM class.
One big benefit of this is approach is that all of the ugliness of parsing and converting is handled in one place, and it sets you up for the ability to use existing external libraries where someone has already done all of the hard work for you.
For a units heavy application with a lot of unit conversions, “base classes” like this belong in their own layer and not within an MVC structure. You are in essence creating a new fundamental type or primitive for your application.
But if you’re really bound to using MVC or your app just doesn’t have that many unit conversions, then the Controller would be your best bet as it can converse with both Model and View. You could also justifiably argue that the Model would be a good area if that’s where you’re putting business logic.
13
Never store strings like 4 x 13/16" screws
in your code or your database. Make it a placeholder string like 4 x {0} screws
, pass it around with the actual value in internal units (in your case US inches), and only when your program finally presents this to the user, it will replace the placeholder by a value either in inches or mm (according to what is actually configured). If your program needs to present US values sometimes as fractions, you could use placeholders with some “hint” symbol (for example, use an f like {0f}
to make sure inches will be displayed as fractions.
Of course, you should try to have only a small number of conversion routines (ideally just one) in your whole program, and a single place where the switch for US units vs. metric units is placed. Having the same information redundantly, or different conversion routines for the same purpose is extremely error-prone. So the central conversion routine should be reused wherever possible. So when I got your alternatives 1, 2, and 3 right, this leads right to option 3. If this becomes messy is up to you, but I think it is possible to handle this without making your code unneccessarily complicated.
3