Connascence: a retrospective

In the previous five articles I have test-driven a classic code kata, using only connascence to guide me during the factoring steps. Here I will summarise the steps I took, and review the final code.

Continue reading

Advertisements

Connascence of Algorithm revisited

Last time I fixed two instances of Connascence of Algorithm. Then I realised that I had introduced some more, so I fixed that too. After I had put that post to bed I also noticed that I had missed some alternative solutions. This article puts that right.

Continue reading

Connascence of Algorithm

This is the fourth post in a series in which I am test-driving a classic code kata, and using only the rules of connascence to tell me what to refactor.

If you have been following along, you’ll recall that my most recent refactor was to create a new domain object for MultiBuyDiscount, thereby alleviating a nasty case of Connascence of Position. The tests pass, so let’s review what connascence remains in this code:

Continue reading

Connascence of Position

This is part three of a series in which I am test-driving a classic code kata, and using only the rules of connascence to tell me what to refactor. Last time I continued working on the checkout kata, and I fixed some Connascence of Meaning by introducing a new class to represent the domain concept of Money. Today I want to take that same code a little further to explore what happens when I continue simply responding to the connascence I see.

Continue reading

Connascence of Meaning

This is part 2 of a short series of posts in which I explore TDD using only connascence as my guide. In the previous article I wrote a test, made it pass, and then refactored away the strongest coupling. That coupling took the form of some Connascence of Value between the test and the Checkout. Later, after the excitement of publishing the post had died away, I realised there was still some non-trivial connascence in the code. Today it’s time to fix that.

Continue reading

Connascence of Value

Connascence is a way of describing the coupling between different parts of a codebase. And because it classifies the relative strength of that coupling, connascence can be used as a tool to help prioritise what should be refactored first. This is the first in a short series of posts in which I test-drive a well-known kata, attempting to use only connascence as my guide during refactoring.

Continue reading

Eliminate many conditionals with this one weird trick

Recently I attempted to classify the conditionals in software according to where in the code they originate. The first category of these was: Checking a value returned to me from code I own. A large proportion of these can be eliminated quite simply.

Imagine we want to begin reading a file at the last saved read position, which may be null if we haven’t read anything yet:

var readOffset = fileReader.GetSavedReadPosition();
if (readOffset == null)
  readOffset = new ReadPosition(fileReader, 0);

This code violates almost every rule in the book:

  • There is duplication, because both the caller and the callee have special code for the “no saved position” branch.
  • There is Connascence of Meaning, because both need a common understanding of what the special null value means.
  • We are violating the Tell, don’t Ask principle because we are making a decision on the basis of a value returned from a call to a different object.

All in all, this code has problems — and yet I see code like this everywhere I look. So, what to do?

Let’s look at this code from the Connascence point of view. The problem is the null value representing the special “not saved” case: both the caller and the callee have to agree to use null to mean that (hence “Connascence of Meaning”). Now, connascence becomes stronger with increasing distance. Our example smells strongly because the two connascent code fragments are in different classes; thus we could weaken it if we can bring the endpoints closer together.

Currently, the fileReader decides what to return when it has no saved read position, and the client code has to cope with that decision. What if, instead, the client code decides what it would like to get back in that case; what if it could simply tell the method what to return if it can’t do the thing we’re asking:

var readOffset = fileReader.GetSavedReadPosition(0);

Now the connascence has disappeared, and the conditional has disappeared with it. It’s as simple as that.

Many frameworks and APIs offer this kind of default return value parameter. For example, the standard Ruby Hash class provides this feature via the fetch method.

But what if there’s no sensible default value that we can pass into the called method? For example, consider the following case:

var username = auth.GetPrincipal();
if (username == null)
  throw new UsernameNotFound();
auth.SetPassword(username, password);

We still have Connascence of Meaning due to the null return case; and we don’t want to push the error handling (or whatever) down into the authentication object, because different callers may want to handle the situation differently. But we can take a leaf from the default parameter book, and have the authentication object execute code for us:

var throwIfNotFound = () => throw new UsernameNotFound();
var username = auth.GetPrincipal(throwIfNotFound);
auth.SetPassword(username, password);

Again, the null value has disappeared, and so has the Connascence and the conditional. For the sake of symmetry we can often also dispense with the return value altogether and pass in both code branches to the callee:

auth.WithPrincipal(
  (username) => auth.SetPassword(username, password),
  () => throw new UsernameNotFound());

lambda1

Pretty much every modern language supports this kind of code now:

  • Functional languages allow us to pass in functions to do the job; likewise Javascript;
  • C and C++ let us pass function pointers;
  • C# lets us use lambdas via Linq; Ruby lets us pass in lambdas, and even C++ (thanks @mmeijeri) and Java 8 now allow lambdas.

Some even let us use named parameters to make the options a little clearer; for example, we might write the above example in Ruby thus:

auth.withPrincipal(
  if_known: lambda {|username| auth.set_pass(username, passwd)},
  if_unknown: lambda {raise UsernameNotFound.new})

It’s as simple as that. By adopting these approaches it is possible to simplify a lot of code, effectively removing the connascence and the duplicated conditionals from the caller and the callee.