Yesterday, Tozier and I intentionally cornered ourselves. We put yesterday’s article in the iPad input folder. The only way that article can get put on the site is for our “Minimum Viable Product” to work. That MVP, we think, is our
JekyllRunner being run as a
cron job, sweeping everything from the iPad input folder and putting it up on the site.
We had imagined that we were ready to do one more test and let ‘er rip. As you’ll read about, we were wrong. The details will appear when that article comes up. Today I want to talk about something that came up during our little retrospective.
Clean code matters.
Boiling down what we discovered about our little program was that there were code smells that show there’s room for improvement. A common name prefix,
ftp, tells us there’s an abstraction waiting to be discovered, and probably a new class. An important missing test kept us from finding an important problem until way down the road. The absence of another abstraction has made the code more procedural than we’d like. Our tiny program’s code isn’t helping us enough, because it’s not clean enough.
Our little program seems pretty clear when we read it. Methods are mostly decomposed well. Names seem to make pretty good sense. The flow is fairly obvious. We wouldn’t publish it other than in The Book of Erors, but it’s not bad. It’s a lot like the code you see around, and better than some.
And it hurt us. It slowed us down. What’s important here is that it slowed us down in a very common way. Today’s thesis is: our few hundred lines of code and test are like every other few hundred lines of code and test.
I’ve been programming for over half a century. I’ve not always been programming for pay, but I’ve always been programming something, for pay, for explication, for learning, for fun. I sometimes feel like I’m beginning to get the hang of it, and I think there are some things that never change. Let’s think about some of those unchanging things.
It’s turtles all the way down.
It seems to me that a programming task almost always goes like this:
- Find the place where the new thing needs to go, the Code of Interest.
- Figure out what the Code of Interest is doing now.
- Figure out what needs to be changed.
- Change it.
- Convince ourselves that it works.
- Convince ourselves that we haven’t broken anything else.
Whenever any of these steps takes more than a little time, the more certain we can be that we have a design issue, possibly missing tests. (Yes, the tests are part of our design, and if we don’t have the right ones, we have a design problem.)
Sure, there are variations … let’s set them aside for now and talk about this situation, which seems quite common to me. After we find the Code of Interest that we need to work on, we have a some amount of code to understand and to modify or add to.
To the extent that the Code of Interest is large, or spread all over, there’s a design problem. The Code of Interest has low cohesion and high coupling. It’s not clean.
To the extent that we can’t understand the Code of Interest, it doesn’t express the ideas behind it well enough. It’s missing good names and possibly missing some important abstractions. It’s not clean.
To the extent that we’re not sure what it does, the Code of Interest needs more examples. It’s not clean.
Those examples should be runnable. We call them “tests”. If they aren’t there or aren’t runnable, we can’t have confidence in our understanding of the Code of Interest, and we can’t have confidence in our changes not breaking anything. Our Code of Interest is not clean.
These problems slow us down. They make it harder to find things, harder to understand them, harder to be sure how they work, harder to be sure our changes work and haven’t broken anything.
These problems slow us down Every Single Time, Every Single Day.
In our little iPad experiment, Tozier and I can identify several hours where we should have been able to go faster but the code held us back. Now certainly you’re smarter and more skilled than I am, and you wouldn’t have had those problems, because, well, you’re smarter and more skilled than I am.
That doesn’t matter. Those problems slow you down, too. You’d be even faster, look ever so much better than I look, if you didn’t have those problems. Oh, yes, you rock at ripping through that kind of problem. You may even revel in it. But the fact remains, if you didn’t have to solve those problems, you’d go even faster. You’d get done even sooner. You’d look even better than you do now. You would be AMAZING!
What’s your point, Ron?
Every day, we face some task that we’ll address with a few lines of code, however many we can produce in a day, blended in with a few lines of Code of Interest that we need to understand in order to do it right, blended in with whatever vast quantity of code the Code of Interest lives in.
And every day, to the extent that Code of Interest isn’t clean, it Slows Us Down. And every future day, when we visit that code again, it will slow us down again.
Tomorrow, if it isn’t clean, the code we write today will Slow Us Down.
Clean code is the only way to go fast, and this means code with good names, with every meaningful abstraction, surrounded with tests that tell us what it does and assure us that it still does it. We have to do this or it will Slow Us Down!
Is this confirmation bias?
From the first day Bill Rogers gave me a FORTRAN II manual and told me to write a function returning great circle distance, I’ve been trying to understand programming, and how to do it well. I’ve tried almost every new development process, tens of languages, hundreds of design alternatives. I’ve spent my life trying to learn to make programs, and programming, better.
Mind you, as a would-be Agilist, I believe that people are the main thing in good software development. I believe that customer engagement is critical. I believe that we need to be able to respond rapidly to the need for change. In order to do those things, I believe that we need working software that is able to be inspected, and able to be changed.
So maybe it’s no surprise that I come back again and again to this simple, perhaps simplistic, view that squeaky clean code is critical to success. I’m invested at a deep personal level in good code, with good design, with good tests. So maybe it’s no surprise that when I find that our little iPad-focused program’s flaws are slowing us down, I generalize to all the code in the world. Maybe it’s confirmation bias.
But I suggest that you don’t dismiss these notions so easily. Observe what happens as you work. Observe how the names aren’t helping. Observe how lack of abstractions produces duplicated code and excess confusion. Observe how lack of tests leaves you wondering how the program works, and wondering whether your changes work and have broken nothing.
Feel the pain, think about what’s causing it. Then ask yourself if you wish today’s Code of Interest was a bit nicer. When you decide that you do wish it was nicer, take that as clear evidence that you’d like all your code to be nicer. Then make it nicer.
Is this a moral imperative?
Uncle Bob Martin writes about clean code. His coding examples and lessons are better than mine, his books on the subject are excellent. By all means check them out.
Bob often expresses his ideas in terms that seem to me to be moralistic terms. He wants programmers to take an “Oath”. He seems to be saying that writing bad code is immoral.
I think you get to make your own decisions about morality, although if you’re not doing the best you can, I personally don’t want to hang out with you and don’t want to have to rely on your code. That’s my view: I’m not telling you how you have to live your life.
I am, however, telling you this: I am as certain as I can be that making your code cleaner will make you go faster. Oh, sure, it’s theoretically possible that you’ll polish something too much. That happens so seldom that I’d bet against it any time. I think that if we sat down right now with any of my code, or any of yours, we’d not find anything too clean, and we’d find plenty that needs improvement.
This is not a moral imperative, it’s a very practical one. You’ll do better, get more done, make fewer mistakes, and have more fun, if you keep your code incredibly clean, every day.