2

Say I have the following data-structure describing a given widget sold by my company, which contains fields of purely atomic information (i.e. data that cannot be otherwise derived from other available fields).

my-widget = { "widget-id": 1, "amount-sold": 100, "profit-per-sale": 0.2 }

Suppose that across my app(s), in addition to the information above, I might want frequent access to the total profit accrued from sales of the widget, calculated using

calc-total-profit(widget-info) = widget-info.amount-sold * widget-info.profit-per-sale

There are two approaches I see available:

  1. Merely call calc-total-profit whenever I need it, even though that may be with significant frequency.
  2. Append the result of calc-total-profit when I initially create the data-structure, and access it directly whenever its required.

I feel like option 1 is more "correct" in that the data-structure ends up containing only the information it absolutely needs, and nothing else. Though it will result in perhaps slightly more crowded and repetitive code.

On the other hand option 2 may result in code that is otherwise more parse-able. However, this is a simple example, and I could see one being able to justify multiple other calculated fields (for example: total-profits in different currencies), conceivably leading to data-structures that begin to "bloat".

I feel like this must be a well-tread dilemma, but I've perhaps been unable to pick out the correct search-terms; I would be interested in reading more about this topic if material/wisdom is available.

3

The answer depends largely on the mutability of the structure. If the values used to create the calculation can change, then storing the computed result can be a source of bugs. That is, you must ensure that it is recalculated when the inputs to the calculation are updated. This is achievable but adds risk. I would avoid it unless the cost of the calculation is high enough to justify the additional code and testing. This is especially true if you are working in a multithreaded application. Encapsulation is your friend if you need this optimization: you don't want to be searching around the code for all the places the data might be changed or worry about someone adding some new code that changes values and doesn't know about they need to recalculate the composed fields.

However, if you are using an immutable data structure, there's really no risk with doing this. I wouldn't bother if the cost of doing the calculation is very small but the effort associated with composed values on immutable structures is much lower. You could either calculate this when the structure is created or lazily when it is access and store the result. This is yet another reason why immutability is a very good thing.

0

The collection of techniques/tools called Optics holds the true, and most elegant, answer here. You can have your datastructures of completely pure and atomic information, and make access to frequently calculated information as easy as normally querying any field, by making a Lens or similar entity for it. The lenses etc. should always be available wherever your datastructure is available.

Lenses (and Optics in general) are a pretty dense/abstract topic and can be a little difficult to grasp at first. I've found the Optics By Example book by Chris Penner the most useful in gaining a better understanding, in addition to a couple of the blog-posts/tutorials on adit.io.

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.