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.

Not on the backlog: a response

Ron Jeffries recently wrote a great article in which he recommends how teams should dig their way out of thickets of technical debt:

We take the next feature that we are asked to build, and instead of detouring around all the weeds and bushes, we take the time to clear a path through some of them. Maybe we detour around others. We improve the code where we work, and ignore the code where we don’t have to work.

I wholeheartedly agree with this approach, and with the advice and analysis in Ron’s article. Ron says “Simples!” but I don’t agree. For most teams there are a few significant hurdles to overcome:

  • The team has to recognise the situation it is in, and that a new approach is required henceforward.
  • The team needs to discover the courage to take the time to invest in this change of approach.
  • The team needs to develop an understanding of what better code looks like.
  • The team needs to learn how to create better code out of bad code.

None of these things is trivial. All of them require the whole team to go on a journey, probably to learn new skills, and above all to have the courage to make the change.

Don’t put refactoring stories on the backlog. Instead, invest in learning what habitable code looks like, how to write habitable code, and how to improve the habitability of existing code. That’s what will make you go fast; that’s what will get you out of the thickets.

interviewed at scottish ruby conf

Way back in March of this year, while I was attending the Scottish Ruby Conference, Werner Schuster interviewed me for InfoQ. The video has been online since August, and this is me finally getting around to telling you about it; watch it here. I talk about Reek, Refactoring in Ruby, and agile development in general.

This was the first time I’ve done a video interview, so I’m keen to hear your comments on how it went!

extract class or substitute algorithm?

I have a dilemma. In fact, I frequently have this dilemma, so I thought I’d ask your opinion on which way you would address it.

I just completed a CRC session for the next feature I want to add to my codebase. One of the classes identified for the new scenarios is a particular kind of counting collector, and I realised that the same behaviour already occurs elsewhere in the codebase. So one of the first steps in coding up this new scenario will be to extract a new class from an existing class. The existing class has reasonable micro-tests, and therein lies the dilemma:

  • I could simply use the Extract Class refactoring recipe, and I’d be done quite quickly; the new collector class would be tested indirectly, via the micro-tests for the original class (which would now be the extracted class’s only client).
  • Or I could develop the collecting class test-first, from scratch, so that it had its own micro-tests, and then use Substitute Algorithm, reimplementing the old class to use the new.

The advantage of the second approach is that it gives me precise micro-tests of the new class. But while developing that class, I could drift away from the required usage, or I could make it harder to switch the original class over to using the new one. (I tend to think of Substitute Algorithm as being riskier than Extract Class.)

So which is better — use Extract Class and know that I have a working client-supplier relationship; or TDD from scratch and risk going off track? In practice, I tend to choose Extract Class if I’m feeling lazy or distracted, whereas I go with TDD followed by Substitute Algorithm when I’m feeling organized; in the latter case I usually get stressed by the “substitute” step…

(It seems to me that if we choose the latter approach in general, many refactorings should cease to be used. That can’t be right, can it?)

fixing Feature Envy by backtracking

After a conversation this week with Hugh Sasse about Feature Envy and Utility Functions, I realised I’ve evolved my approach to dealing with them:

When Reek tells me about one of these smells, my first step is to inline the smelly method back into all of its callers. Then I look for ways to fix the resulting duplication without extracting the same method again. Sometimes the re-formed methods break apart in new ways (compared to when they were first written), other times I see opportunities to peel off new classes. (One thing I never do these days is to introduce inheritance relationships in order to remove duplication; I look hard for ways to solve it through delegation, often to a new class, or I leave the duplication in place for the time being.)

This approach seems to be working well for me at this early stage. Have you tried this or something similar? How did it turn out?

communicating intent is all about names

Ths ten-minute video chat between Corey Haines and J.B.Rainsberger introduced a nice simplification of eXtremeNormalForm.

In the discussion, JB hardens up the wishy-washy Communicates Intent value by noting that it’s just about “bad names”, and here’s why. In an OO language, “communicating intent” boils down to breaking the system into small pieces and giving them good names, names that resonate with the design and the domain. Small pieces are no good on their own, and good names for bad ideas will soon be weeded out. JB therefore claims that good design (he says good architecture) boils down to

  1. eliminate duplication
  2. eliminate bad names

(He takes passing all tests – ie. correctness – as a given, and he says that eliminating duplication and bad names also renders the software “small”. I disagree on that last point.) So, his assertion is equivalent to saying that every code smell is a symptom of either Duplication or Bad Names, which I find easier to explain than asking people to ensure that the code “communicates intent”.