The Rule Of Three Kata

Image

A widely-known – and even more widely misunderstood – principle in software design is Don’t Repeat Yourself (“D.R.Y.”).

Duplication in code can be a problem, because it can multiply the cost of making changes to the repeated parts. But it’s by no means the worst thing we can do in code. I’ll take code that’s easy to understand over code that has zero duplication any day. (And I’ll take code that works over code that’s easy to understand, too.)

So, although duplication is listed in many sources as a code smell, it’s importance is perhaps sometimes overstated in the maintainability stakes. But D.R.Y. serves a purpose in the actual design process itself.

Think about it: what’s the opposite of duplication? Reuse. When we see repeated examples of code, they can act as a signpost towards some kind of modular, reusable replacement. Repeated blocks of code could become a parameterised function of method. Copied and pasted groups of functions or methods could become a shared module or class.

By paying attention to duplication and refactoring to consolidate it, modular abstractions emerge in our code; shared functions/methods, shared modules/classes, polymorphism, and so on.

It’s argued by some, like Kent Beck, that pulling on that string of duplicated code to allow a modular design to emerge is a more evidence-based, “scientific” approach to design. We introduce abstractions, not because we think we might need them (another code smell called “Speculative Generality”), but because we see multiple examples where we do need them in the working code as it presently is, and not as we imagine it might be or should be.

The skill in following duplication to a modular design is in seeing the patterns. And, here, it serves us to see more examples so we’re more likely to choose the right generalisation, encapsulated in the right abstraction.

But leave it too long – let the repetition go on and on – and we face another problem, which is that any refactoring we do to consolidate it will take longer and longer. In the zero-sum game of software development, where we have limited time and resources, things that take longer (and/or cost more) are less likely to happen.

So we want to wait until we see enough examples, but not wait too long that we might not ever get around to refactoring it. This balance is captured in The Rule Of Three. On average (i.e., not always), we wait to see three examples of repetition before we refactor. Could be more, could be fewer, but on average, three.

The other thing about The Rule of Three is that, when we see something repeated once, the odds of it being repeated again (and again) are quite small. When we see code (or a concept – a much longer blog post!) repeated three or more times, chances are higher that it will be repeated again. In the coding kata that this exercises I’m going to introduce is based on, you should see things really speeding up after you’ve refactored out the duplication in the solution code.

And, of course, code isn’t the only thing we repeat in software development. The process itself can be full of examples of duplicated effort. For example, I might manually deploy my web application every day. The stuff I’m doing at the command line – stopping servers, deleting old folders, copying new files across, running database updates, restarting servers, etc – I could do with a batch script so it becomes an automated single-click process. If the time and effort involved in automating deployments is significantly outweighed by the time saved doing deployments every day, that’s a profitable venture.

In the same way that duplicated code can signpost a better modular design, duplicated effort can point us more scientifically to a better process. And in this sense, it’s useful to be aware of where that duplicated effort’s occurring. Time and Motion studies kind of thing.

Anyway, here’s a coding kata that exercises your Rule Of Three senses. It’s based on a well-known kata that’s good for practicing spotting and removing duplication in solution code, but we’re going to expand on that.

The problem you’re going to write code to solve is the Roman Numerals kata. Ordinarily, developers tackle this exercise by writing their tests first (TDD). But in our version, we’re going to go test-after. Like in the bad old days. But still working in micro-feedback loops. So, write a little bit of code – change or add one thing – then test it.

For example, write a function that converts 1 into “I”, then test that. Then change the function to turn 2 into “II” and then perform both tests. Then change the function to turn 3 into “III”, and then test all three cases. And so on. So, baby code-test steps. And, of course, if you see a pattern of repetition in your solution code, consider refactoring once you’ve seen three complete examples of that pattern. (Pro tip: don’t jump in too soon, the pattern’s larger than you think!)

The Rule Of Three kata has… well… three rules:

  • When you’ve performed the same test – e.g., 1 = “I” – at least three times, automate that test in a main() function or method so you can run it with a single command in a terminal, and easily inspect the result in your console window (test name, pass/fail, expected result, actual result). DO NOT USE A TESTING FRAMEWORK. The goal here is to discover a framework by consolidating duplication.
  • When you’ve written at least three automated tests, refactor repeated test code into a shared set of abstractions (e.g., shared functions) to remove that duplication, and then carry on
  • If you do this exercise alongside other developers or pairs (highly recommended), when three of you have your own set of shared testing abstractions, compare and consolidate them into a single shared testing library that you all use. Then carry on. You may find, as the number of automated tests grows further, that more evolution of the testing framework will help you to Don’t Repeat Yourself. So we may be looking at some kind of trunk-based concurrent development here 🙂

All The Code’s A Stage…

Image

Many years ago, I joined a youth theatre club. Now, those of us who thought we might be good – or, at least, not bad – at acting often think that because we are good at reading out loud. Maybe when it was your turn to read from the text in your school English classes, you did a pretty decent job with pronunciation, diction, and perhaps even reading it with appropriate emphasis and “feeling”. So you might have thought “Hey, I should do drama!”

