Wednesday, October 10, 2018

For Coupling, Ask "Does This Express a Semantic Relationship?"

There are two kinds of relationships you can form from a class:
  1. The fulfillment of a semantic need.
  2. 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.

A diagram depicting four classes. InvoiceGenerator depends on Client and has references to two other classes: BillablesStore and ExpensesStore. BillablesStore and ExpensesStore also depend on client and each has a method that can be used to get the relevant kind of entity for a given client.

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.

A UML Diagram depicting four classes. InvoiceGenerator depends on Client, Connection, and Command. Connection and Command have the usual kinds of methods (e.g., open, close, prepare, execute).

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?

The same diagram as before with the database-related classes circled in red and a note that says "new DB tech forces change to invoicing!"


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.

A description of the back half of the original design, where BillableStore and ExpenseStore depend on Connection and Command.

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.

All the previous classes in synthesis. A UML Diagram depicting the merger of the designs from the first and fourth pictures in this entry.

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.