

Saturday, June 09, 2012

Connascence and primitives

"Connascence between two software elements A and B means either: 

1. that you can postulate some change that would require B. to be changed (or at least carefully checked) in order to preserve overall correctness, or

2. that you can postulate some change that would require both A and B to be changed together in order to preserve overall correctness."

I think it’s fair to say that the reason we organize primitives and operations on them in larger structures, encapsulate them in modules or as separate entities, is to make sense of them - as humans. We need some way of having them meaningfully catalogued, so we can wrap our brains around the concepts of a domain. We require to continuously enable ourselves to understand what the program does by growing and constantly refactoring the design. We need to make it easy to identify the parts of it that require alteration when the business finds a program behavior necessary to change. And again, we do all of this only because we as humans need it, because this is how our brains work, how we think, learn and reason.

The computers could hardly care whether we introduce the domain concepts to the program design. If it weren’t for us, the programs could as well be still written in Assembler, or even in the machine code. As much as the previous sentence seem blatantly obvious, it should help me make my point - by having connascence as a tool we can more easily make the conscious decision of using either the primitives or the domain objects. I truly believe that the most important factor for choosing either of the solutions, is to help us to minimize the number of the interconnections required by a potential change (ie. make the “total connascence” lower, and better localized).

Where there is no (or minimal) ambiguity what a “price” means, and how to operate on it, it may be safe to just let it be “BigDecimal”. But then, if the application grows larger and larger, it may so happen that the other concepts will start appearing, such as “taxedPrice”, or “weight”, etc. Then it may become more difficult to perform a change related to “price”, because many entities are connascent, ie. “BigDecimal” and operations on “BigDecimal” mean different things in different contexts. Consequently a programmer may use incorrect methods on wrong data, change parts of code which are semantically unrelated, or do not change these parts that are related.

All in all based on the definition of connascence in order make a “perfect modification” in a program I want to:
  • carefully check as little of it as possible,
  • be as certain as possible that I checked enough,
  • change as little of my program as possible,
  • be as certain as possible that I changed enough.

The list above may not be exhaustive, and I confess to actually creating it a bit ad hoc, but it can be extended as needed based on a definition of connascence. IMHO all that matters is that we keep connascence localized (ie. easy for a human reader to spot), and minimize the number of connascent software elements. That of course as a rather generic statement surely may be applied not only to the problem of primitive obsession, but to a large number of design decisions.