Connascence of Position

We’re at the end of our journey into the static levels of connascence, with connascence of position as the last stop. Connascence of position refers to when multiple components must agree on the order of values.

The most obvious example of connascence of position are method arguments- these must appear in the same position in the caller as they do in the declaration, or things are going to break. There’s also the order of items in a data structure such as an array, and having multiple components relying on this being the same. We’re going to look at method arguments in detail, as there are a number of ways to mitigate connascence of position when talking about the order of arguments.

Take the following classes:

We have connascence of position between these classes around the order of the arguments passed in to the method- we send an alert by passing in the recipient, the sender, and the message. We have to make sure that we pass those arguments in that exact order, otherwise our message isn’t going to get where it’s supposed to go, which could be disastrous.

We can already see that the alert in our test is being sent incorrectly, but that’s ok. We’ll just run our tests, the issues will be found and a helpful error message printed to the console, and we can proceed to fix the problems.

That’s the output of our alertConfirmationContainsRecipient() test. You might have noticed that the error message is incorrect- the test for the recipient shouldn’t expect the value to be generic.person@soontobe.eaten, it should expect it to be john.hammond@ingen.com.

The issue is that also we have connascence of position within our test class- with the JUnit library we are using for our tests. This is because JUnit methods such as assertEquals() expect the parameters to be passed in a certain way- the expected value followed by the actual value. We passed them in wrong, so when something fails we end up with a confusing and incorrect error message.

We can solve connascence of position in a number of ways, which we’ll examine below.

Probably the most elegant way of solving this particular connascence of position issue is using named parameters- instead of relying on passing parameters in the same order in the call as the declaration, we can give each of the passed parameters a label that matches the declaration, and reduce our connascence of position down to connascence of name.

That would be great if we were writing code in Ruby or C#… or Python, or Ada, or a whole bunch of other languages. Our code is in Java, so we’re not quite so lucky. I suppose we could attempt to mimic the behaviour of named parameters by passing in a Map, with the keys as the names and the values as what we want to pass.

That’s not really as elegant as I was hoping. We’ve made our parameters a Map<String, Object> so we can pass different types in to our method even though we don’t need to currently. Unfortunately this gets rid of any type safety we get, which is a feature I quite like from Java. It’s less explicit in what arguments you can pass too, so we lose those compile time checks as well. There’s also a whole bunch of extra boilerplate we need in both the caller and the declared method, which isn’t brilliant either. What else can we do?

Well- it doesn’t solve the issue of extra boilerplate (not by a long shot), but there’s something we can do with type safety and explicit arguments. There’s a technique we can use called Tiny Types. Instead of passing in basic data types like String, Integer, Double, etc., we can wrap these up in objects representing domain concepts for each of the parameters- like Recipient, Sender, and Message.

Ok yeah that is a lot of boilerplate actually- but it has managed to reduce our connascence of position down to connascence of type. Try to pass the wrong type in and you’ll get an error rather than your message going to the wrong place or getting lost all together.

Tiny types can be really useful when you’re trying to express an actual domain concept that has behaviour- such as maybe recipient having to contain an @ sign, or message only being a certain number of characters. However, it’s probably overkill to use this technique as purely a method to remove connascence of position when your primitives won’t benefit in other ways by being promoted to full-blown domain objects.

Alternatively, we can use the Parameter Object and Builder patterns to reduce our connascence down to connascence of type. We’ll have a look at what the Parameter Object looks like first, but we won’t stop there:

Not really that helpful- we’ve added a layer of indirection but we’ve still got connascence of position, it’s just somewhere else now. This is where the Builder pattern comes in.

There we go- connascence of position has been removed and replaced with connascence of type. We can now send an alert without needing to know the order of the parameters to be passed. We have opened up other issues in the code though- for example, the way we’ve used the Builder pattern currently allows us to create an AlertRequest in an invalid state, which is far from desirable. If we’d used the pattern as intended, any required arguments would be part of the builder constructor… which would give us connascence of position again. Alternatively, we could throw an InvalidStateException when calling build() without first setting the required parameters.

You’ll also notice that we’ve replaced calling the JUnit library directly with calling a different library instead- AssertJ. This library uses fluent method chaining (A technique we’ve not looked at) to ensure connascence of position isn’t an issue.

Anyway, we’ll leave it to the audience to decide which technique to use and when it’s appropriate to use it. As always, there are tradeoffs to consider when changing any code- just do one that you’re comfortable with.

 

Author: Sean O'Toole

I like development and I like dinosaurs. Here we are.

Leave a Reply

Your email address will not be published. Required fields are marked *