It’s obvious from my recent writing that I’m a big fan of Test-Driven Development. Last time I talked about how TDD enforces good code architecture. It is particularly good at forcing you to decouple your code modules from each other. Tightly coupled modules are more difficult to test.
“Coupling” is a big term, though. What are the different types of coupling? How harmful are they? What can we do about them?
I recently came across the concept of “Connascence”. It’s a qualitative metric that describes how strongly different components of software are coupled together.
The basic idea is: what must multiple software entities agree on for the software to work?
In other words, if you change something in one part of the codebase, do you have to make a corresponding change in other places? How many other places do you need to change it, how easy is it to find those places, and how easy is it to miss one of them?
The simplest, least harmful (a.k.a. the weakest) type of coupling is Connascence of Name. In order for module A to call a function from module B, they must both agree on the name of the function. This is perfectly fine, and indeed inevitable.
A more harmful (i.e. stronger) type of coupling is Connascence of Meaning. Multiple parts of the software must ascribe the same meaning to a value or variable. Examples include:
- “Magic numbers”
- primitive types (i.e. ints or floats) representing values with units (dollars, meters)
- special return values that represent errors rather than valid function results
Since meaning is a stronger connascence than name, you can refactor the code to move the connascence from meaning to name, for instance by declaring clearly named constants, or adding units to the variable names.
I won’t step into the static vs dynamic-typed flamewar, but it’s clear that codebases in dynamically-typed languages such as python more easily suffer from Connascence of Type. You often don’t find out about these errors until runtime.
There are different types of coupling. There are also three different properties of coupling in a codebase. They are:
- strength (how easy is it to refactor?)
- locality (how close are the coupled components to each other?)
- degree (how many different components are affected by a particular instance of coupling?)
I found the Connascence website so valuable because it gives concrete examples and definitions of things that I’ve long been treating as vaguely defined code smells. I feel like I can have a better conversation with fellow engineers about these issues.
From the website itself (emphasis mine):
Arguably one of the most important benefits of connascence is that it gives developers a vocabulary to talk about different types of coupling. Connascence codifies what many experienced engineers have learned by trial and error: Having a common set of nouns to refer to different types of coupling allows us to share that experience more easily.
I love this concept. Share it with your friends and your team, and you may find your discussions about software architecture a little easier to have. Who knows? Maybe your own code will get better.
That’s the dream, right?
Be safe out there, and happy developing.