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.

  • Does this answer your question? How to tackle a 'branched' arrow head anti-pattern? – gnat Feb 1 at 3: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 1 at 7:03

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.

  • 1
    Thank you for the recommendation on the rule engine -- I found noolsjs which has provided to be a great method of doing this in JS. – Justin Feb 5 at 3: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 5 at 7:14

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) {...}

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

  • 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 1 at 16:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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