Office hours again this Thursday! Come ask me questions. We can talk about anything.
I’m speaking at Heart of Clojure! Get your tickets. I’ll see you there.
I also decided to attend Madison Ruby this year because it’s local. I’ve never been to a Ruby conference, and I heard they are great.
Grokking Simplicity continues to sell well. Get your copy for 50% off with the coupon TSSIMPLICITY. If you have read it, I’d appreciate a review on Amazon.
Uncoupling by Michael Nygard
EDIT: I regret publishing this essay. It is not up to my standards and comes off as picking on Michael Nygard’s presentation. I violated my standards in at least three ways:
I critiqued the talk instead of the ideas in the talk.
I confused personal opinion (“I don’t like X”) with personal experience (which I do want to share).
I didn’t have a main point that could help you, the reader.
I apologize and commit to doing better. I have already apologized to Michael. Besides this message, I’m leaving the essay unchanged for posterity.
Today I am reviewing a talk. It’s called Uncoupling. It was presented in 2018 by Michael Nygard, whom I respect greatly as an accomplished and capable software architect. I’ve met him personally at Clojure conferences. A reader asked my take on it. I want to share my personal opinions about the content and presentation of the talk, finding the good stuff and critiquing what can be improved.
I didn’t disagree with much of the content of the talk, but neither did I find that it got concrete enough to find fault. A lot of my critiques are about the presentation, such as the use of vague terms. But I also want to address problems with the concepts themselves.
The talk is about coupling, a word we bandy about a lot in software engineering. I agree that the topic is worth addressing and spreading a common understanding. The talk aims to educate the industry about coupling and depict different kinds of coupling.
The talk gives examples of coupling in other engineering fields, where it is not a dirty word. He then gives a lengthy (3 minutes, 10 seconds) example of coupling between two moons of Saturn. There was a long chain of effects that linked the two together:
Phoebe is ablated by micrometeorites, causing dust
The dust is radiated unevenly by the sun, causing it to move closer to Saturn
The dust then hits Iapetus, causing discoloration on one side
I think the point was to show how pervasive and distant coupling can be if you look for it. The example was interesting, but maybe it took too long for the payoff. I think he should have made a callback to it later in the talk after all of the setup as an example of long-distance coupling.
He then talks about our servers being coupled to the ambient environment. The temperature and pressure at the data centers need to be maintained, or the servers will stop working. He’s inspiring appreciation for our physical operations. But was there a practical takeaway?
The first big takeaway is that coupling is inevitable, yet it is also necessary. It can also enable the functionality you want. I wished he had dwelled a bit more on this, drilling into how it affects us. For instance, I was waiting for him to say, “That means your job as a designer is to choose which coupling you want in your system—not avoid all coupling.”
He gives four categories of coupling:
Operational - one cannot run without the other
Developmental - programmers must coordinate changes
Semantic - sharing concepts
Functional - sharing responsibility
Incidental - no good reason
I’m not sure categorizing the types of coupling is doing much work. Are these all of the kinds of coupling (exhaustive)? I would guess no because of the grab-bag “incidental” coupling. I can even come up with a new kind of coupling, Bus Coupling, which is all the knowledge that would be lost if a particular programmer got hit by a bus. How does identifying which category the coupling is in help us? Do we address each of these differently?
I’ve recently been strongly influenced by Residuality Theory. It states that instead of classifying the coupling, we list possible changes. So, instead of looking at arrows on a diagram and thinking, “Is there operational coupling?” we imagine scenarios that might disturb the system. What if the power goes out? What if the network is partitioned between these two services? What if there’s a bug in the consumer? What if there’s a bug in the producer? By seeing what systems each of these scenarios affects, we operationalize the analysis of coupling.
He gave two interesting examples of domain modeling gone wrong. The first was about Stock Keeping Units (SKUs). They’re numbers that help us relate data from different systems. However, we colloquially use the term SKU to refer to the product itself. Over time, we start to think of the SKU as a thing that we have to model. The SKU becomes the name of the row in the database that contains all the data about a product. All of the data gets coupled together unnecessarily into one system. What kind of coupling is this? Incidental? (Does it matter?)
Within a domain, we start to think of certain concepts as being real and fundamental when in fact they're abstractions for bundles of attributes.
At the same time, it started to feel like this same phenomenon was happening with the term coupling itself. Are we taking an abstraction too far and thinking it has its own properties?
The second was about a concept called Price Point that they introduced as a layer of indirection between the SKU and the price. Then the concept of Price Point got leaked out and downstream systems had to change to support Price Point, even though all they cared about was the price. This was a form of semantic coupling that caused a lot of unnecessary changes.
He introduces the metaphor of a Semantic Polymer that couples long chains of components together because they share meanings. Do we need a new concept for that? I doubt it.
He goes over the example from the famous David Parnas paper On the criteria to be used in decomposing systems into modules. The paper is worth reading, but talking through the example is tedious. There’s software to make an index. Parnas shows the original design and his design, and he explains why his design is better.
This section contains the best slide in the talk:
This diagram shows why Parnas’s design is better. There are two types: Line and Ordered. These types are repeated and used as inputs and outputs. The other system apparently had more. One way to make this slide better is to show the original design next to it so we can compare. Another way is to highlight the small number of data types.
During this section he also gets the closest to “Residuality Theory” (terrible name 🤮). He asks us to “consider the effect of changes.” What modules need to change if we:
Read and print ASCII instead of EBCDIC?
Stop using packed characters and store one character per word?
Write the index to disk instead of RAM so we can index larger documents?
I love this process of identifying specific changes that require changes to at least one module. We identify coupling by seeing which modules change, regardless of how we draw the architecture diagram.
Unfortunately, he also uses vague terms like “too broad an interface.” This might be a nitpick, but I wish we’d stop using these impressionistic terms. How does one measure the breadth of an interface? And where is the line between too broad and broad enough? If the answer is “intuition,” then you’ve just kicked the problem of learning it back to experience, and your talk has not advanced the art.
He makes another statement:
Composability is inversely proportional to the # of interfaces
Composability is inversely proportional to the # of data types
These are interesting. He means that, all things being equal, if you can find common data types and common interfaces instead of inventing new ones for each module, you’ve got more composability. I think he’s right there. He has found a semantic layer below the problem he’s solving where common structure exists. Then he’s building using that structure. This is the kind of thing I get to a bit in my Composition Lens chapter and deeper in the Layers Lens chapter of Runnable Specifications. I try to answer, “How do you systematically explore the lower layer to discover these hidden structures?” However, he fails to relate composability to coupling sufficiently.
In the end of this section, though, I started to think that “information/decision hiding” was not the reason Parnas’s design works better. It’s more about resiliency to external decisions. I’m not sure, though.
He ends the talk by analyzing architecture diagrams, identifying coupling, then offering solutions to those instances of coupling. Again, this part is a little too abstract for me. The diagram is a lot to take in all at once, so the audience can’t really participate. Then he just circles two arrows and says, “here be coupling.” He gives a brief explanation of what kind of coupling, but not a method for seeing it. After identifying a few, he offers some solutions which also seem unexplained.
One reason I don’t like it is it seems to repeat the mistake he seemed to hint at at the beginning with the moons of Saturn. Is it just about looking at arrows? There were no arrows between Phoebe and Iapetus (scientists did not have a diagram to study), yet there was a coupling. Likewise, I wish he had used the other method he mentioned in the Parnas section, listing specific changes and see which modules were affected. Everything felt disconnected.
In the end, I was disappointed with the intuitionist and impressionist terms. But I also ended the talk thinking we should use the term coupling way less than we do now. We treat it like an abstract substance, a glue that gets caught in our architecture. Just like with technical debt, the term is so vague that we can talk across each other. I’d rather address the impact of specific, representative changes that would affect multiple modules than argue about whether things are too coupled. I don’t know if that’s the effect Michael Nygard had in mind when he gave the talk. But now it’s on my list of overused words.