The Transformational Power of Weak Connascence (Part 1)
I hope you enjoy the post this week. I’m experimenting with storytelling, so please let me know if you like (or hate) this approach.
Fools ignore complexity. Pragmatists suffer it. Some can avoid it. Geniuses remove it. — Alan Perlis
The atmosphere on the Zoom call was filled with apprehension. The software engineering team at Acme Corp had come to dread this weekly ritual. The ambitious e-commerce platform they’d built over the years was starting to show its age. It had become a nightmare to maintain. Everyone knew fundamental improvements needed to be made, but who had the time? The team was already months behind on contractually obligated features for their customers.
The codebase has become a tangled mess over the years. What started as a straightforward application has progressively grown in complexity with years of patches and features added by different teams to accommodate unique requests by its customers. While attempts were made to modularize the system, it just made things worse. The application was somehow both a distributed system and a monolith. The code was spread across many repositories, simultaneously making it difficult to reason about and, counterintuitively, tightly coupling the system. Changing the code in one repository could (and many times would) impact code in a dozen other places. This led to a brittle system in which every part seemed to be interdependent on the other.
Susan, a newly hired software engineer, looked at the proposed features for the quarter. Her usual optimism had faded. “It’s obvious that we need to update the payment processing service to meet our compliance obligations, but honestly, I’m dreading this.”
The team was well-acquainted with these challenges. They had navigated through similar situations numerous times. The sequence was all too familiar: update the payment module and the shopping cart malfunctions. Fix that, and the user authentication starts acting up due to session caching issues. It felt like a never-ending game of whack-a-mole. One issue was fixed, and three new ones emerged.
Justin, the QA lead, sighed. “Last time we touched that module, it took us weeks to iron things out, and we still missed a critical bug that went live.”
The team had tried refactoring parts of the code before, but it was like trying to untangle a knotted ball of fishing line; pulling one thread only made the knots tighter elsewhere. The dependencies were so deep and intertwined that no one felt confident making even the smallest changes.
“I’m spending more time trying to figure out what might break than actually writing code,” said Juan, a junior developer on the team. “It’s like walking through a minefield. One wrong step, and everything blows up.”
The dread spread to the others on the call. It wasn’t just a fear of introducing new bugs but the sheer mental exhaustion of dealing with an unmanageable codebase. The joy of building new and exciting technology had been replaced by the constant anxiety of what might go wrong next.
Susan knew something had to change. Things as they were were not sustainable. But the question was: how could they turn this around without burning the entire thing to the ground and starting over?
Connascence and Complexity
How do we even start to talk about complexity? You might have heard about the term coupling in software. Ideally, systems prefer loose coupling over tight coupling; that is, we try to reduce the amount of interdependencies on any two parts of a system so that if we need to swap out a component, it is easier to do. This becomes important in software because software must change over time, so reducing the complexity between parts will also help reduce the burden of change. But have you of Connascence? This term helps us measure how intertwined parts of your system might be.
Two components are connascent if a change in one would require the other to be modified in order to maintain the overall correctness of the system. — Meilir Page-Jones
Connascence is a powerful tool for reasoning about complexity. I first learned about this concept while reading The Fundamentals of Software Architecture by Neal Ford and Mark Richards. In fact, not only did we discuss this book on Book Overflow, but we were fortunate enough to interview both Neal Ford and Mark Richards about the book. These concepts are further enforced in Neal’s book Building Evolutionary Architectures, which we’ll be discussing soon on the podcast.
The connascence ranges from weak to strong and from static to dynamic. Counterintuitively, the weaker and more static the connascence, the easier the system is to change. The stronger and more dynamic the connascence, the more complex the system is to change. An example of an ideal static and weak connascence is the Connascence of Name, in which two parts of a system only have to agree on a name to define their connection. An example of a strong and dynamic connascence would be the Connascence of Timing, in which the timing of a system binds two components, so a change in timing would affect the relationship between the two components.
When changing some code, we have many “find and replace” tools that can quickly help us with static analysis in naming, making changes bound by names trivial. Making a change to timing is complex because I’d have to have access to the runtime to make these changes.
A third consideration when considering connascence is a concept called locality. The farther two components are from one another, the weaker the connascence should be. The closer the two components are, the more acceptable a stronger connascence should be.
This also means that if we have a non-local system with strong and dynamic connascence, we can work on refactoring the system to favor using weaker and static connascence (or move some of the components closer together).
With this new design language under our belts, I think we’re ready to return to Susan and her team at Acme Corp. (but that will have to wait until next week).
Notables links this week
We discuss Recoding America by Jennifer Pahlka (Book Overflow)
Conversation with Apple Design Award Winner Devin Davies (Book Overflow)
Finding the biggest shape in the universe, a cool bit of Computer History and Math