primitive obsession in ruby

I spent an hour or so this afternoon refactoring some code deep inside reek. I wanted to simplify the code that checks for the Uncommunicative Name smell, but it just wouldn’t fall out as clean as I would like. And at some points it seemed that I was going around in circles — a name is represented as a Symbol here, needs to be a String there, but when I add a call to to_s something else seems to need it back as a Symbol again. It’s the old feeling of squeezing water in a balloon: squeeze in any one place and the problem seems to pop up somewhere else. I put the problem down to tiredness and took a break — actually I took a drive in falling snow, which is not necessarily a cure for tiredness!

But the change of scene cleared my thoughts, and I realised what was going on: The troublesome names were a case of the Primitive Obsession smell. Several classes throughout reek “know” when a name travels around as a Symbol and when it travels around as a String. I needed a new class, Name, to hide the details of the actual representation. I added it (following the recipe in the ruby refactoring workbook, you’ll be glad to hear), and all was well. The new class even acquired some behaviour along the way, so all is well.

So, nothing new there; why am I even writing this at all? Because I asked myself why it had happened — why had such a huge case of Primitive Obsession escaped my attention for so many weeks, and why didn’t I pick it up this afternoon when it hit me repeatedly between the eyes (can a smell do that)? Is this another manifestation of my anosmia? Am I smell-blind to Primitive Obsession? I don’t think so.

Every day in my coaching practice I see code riddled with this same smell. I point it out, we have a quick ad-hoc training session and a couple of lunchtime dojos. I can spot this problem easily. The difference is that the teams I work with all use C# or Java or C++, where the types are stated clearly in the method signatures. But in Ruby that’s not the case: when you read a method in Ruby code, you have to infer the types of the actual arguments by looking at how they are used. Parameter names don’t always help here either (in the reek source code above, sometimes the names were called ‘sym’, other times ‘name’).

So I contend that dynamic typing makes Primitive Obsession harder to diagnose. Do you find that too? Does this smell linger longer in Ruby code than in Java code, for example?

And if my contention is true, what new diagnostic tools do we need? If we don’t have statically typed method signatures slapping us with the wet fish of int and string, are there any simple alternative cues we can look for?

2 thoughts on “primitive obsession in ruby

  1. I totally agree.

    I think there’s something about the looseness of working in a dynamic language like Ruby that maybe makes us less willing to create special types for things. After all – if we need a new method on a primitive type we can just duck-punch it in there – right? No need to create a new class for that… or so the thinking goes.

    I’ve noticed that this looseness can make us sloppy when working in Ruby, which I think is counter-intuitive: this flexibility actually means we need to be much more careful and rigorous, because we can’t just lean on a compiler.

    Thinking out loud… Maybe the solution might be to look for lots of calls to the same method a given object? In your case, you would have found lots of calls to #to_s which would suggest that clients would actually prefer to get a more rich object that was a bit more self aware and could give them what they needed by default?

  2. @Matt Wynne:
    Agreed. I’ve found myself using OpenStruct to hack together a mock object for a test, only to find later that the behaviour of the mocked thing changes and all the mocked tests break. No static typing = no safety net.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s