2

I work in a production company where my colleagues calculate costprices based on 3D models and their respective operations. Apart from workactivities where a user has to insert an operation time and setuptime, most operations are calculated automaticly. Currently, this is done in an Excelsheet. I am responsible for improving an existing software product (C#) where those algoritms are migrated to.

These automatic operations are calculated on a high variety of parameters, which depening on the workactivity (unique by certain code).

I would draw a workflow like below:

Workflow of the desired program

The project will be used in a view for the user but also for recalculating the current database.

Some examples

  1. The operation of bending a plate. The operation and setuptime is based on the length of tooling which is used, the number of stations and number of bends. Each of those numbers are then multipied by another variable, say a "setting" variable?

  2. The time we calculate to prepare a single product before it goes to production. This is based on some parameters as described in the previous paragraph, but also if the product contains workactivity A, workactivity B or is an assembly. And if so, a certain time is added..

  3. A workactivity where there user is counting holes and based on the material, required quality (user input) and thickness, an operation and setuptime is calculated. Or another workactivity which is based on a table of minimum and maximum product length.

  4. A workactivity which is calculated in money, not time. There are some which are based on containing an outsourced activity. If yes, then two workactivities are added with a price depending on the outsourced activity (some require more money because they are done further from the company).

Now ofcourse this can be done with an endless chain of switch- and if-statements but something tells me that might be the worst way to go. I have checked the Refactoring Guru but I can't quite find which one should help me, or if I am looking in the right direction.

Jannick Breunis
  • 119
  • 1
  • 7
  • 2
    I see a lot of unique and optional calculations happening here but architecturally aren't you just adding these up? Where's the complexity? – candied_orange May 19 '22 at 18:11

2 Answers2

1

The decorator pattern may be of help here. The idea being that optional behaviors can be mixed and matched arbitrarily with construction code rather than a forest of if branches.

This can end up requiring a significant number of classes. So look at it critically before committing to it. It's work mocking up alternatives and refactoring to see if this pattern is really adding value.

But it will give you a way to optionally invoke behaviors. I can see this helping if selecting a parameter means the code must prompt for more input. If all you're doing is adding up the sub totals of a fixed number of "parameters" then remember, zero is a powerful number.

candied_orange
  • 102,279
  • 24
  • 197
  • 315
1

There are a couple of approaches possible here. To name a few:

  • create dependency network: the parameters of your excel sheet would be nodes. The transformations that use these parameters to determine other ones would be another kind of nodes. The dependencies (input, output) are edges between the nodes. The problem is then reduced to a graph coloring: set the values of the known parameters and flag them as change. Propagate changes by finding the transformations having at least one input flagged, and determine the value and set and flag the output node.
  • create a rule engine using simple forward chaining: on one side a set of parameters, on the other a set of rules. Go through the rule set, one rule after the other. Look if you can execute the rule. If yes perform the calculation, look if its results require any change in the parameters. Once no rule produce any change, you can stop: you’re in the end state.
  • Use the interpreter pattern: The interpreter nodes correspond to the rules/calculation. The ”context” passed to evaluate the expressions of the interpreter could be a simple value table (parameter,value).

In fact all three examples are variants of the same principle (e.g. interpreter can facilitate implementation of rules, network is constructed by analysing the rules, interpreter can also be used to implement the network). See also this other SE answer about implementing a rule engine using interpreter, command and decorator patterns.

These designs are very flexible. They allow a hard-coding the rules (to avoid dealing with parsing components). But they also enable a dynamic configuration based on some configuration files (e.g. easy to read calculation rules/expressions that would be parsed when your system is started). And it’s fun to code.

The simple alogorithms described would of course need some more thoughts, for example if there are interdependencies between parameters and if some loops are needed to reach a convergence. Now, up to you to finish the work ;-)

Christophe
  • 74,672
  • 10
  • 115
  • 187
  • Thanks for the different possibilities to use, also the reference to the other post is very helpful. If I use the interpreter pattern, how do I define the "context"? Is that a self made class whose parameters are known by the [Rules](https://www.youtube.com/watch?v=2f5M6iyOu1Q)? If I understand correctly, the various (optional, so standard false or 0 as brilliantly said by @candied_orange) parameters should then go in this Context? – Jannick Breunis May 23 '22 at 11:23
  • 1
    @JannickBreunis indeed, the context is usually a class with which the interpreter interacts to get values to be used in the expressions. In my own experience it’s basically a table of variables, although for simpler use cases it can be a class with a limited number of fixed getter/setters. – Christophe May 23 '22 at 13:26