2

I am creating a plugin that uses a metric to determine a score on one page and allows the user to click through to see a more detailed breakdown of the score on a separate page.

The trouble is: I can't decide whether it is best to re-implement the logic used to derive the initial score when generating the breakdown. On the one hand, the same logic should be used in both cases. The score should be the same; the breakdown code should just run some extra queries to give more detail on what constitutes the score.

Re-implementing (what should be) the same logic using new methods could run afoul Segal's law: "A man with a watch knows what time it is. A man with two watches is never sure." If anything changes about how the metric is calculated then the two scores (the one shown initially and the one in the breakdown) could diverge - at least the logic would need to be updated in both places.

On the other hand, it seems cleaner to have methods that have a single purpose (or as few as possible). Running through the same methods means using a flag to determine whether we are generating the simple score or the breakdown. Adjusting the behaviour of the methods in this way, depending on the flag, makes the code more complex, harder to see the purpose of, and harder to maintain. The score that is calculated should be the same. If it is not, then that points to a fault in the logic. One solution would be to create new methods to calculate the breakdown and then create some unit tests to check that the scores match. That provides the extra benefit of revealing flaws that would otherwise be hidden (a man with two watches is more likely to know when a time-telling device is unreliable).

I am not really asking for an answer in my specific case as I am sure it will depend on the details (how much extra work is being done in the breakdown, and so on). The question is: What should I consider when deciding how to re-use application logic in a situation like this?

1

"Where is truth?"

There should be a single authoritative source for the score value.

You seem to think that you can have two different methods that take different inputs, but can both accurately calculate the score, but that is not possible. Both of these score methods you propose must take the same inputs, the only difference is that one produces more than just the score, it also produces some sort of breakdown object. Just use the latter score method and ignore the extra returned information. Only denormalize (i.e. Have two sources of truth) if there is a clear performance benefit.

As an analogy, when you get a user object, but only plan on using a proper subset of its fields, you don't think to make a new User class with just those fields. Same thing here, you are calculating a score breakdown, but only using a proper subset the the returned information.

  • That makes sense, thanks. Both answers so far (@Spotted's and yours) are useful. Currently my calculateScore method only returns the score value but I will change this to return all of the data it uses to calculate the score and then create a new calculateScoreDetails method to retrieve additional details. In my case, there are performance considerations, since the page on which the simple score is displayed will be loaded frequently and it will be used on large sites. This does not amount to denormalization, rather, the equivalent of an extended_user table, only relevant to a few users. – Guambra Feo Mar 4 '16 at 13:17
0

You could implemented a first method, let's say calculateScore that executes when the user sees the first page.

If the user want to see more details, a method calculateScoreDetails should be executed. Its implementation will be a call to calculateScore plus some extra queries you mentionned.

0

Cohesion affects code from both directions. It splits things that are unrelated and groups things that are related. In your case, the code that calculates the full score and one that calculates detailed score have high cohesion. They are same thing, just slightly different. So both should be represented by same thing.

BUT in your case, that thing will most probably be a class or a module (whetever your language supports). Taking a function as "unit" is too limiting, just like you are experiencing right now.

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.