- The fulfillment of a semantic need.
- The exploitation of an implementation detail.
The former kind of relationship is far more resilient than the latter.
There are a lot of reasons why this is true.
The most compelling argument is the asymmetric relationship with change. A change to what you need invalidates an expression of both what to do and how to do it. A change to how something should be done, on the other hand, is unlikely to invalidate what need is being fulfilled.
So today's code quality question is "Does this express a semantic relationship?"
Consider the following.There are a lot of reasons why this is true.
The most compelling argument is the asymmetric relationship with change. A change to what you need invalidates an expression of both what to do and how to do it. A change to how something should be done, on the other hand, is unlikely to invalidate what need is being fulfilled.
So today's code quality question is "Does this express a semantic relationship?"
This is a great example of semantically-meaningful relationships. The invoice generator needs a client, the billables for that client, and the expenses for that client and that's how its relationships are expressed, above.
Let's consider an alternative design for the same problem that represents an all-too-common design decision.
In this case, the invoice generator uses information from a client object to make database-related calls to a database-oriented API.
...and that's just the problem. If anything changes about the implementation steps, you have to touch things that shouldn't be related. For example, is it reasonable that swapping out database technologies should involve a change to how invoices are generated?
Those aren't really related concepts. You shouldn't have to change how invoices are generated to swap out how you access your data.
Note that the semantic-ness of a relationship is evaluated for a specific class or code structure. Something that is a "how" for one class, can easily be a "what" for another class.
For instance, the billables and expenses store do need to access data somehow. Maybe the database-related APIs really are fundamentally a part of how they do their work.
This gives the who what/how distinction a fractal note. A connection that you decide is a "how" for one class may just be the "what" of another, lower level class.
That makes the question "Is this a semantic relationship" more powerful than one might initially guess. It gives you more options when the answer is "no". Maybe you just don't want the coupling at all. Or maybe the relationship represents a valid dependency that should live in some other, lower-level code structure.