6

I am developing an application that needs to programmatically determine the complete state of a DC motor, given a limited number of details about the state. For example:

{
  voltage: Measurement(12, "V"),
  rpm: Measurement(5000, "rpm"),
  currentDraw: undefined,
  torque: undefined
}

This object would be passed to a function that calculates the values of currentDraw and torque according to the defined properties of the object. However, it is not always voltage and rpm provided - it may be any combination of properties, and the ones listed above are not the only ones available (simplified for the question).

I would like to avoid this logic:

constructor(state) {
    if (state.voltage) {
        if (state.rpm) {
            state.torque = ... ;
            state.currentDraw = ... ;
        } else if (state.torque) { ... }
        ...
    }
    ...
}

As it's not clean and difficult to read. Plus with a large number of possible variables, the function would get very large very quickly.

Has anyone solved a similar problem before? All advice welcome.

lennon310
  • 3,132
  • 6
  • 16
  • 33
Justin
  • 71
  • 3
  • Does this answer your question? [How to tackle a 'branched' arrow head anti-pattern?](https://softwareengineering.stackexchange.com/questions/205803/how-to-tackle-a-branched-arrow-head-anti-pattern) – gnat Feb 01 '21 at 03:50
  • Is there a subset of properties (or some combinations of properties) that must be present in order to be able to reconstruct the full state? And if so, can you write the reconstruction logic in the form of `if not X, then calculate X from the properties that must be known and those reconstructed earlier`? That would keep the condition nesting low. – Bart van Ingen Schenau Feb 01 '21 at 07:03

2 Answers2

3

If you have a very large number of variables and hence a growing list of formulas to calculate missings. If moreover, there are identified dependencies in these formulas, the execution logic of your completion algorithm could become quite complex.

One way to solve it would be to use a rule engine. In your case it could be a very simple one:

  • It would use a set of rules, i.e. formulas that you can apply.
  • Each rule has some conditions, i.e. the variables that are needed to apply it (and perhaps also the missing variable that it determines).
  • You'd iteratively go through the set, to find the next one that you could apply.
  • Once flagged you can eliminate it from the subsequent iterations
  • You can also eliminate from the iteration the formulas for variables that you already have.

This is flexible: it's very easy to add new rules for new variables. It's straightforward to implement, since known variable do not change.

A variant of this approach would be to build a dependency graph derived from the set of rules (nodes=variables and formulas). The graph may allow you to find for each missing variable the formulas (rules) to be used by traversing the graph , and navigating back to the known variables. Order the set of formulas found int the path reversely based on the number of missing dependencies (some more thoughts may ne needed here). This is slightly more complex to implement, but would probably optimize execution. SO if you have a large dataset to be completed, it could be worth giving it a try.

Christophe
  • 74,672
  • 10
  • 115
  • 187
  • 1
    Thank you for the recommendation on the rule engine -- I found [noolsjs](http://noolsjs.com/) which has provided to be a great method of doing this in JS. – Justin Feb 05 '21 at 03:25
  • @Justin thank you very much for this feedback. It will help other readers working with JS to benefit from your practical experience. – Christophe Feb 05 '21 at 07:14
0

You are avoiding the simplest solution of them all, push the decision back a layer make the calling code or ultimately the user choose by having different methods for each valid combination of properties

class DcMotor
{
     DcMotor(float voltage, float rpm) {...}
     DcMotor(float currrentDraw, float torque) {...}
     ...etc
}

If you cant pre-decide in anyway then the conditional statements are unavoidable as you only have a limited number of hardcoded equations which determine the missing properties.

Using a rule engine simply moves your conditionals from your programming language to the rule engine rule language

Ewan
  • 70,664
  • 5
  • 76
  • 161
  • 1
    According to OP, it may be _any_ combination of properties; therefore it _seems_ to be unfeasible to preset them on overloaded constructors. – Emerson Cardoso Feb 01 '21 at 16:00