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.)