But, it turns out, 80% of acting isn’t saying your lines, it’s listening to what the other actors in the scene are saying – and how they’re saying it – and *responding*. And in that sense, no matter how much you prepare for a role, your plans will almost certainly have to change as soon as someone else starts talking. Actors – proper ones – have it drummed into them to be present in the moment, to actively listen, and to respond truthfully to what the other actors are saying and doing. That tends to make the difference between someone reading out lines, and someone being authentic in the scene.

Software development’s a lot like that. Many folks might think that it’s all about writing code, but it’s actually mostly about paying attention to what everyone else “in the scene” is doing and responding effectively. This is why I encourage devs to be more situationally aware of what other people in the team are doing.

People may mistakenly believe they’ll be good at acting because they’re good at talking. And people may be equally mistaken in believing they’ll be good at software development because they’re good at programming.

Rookie Mistake: Minimising “Interruptions”

Image

We all know that feeling when we’re deep in concentration, lost in our mind palaces, and some absolute sod dares to talk to us and completely breaks our flow. The natural response is to try to minimise those kinds of interruptions. But that would be solving the WRONG PROBLEM.

The idea of deep work, or “flow”, is pervasive in software development. The received wisdom is that programming requires a Zen-like state of concentration where the problem is completely contained in our heads and there is only the problem. We are not thinking about anything else. And this state takes time to achieve, a bit like how a computer program takes time to load into main memory.

Image

Anything that stops the program – breaks our state of concentration – forces us to load it all over again, which loses us time – typical estimates put it at 20-30 minutes of time “wasted” with each interruption.

It’s understandable therefore that developers – and the people who pay us – seek to minimise those interruptions to maximise deep work or “flow”. But this is to fundamentally misunderstand what software development is. To the layperson or the inexperienced, software development is “coding”, and we maximise the value created by software developers by maximising “coding”.

But when we actually observe teams, we may notice that the more “coding” goes on, the more the effect is typically the opposite. One line of code can literally be worth millions of times more than another. We maximise the value of what we create not by maximising code, but by maximising the value of code.

And how do we maximise the value of the code we write? By hiding in our cubicles, sticking on our headphones and putting a big “Do Not Disturb” sign up? Or do we maximise the value of our code by TALKING TO PEOPLE? Talking to customers. Talking to users. Talking to the ops team. Talking to each other.

When we set out to minimise “interruptions”, we risk minimising the COMMUNICATION that helps steer us down the right path. We’re minimising value.

Then there’s the other purpose of “interruptions”, which is to keep us all in sync – to keep us on the same page. In software development, having everyone on the same page is especially important, because when programmers working on the same code base aren’t in sync, that can break a bunch of stuff.

As common as our hatred for interruptions is, that can be greatly outweighed by our loathing of that person on the team who merges 1,001 changes that weren’t discussed with anybody else. Far from making the team more productive, that can often lead to major rework down the road, costing us more time than the so-called “interruptions” that could have kept us in sync.

When it comes to maximising value, communication is key. When it comes to avoiding train wrecks, communication is key.

The challenge for many teams is how to have their cake and eat it. How do we achieve a state of flow, and be continuously communication? It’s a paradox, surely?

Well, no. Think back to my analogy of loading a computer program into main memory. If the program takes up 10 GB of memory, it could take quite some time to load, so stopping the program every few minutes would indeed be a major headache. But if that program only took up 10 MB of memory, or 10 KB, then reloading it on today’s machines wouldn’t take much time at all. We’d barely notice.

Image

When it comes to this state of flow, a big factor is COGNITIVE LOAD – how much do we need to fit in our heads at one time, how many plates do we need to keep spinning?

Developers who work in very short feedback cycles – code a bit, test it, code a bit more, test it – often find that interruptions aren’t a problem. They make one or two small changes at a time, which require them to hold a lot less in their heads.

This is especially true when they combine those baby steps with some kind of high-level road map – a list of tests, or a high-level design, or a UI storyboard, for example. This enables them to keep their place in a bigger picture without having to hold a detailed map in their heads. They’re not doing the high wire act that many developers are doing when they make a whole bunch of changes before seeing the code work again.

By dramatically reducing cognitive load as they work, they’re able to communicate much more frequently, and stay much more closely in sync with the rest of the team.

This is one of the biggest payoffs for technical disciplines that maximise opportunities for communication, by working in very short feedback cycles that bring us back to tested, working software many times an hour.

Easier said than done, of course. This isn’t a way of working you can just switch on. It’s a whole skillset that needs to be learned, a set of habits that need to be instilled, and a dev culture that needs to be cultivated. That costs significant time and money, which is why most organisations choose to stick with the proverbial “Do Not Disturb” sign.

Rookie Mistakes

In case you’ve not seen it, I’ve been busy making short videos for the Codemanship YouTube channel for a series called “Rookie Mistakes”. These are the kinds of mistakes that I made – and I’ve seen many others make – at the beginning of their dev careers. And let’s be honest, some continue to make after decades in software development. (Sigh!)

Maybe you’re making some of these mistakes, or maybe you’re watching people make them. These little vignettes are for you.