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?

  • 1
    You are in for a world of hurt if you try to represent a 13/16" screw in metric. It won't mean anything to anybody. BTW, how do you represent a #20 screw? 12 gauge wire? – BobDalgleish Aug 21 '14 at 17:17
  • I'd represent it as 20.64 mm (with rounding). Luckily I don't yet have to deal with #20 screws. – Dennis Aug 21 '14 at 17:51
  • Aside from the good answers already posted here, I will add that it almost sounds like you need a variant type, but for measurement systems, not primitives. This type would convert between measurement systems and be usable in either context. – user22815 Aug 21 '14 at 20:01
up vote 5 down vote accepted

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.

  • I don't agree with your last paragraph. To me, the UoM class is part of the business logic and thus belongs in a layer within the Model part of the MVC triad. – Bart van Ingen Schenau Aug 21 '14 at 18:21
  • @BartvanIngenSchenau - each app will have different requirements. I view UoM as a fundamental type. But I certainly understand the perspective of that representing business logic, and in that case I agree with your assessment. – GlenH7 Aug 21 '14 at 18:46
  • 1
    It's a class, and the class handles the conversions for you. So you might have UoM myUOM = new UoM(12, "inches); and then myUoM.getLength("centimeters"). Pick a method / function syntax that makes sense for your app. – GlenH7 Aug 21 '14 at 20:38
  • 1
    owie, just realized I'll have to (re)define all the operations on this type such as *, +, -, /, pow(), etc – Dennis Aug 21 '14 at 21:25
  • 1
    I think this is a valid approach, but for a program which uses mostly one unit system (US) for all internal operations (and so most business logic), and only converts to metrics in the parts which are presenting information to the user, this has a high risk of making things unneccessarily complicated. Or at least, the conversions maybe restricted to the view part. – Doc Brown Aug 22 '14 at 5:54

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.

  • I'll have to think about this.. I'd rather not have it become a type (aka type == coupling the placeholder string with the value that knows its own type (i.e. inches) into their own struct/class), as this will complicate the code a bit. Also this string is more of a special case. Most other times I just need the value to plug into a specific HTML spot. Here I have a string that I will need to plug a value into, and then take the resulting string and plug it into HTML.. – Dennis Aug 21 '14 at 20:58
  • 1
    @Dennis: my general suggestion you clearly separate any presentation information (like strings or HTML) from the actual values. – Doc Brown Aug 22 '14 at 5:50
  • good point. I have separated those out! Surprisingly the pain of doing that was less than I thought it would be. – Dennis Aug 22 '14 at 15:24

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.