February 19, 2019

...Learn TDD with Codemanship

When Should New Programmers Be Introduced To Code Craft?

When I look back at my journey to becoming a software developer, and talk to many others who have made similar journeys, it strikes me that there was a point fairly early on when I could really have benefitted from a bit of code craft.

Programs of a few dozen lines like I used to cobble together on my Mattel Aquarius and Commodore 64 probably don't need automated tests or refactoring or a CI server.

But as I grew more confident with code, and the amount of main memory and disk space grew from kilobytes to megabytes, my hobby projects grew too from dozens of lines to hundreds to thousands.

During my coding adolescence I really could have used some automated unit tests. My code really would have benefitted from being simpler and clearer. It really would have helped to break things down into smaller, more modular chunks. It really would have made a difference if my code hadn't repeated itself quite so much. (When I discovered Copy & Paste in Turbo Pascal, I was like a kid who'd found his Dad's gun.) And it would have really, really helped if I'd used version control.

Without those foundational things, my programs experienced growing pains. As with all adolescents, there ought to be a time to take programmers aside and explain the Facts of Code:

1. You'll be spending most of your time trying to understand code, and that includes code you wrote.

2. Code gets real complicated real fast. All the "moving parts" are interconnected. You'd be surprised how many ways just a few lines of code can be broken.

3. Code will need to change many times, mostly because it takes many tries to build something good. It's all one big experiment.

4. Changing code often breaks code, including code you didn't even touch. Like I said, it's all interconnected.

5. The longer our code is broken, the longer it takes to fix. So much so that, after a while, all we seem to be doing is fixing code. That's no fun.

6. There'll be many times you're going to want to go back: to the last time your code worked, to the last time you were happy with the design, to see what was in the code in that version that the user reported a bug in, etc

7. Just because it worked on your computer doesn't mean it'll work on someone else's

8. Just because you think it's good, it doesn't mean end users will

Whether you're coding for fun or for money - above a basic level of complexity - these things are almost always true of the code we write.

Writing computer programs can be fun and rewarding. Burning the midnight oil banging your head against the wall and crying "Why isn't it working?!" or having to write reams of code all over again because you totally borked it and your last back-up was 24 hours ago... not so much.

I would have had more fun and got more done if I'd kept my code clean, if I'd beeen able to re-test it speedily, and if I'd beeen able to go back to any point in its evolution easily. And when I started my professional career, I have no doubt at all that I would have written better software, and got more done. I'm 100% sure of that.

So, with the twin aims of enabling hobbyists to have more fun and waste less time on not-fun activities like debugging and fixing code that didn't need to be broken in the first place, and to produce a new generation of more confident and more capable software developers for those who "go career" (including the millions of people who write code as part of their job but don't consider themselves "software developers" - e.g., scientists and engineers), I still firmly believe that code craft should be introduced once programmers have progressed beyond small and simple programs of < 100 lines of code.

And I would introduce code craft in this order:

1. Version Control. This is seatbelts for programmers. If you're planning to take the car out of the drive, it's time to put them on. The ability to go back to any working version of your code is the ultimate Undoability.

2. Unit Tests. Knowing if your code works is really, really useful. The sooner you know you broke the code, the sooner you can fix it, and the easier it is to keep it working. It turns out working code is a good thing. You'd be surprised just how profound an impact fast-running automated tests can have on everything else. Programmers can experiment with the confidence that if their experiment broke the code, they'd know straight away. Fast-running automated tests make us brave. Programming without fear is way more fun. I know this from 13 years programming without unit tests, and 24 years with them. Night and day.

3. Writing Readable Code. And, no, teachers: I don't mean writing more comments in your code. I mean writing code that clearly communicates what it's doing. If you're looking at a block of code and wondering "what does this do?", maybe it should be in a function with a name that tells that story.

4. Refactoring Code. The ability to make code easier to understand and easier to change without breaking it is super, super useful. Refactoring is arguably one of the most undervalued skills in programming. A woefully small percentage of professional software developers can do it, and the alarming cost of changing commercial software is the result. I've seen multi-billion dollar businesses brought to their knees by their inability to change their code. Buy me a beer and I might even name some of them.

4. Part II. Basic Principles for Writing Code That's Easy To Change. Hand-in-hand with refactoring is knowing what to refactor, and why. What makes code harder to change?

a. Code that's hard to understand is more likely to get broken by programmers who don't understand it
b. Duplicated code may need the same change made in multiple places, multiplying the cost (and risk) of making that change
c. Complex code is more likely to break because there are more ways for it to be broken
d. Changing one line of code might break other code that's connected to it (and, in turn, code that's connected to that code). We have to manage the connections in our code to localise the impact of making changes. This means our code needs to be effectively modular, built out of parts that:
i. Do one job
ii. Know as little about each other as possible
iii. Can be easily changed or swapped without effecting the rest of the code

5. Making It Easy To Get Your Working Code Out Into The World. They say "there's many a slip 'twixt cup and lip", and so many times as a hobbyist programmer (and an early professional developer) I fell at the final hurdle of getting the code I slaved over for hours on my computer to work on other people's computers.

This was because it was a manual process that involved me compiling my code, gathering together all the files my program needed, zipping it all up onto floppy disks (or copying it all across the network), unpacking all that on the target machine, changing some settings on that machine, starting some background programs and services that my program needed, and so on.

As artisanal and cool as "hand-deployed software" might sound, aside from the time this took, installs would often go wrong, and I often found myself saying those immortal words "Well, it worked on my machine!"

The whole process of going from my machine to potentially thousands of target machines needs to be speedy and reliable and - very importantly - reversible. Like all information processes that need to be speedy, reliable and reversible, that means it needs to be completely automated.

Programmers would benefit greatly from automating the building, testing (to make sure it really does work on other machines) and deployment of their programs to whatever target platforms they need them to work on. This will enable them to release their code often, which means they can get useful updates and fixes to their end users sooner and they can learn from the feedback faster. This is the secret sauce of software development. It's a learning process. Most of the value in code is added as a result of user feedback. More feedback, more often, means our programs improve faster, and we mature as programmers sooner.

It also helps us to engage with the people who use our programs more frequently and build those communities more effectively. This is the final way in which code craft adds to the fun...

Another hobby I had as a kid that followed me into adult life is playing the guitar. Playing the guitar in your bedroom is fun. Playing guitar in a band in front of real audiences is really fun. And a little scary, of course. But until you do it in front of other people, it's very hard to know if you're doing something good. The Beatles didn't get great in their bedrooms. They got great by playing hundreds and hundreds of gigs. They'd probably played thousands before their first single was released.

Now, please remember: I'm not suggesting that all people who try programming must learn code craft. Most people will give it a try, maybe get something out of it, but then leave it there. Just as most people who try the guitar learn a few chords and are perfectly happy leaving it at that.

But a proportion who try coding will really enjoy it, and they'll naturally get more ambitious with their projects. These are the people who need a bit of code craft to make that journey easier and utlinately more rewarding. Fun requires the fundamentals.

Teachers and code club organisers and should be looking for the signs, identifying who these people are, and encouraging them to learn about code craft. As a profession, we should be ready to help in any way we can.

Posted 3 years, 2 months ago on February 19, 2019