2

TL;DR:

I have bad, no .. horrible, horrendous code that kind of works but is a mess and is not easily maintainable.

I want to redesign it and repackage it to where objects are well defined and messages that pass between the objects are well-defined, and the whole architecture makes sense and is easily maintainable.

This is a "new design requested" question but with some mind towards already existing code that will need to be refactored to the new design.

Details

I have some code that generates values and unit denominations and also extra formatting. Units can be English or Metric.

Examples when Metric

A = 3,000.65mm
B = 0.00mm +/-1.5
C = 2 x 20.64mm holes
D = 270.40mm +.00/-1.5
E = 2 x 228.60mm TYP.
F = 0.000mm +.00/-1.5
G = 0.000mm

Examples when English

A = 126.55"
B = 8 x 0.81" holes
C = 19.58" +/- .06
D = 2 x 9.00" TYP.
E = TBD
F = 0.00" +/- .06
G = 0.00"

Where A-F are variables in associative PHP array and the values on the right of the = sign are string.

Problem

Depending on a particular product I need to show only certain values (i.e. A, B, D) and hide values that are 0. Depending on particular product options I need to show one value but not the other (i.e. show C or E but not both).

Source of the Values

That is the output that I get from database. It gets written into the database in this exact format as above and that is the source data that I get.

How does it get into the database?

First, user selects unit system Metric or English, then selects a product, and various product parameters, which are computed, the above output is created, formatted, and inserted into the database.

The database uses a table and table columns that are shared between different product types. So, for example one product can use above variables A, B, C, but another may only use D, E, G, but a third one uses A, C, F. Also, sometimes product options dictate using say variable X for option X and variable Y for option Y.

Problem 1 - values that should not be there at all

Each of the values above describe some type of physical dimension, with extra info and sometimes with tolerances. Some of the code that generates the values however is faulty. When a particular physical dimension is not available for a certain product, a value is generated anyway but is 0 (see last rows of above examples).

To deal with the 0 values what I do now is I have a formatter class that cleans the values, and then blanks them out if they are effectively 0. So I remove the " mark and I remove the mm mark and I check if the value is 0. If it is, I remove that associative (key => value) pair from the array, so that it does not show in the view.

Problem 2 -- values that hide/show based on business requirements

As mentioned above, different products use different columns for data in the database, and once read from the database the different product options may optionally use different variables to display depending on the options.

Understanding

The current code is quite convoluted. The above gives out the essentials. Going into details there are probably around 10-20 classes total that run this and trying to come up even with a skeleton code showing what I have now may be out of scope here. So, instead of trying to convey the exact picture of what's going on exactly in my code for purposes, I am thinking of starting off with a better design and then porting things accordingly.

Question

That is, I want to get a clear design and identify clear boundaries and define clear messages to produce values above, according to product types and product options.

My initial thoughts are

  • keep data in most basic numeric format
  • keep unit denominations separately
  • keep extra formatting (descriptions, tolerances) elsewhere
  • not sure what to do about quantities in values like 2 x 6.50" TYP
  • keep business logic that figures out what values to show for which product and for which option in a code component (class object)

Currently everything gets written to the database as in above examples. There is a huge backlog of this in the database, so any design change will either have to deal with this or I will need to redo the database as well (not desirable).

Goal:

Come up with a clear design that given product and product options computes "which values to show" and formats them appropriately, like above, but giving me control at the start, ending with showing those values

That is, instead of me having to try to control the values when starting from those values.

Is this doable?

In response to Robert:

Use database to store raw numeric values

To accommodate for that I will need a fairly major redesign of the entire structure. To do this in one step will be prohibitive at the moment. I will need to think on how to mitigate that...

I still need to consider my situation as it is now where I am dealing with breadth of the existing code and don't have a luxury to design from scratch, and I will need to think long and hard on how to fix that.

i.e. my next immediate task with this code is to fix values that are incorrect and hide values for variables that are showing that should not be showing -- for a specific new variation of a product. "Simplest" thing is to add/modify yet another class to accommodate for the business logic, once I figure out where that is exactly.

maintain values in a default unit system, or system explicitly stated

all values are currently stored in English unit system so I will keep that route (that is all values that are not already encoded with a unit system, such as in original examples above)

My current thoughts

I am thinking of a special formatting class that knows for example how to take a raw number value and transform it into something like 2 x 228.60mm TYP. Well actually I am thinking of several classes..

  • First takes raw numerical value of 9 (inches assumed), converts it to 228.60mm, if Metric system is desired.
  • Then special formatting class takes that and applies business formatting to form 2 x 228.60mm TYP..
  • Then somewhere I will have a system that connects these formatters, and before that, a system that selects the values to show, and if there are alternative choices based on options,

That is a the system I am thinking of designing, beyond what has been stated so far. Having raw numerical values in the database is a precursor to that, but not the entire system.

I am seeking more advice on how to structure and organize this system.
Do I have a chain of command approach or something different?

i.e. something like this:

//get raw numeric data - assumed English Units
// 9 (assumed inches)
$data = $this->repository->getData($product = "P", $model = 20);

//transform into appropriate unit system
//9 => 228.60
if ($system === "Metric")
    $data = (new EnglishToMetricConverter())->convert($data);

//228.60 => 228.60mm
$data = (new UnitAdder($system))->addUnits($data);

//from $data = {'A' => 1, 'B' => 5, 'C' => 6, 'D' => '228.60mm'};
//to $data = {'A' => 1, 'D' => '2 x 228.60mm +/- 1.5'};
$data = (new BusinessLogic($product, $model))->trimData($data);

//send to view
return $view->setVariable('data', $data);

the techniques or a general overall system design is what I'm seeking. What I typed up above in the code is relatively simple and complete and can be understood at a relative glance. I wanted to be more sure that that is what I want to do before going ahead and doing it.

What I have now in my current code is on the order of 20 classes doing bits and pieces of the above, while trying to deal with existing formatting issues, passing data in unorthodox ways and there is no clarity in understanding. I suppose any improvement is an improvement, but if I am do undergo an improvement I want to maximize maintainability now and not later! Hence my question.

1 Answer 1

1

Your fundamental problem here is that you are storing formatted values in the database as strings. Don't do this. Always store the actual numbers as first-class values in the database instead.

If you need a conversion, pick a unit of measure to be stored in the database (use a separate column to specify the unit of measure, or standardize on a specific unit of measure for storage), and then perform a conversion to the desired units at display time. For example, 1 inch becomes 2.54 centimeters.

You never need to store formatting characters in the database unless it's part of a larger, overarching strategy to provide globalization/internationalization capabilities. Most software systems already provide tools to help you do this so you won't need to do this yourself.

Tolerances should also be stored as numbers, so that you can do things like statistical analysis.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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