Single Source Of Truth
Collation Of Concerns
In the previous chapter Separation Of Concerns, we established the value of a single module of code only dealing with a single concern.
The complement to that is to pull all the code that deals with the same concern into a single module of code. In other words, collate all the code that deals with a single concern, and put it in a single module.
This improves readability. For a single given concern, the corresponding code only needs to be read once. The reader will not find themselves wondering "Wait, is this code essentially the same as that other block of code I read earlier?"
A single code element that captures a single concern and is used in more than one place is known as the 'Single Source Of Truth'. The name highlights how the structure supports the correctness of the code. Robustness is improved, not just readability, as we'll illustrate in the following example.
Single Source Of Truth
Consider a piece of code dealing with some important concern. It need not be very big - for example, it could be a single configuration value, perhaps just a boolean flag. Or it could be something bigger, such as a function that does some mathematical calculation.
Now consider the situation where the code is duplicated - there are two (or more) functionally identically pieces of code. Now let's imagine that at some point in time, the two copies diverge so that they are no longer identical. This can easily happen if, for example, one copy was updated, but the other was forgotten. Finally, let's assume that the divergence is a bug, the program as a whole is no longer correct.
The obvious solution is to not have duplicates, but rather to have a single piece of code that deals with the critical concern - the Single Source Of Truth. That way, when the concern changes in any way, code needs to be modified in only one place, and overall program consistency is always guaranteed.
Similar Sources Of Truth - Do Not Collate
Now consider the superficially similar situation: There are two (or more) functionally identical pieces of code. But now, the two pieces of code have different purposes or meanings; they are semantically different. In other words, from a certain point of view, the two apparently-identical pieces of code do not deal with the same concern.
This may seem very subtle and confusing - how can we tell if two apparently-identical pieces of code deal with the same concern? The litmus test is this: Could the two pieces ever evolve in different ways so that they are no longer identical? As the code base changes over time, could it ever be correct for the two pieces to be no longer identical? If the answer is yes, then in the most important sense, the two pieces of code do not deal with the same concern. Therefore, they should not be collated into a Single Source Of Truth.
Because this point is quite subtle, and the misleading advice "Don't Repeat Yourself (DRY)" is often mindlessly followed, we often see this anti-pattern of superficially identical code fragments being collated into a Single Source Of (More-Than-One)Truth. One sign of this that the code module for the Single Source Of Truth has acquired a parameter or two to 'handle the different cases'.
A single parameterised function is generally worse than two separate but simple functions, even with considerable code repetition. A parameterised function is much more onerous to test, and much harder to read and reason about. Getting the parameter wrong for the use case is a potential bug. So just use two simple separate functions. Fight the demon of Abstraction Addiction!
DRY Done Right
The advice in this chapter on when to abstract out a Single Source Of Truth is essentially the ideal intended outcome when the overly-simplistic advice "Don't Repeat Yourself" is issued. In other words, a well-crafted Single Source Of Truth is 'DRY Done Right'.
To summarise:
- Separate Concerns in the code base, so that the code now comprises of many individually coherent code modules.
- If two (or more) code modules appear to have identical functionality, ask the question: "Could it ever be correct for these two modules to diverge so they are no longer identical?"
- If the answer is "Yes", then leave the two code modules alone. Do not merge them.
- If the answer is "No, for program correctness, these two code modules should always be identical", then Collate Concerns - merge the separate code modules into a Single Source Of Truth.
🙠