Today is Independence
Day in the USA, which got me thinking about loosely-coupled “independent” software components. I was reminded
of a video I bookmarked quite a while ago
of Jim Weirich’s “Grand Unified Theory
of Software Design” talk at MountainWest RubyConf 2009. I finally watched that video this morning. I highly recommend it. In the video, Jim talks about software connascence. The dictionary definition
of connascence (con-NAY-sense) is: 1. The common birth
of two or more at the same time 2. That which is born or produced with another. 3. The act
of growing together. The brief Wikipedia page about Connascent Software Components says that: Two software 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. Connascence is a way to characterize and reason about certain types
of complexity in software systems. The term was introduced to the software world in Meilir Page-Jones’ 1996 book “What Every Programmer Should Know About Object-Oriented Design”. The middle third
of that book is the author’s proposed graphical notation for describing OO designs. UML became the standard about a year later, so a revised version
of the book was published in 1999 as “Fundamentals
of Object-Oriented Design in UML”. Weirich says that the third part
of the book, in which Page-Jones introduces the concept
of connascence “is worth the price
of the entire book”. (The price
of the entire book, by the way, is not much – I just bought a used copy on Amazon for $1.36, so that was a pretty low-risk investment. I’m looking forward to getting the book and learning about connascence from the original source.) Meanwhile, here’s my summary
of Weirich’s summary
of Page-Jones writings about connascence: The stronger the form
of connascence, the more difficult and costly it is to change the elements in the relationship. Some
of the connascence types, ordered from weak to strong are: Connascence
of Name Connascence
of name is when multiple components must agree on the name
of an entity. If you change the name
of a method or property, then you need to change all references to that method or property. Duh. Connascence
of name is unavoidable, assuming your objects are actually used. My main takeaway about connascence
of name is that it emphasizes the importance
of giving things good names so you don’t need to go changing them later. Connascence
of Type Connascence
of type is when multiple components must agree on the type
of an entity. I assume this is more
of a problem for languages without compilers (especially when used in apps without tests). I know it’s an issue with evil JavaScript type coercion. Connascence
of Meaning Connascence
of meaning is when multiple components must agree on the meaning
of particular values, e.g that “1” means normal customer and “2” means preferred customer. The solution to this is to use constants or enums instead
of “magic” strings or numbers, which reduces the coupling by changing the connascence form from “meaning” to “name”. Connascence
of Position Connascence
of positions is when multiple components must agree on the order
of values. This refers to methods with multiple parameters, e.g.: eMailer.Send("
[email protected]", "
[email protected]", "Your order is complete", "Order completion notification");
The more parameters there are, the stronger the connascence
of position is between the component and its callers. In the example above, it’s not immediately clear when reading the code which email addresses are sender and receiver, and which
of the final two strings are subject vs. body. Connascence
of position could be improved to connascence
of type by replacing the parameter list with a struct or class. This “introduce parameter object” refactoring might be overkill for a method with 2 parameters, but would definitely be an improvement for a method with 10 parameters.
This points out two “rules”
of connascence:
The Rule
of Degree: The acceptability
of connascence is related to the degree
of its occurrence.
The Rule
of Locality: Stronger forms
of connascence are more acceptable if the elements involved are closely related. For example, positional arguments in private methods are less problematic than in public methods.
Connascence
of Algorithm
Connascence
of algorithm is when multiple components must agree on a particular algorithm. Be DRY – Don’t Repeat Yourself. If you have “cloned” code in multiple locations, refactor it into a common function.
Those are the “static” forms
of connascence. There are also “dynamic” forms, including…
Connascence
of Execution
Connascence
of execution is when the order
of execution
of multiple components is important. Consumers
of your class shouldn’t have to know that they have to call an .Initialize method before it’s safe to call a .DoSomething method.
Connascence
of Timing
Connascence
of timing is when the timing
of the execution
of multiple components is important. I’ll have to read up on this one when I get the book, but assume it’s largely about threading.
Connascence
of Identity
Connascence
of identity is when multiple components must reference the entity. The example Weirich gives is when you have two instances
of the “Bob” Employee class and you call the .RaiseSalary method on one and then the .Pay method on the other does the payment use the updated salary?
Again, this is my summary
of a summary, so please be forgiving if I misunderstood anything. Once I get/read the book, I’ll make corrections if necessary and share any other useful information I might learn.
See Also:
Gregory Brown: Ruby Best Practices Issue #24: Connascence as a Software Design Metric (That link is failing at the time I write this, so I had to go to the Google cache
of the page.)