October 7, 2014

...Learn TDD with Codemanship

Programming Well Part I - A Basic Guide For Students & Teachers

This is the first part of a series of blog posts aimed at new programmers who have gotten the hang of the basics and want to progress on to more challenging projects, as well as teachers and mentors who may be helping people to progress as programmers. I'll add more installements as time allows.


If you're a teacher working with the new computing curriculum, then you probably have a lot on your plate.

But there are some things I would like you to think about on the subject of programming that, as far as I'm aware, aren't covered in the curriculum. I believe they should be, because they're actually very important things every programmer should know.

Once a programmer has learned enough to write simple programs that successfully compile and run, and kind-of, sort-of work, they are ready to move on tackling more complex problems and more ambitious projects.

This is where it all can get, well, complicated. Programming is like Jenga. Programs are easy to start, but can be very difficult to keep going.

As the code gets more complicated, we run into difficulties: in particular, it gets harder and harder to make any additions or changes to the code without breaking it. You may be surprised to learn that changing code without breaking it is the predominant focus of most programmers.

And if there's one thing we know about software, it's that it is going to change. That's why we call it "software". We write a program that we think solves our problem. Then we try to use it, and inevitably we learn how we could do it better. Then we go back and change the code to incorporate what we learned. It's one of the main reasons why we often wait for "Version 2.0" of a program before we consider adopting it. When change is difficult, software doesn't improve.

And you might also be surprised how quickly you can run into difficulties. I've run workshops where code attendees wrote in the morning was holding them back in the afternoon.

For these reasons, professional programmers understand only too well the importance of programming well, even on what might seem like trivial projects.

What is "programming well"?

Let's break it down into a handful of simple disciplines (simple to understand, not so simple to master, as it turns out):

1. Test Continuously

By far the most empowering tool a programmer can have is the ability to find out if a change they just made broke their program pretty much straight away. If we break it and don't find out until later, it can take much more time to debug. For starters, we're no longer working on that part of the code, so it's not fresh in our minds. We've got to go back, read the code and understand it again - a bit like loading it into main memory - before we can fix it. And if we've made a bunch of changes since then, then it can be much harder to pinpoint what went wrong.

For this reason, we find it's good idea to test the program as frequently as we can - ideally we'd want to re-test it after making a single change to the code.

Doing this by hand over and over again can be very laborious, though. So we automate those tests. Basically, we write programs that test our programs. This practice is very highly recommended. And it can be done in pretty much any programming language - Visual Basic, Python, C#, Java, FORTRAN, C++, you name it. If we can call functions we've written in our program, we can write code that drives our program - using those functions - and asks questions about the outcomes.

There are special frameworks that can help us to do this, and they're available for most programmig languages (e.g., PyUnit for Python is a "unit testing" tool that lets us automatically test discrete chunks of our software).

Automated tests, at the end of the day, are just programs. If the kids can write programs, they can write automated tests for those program. Simples.

Here's an example of an automated unit test for a Java program:

Tests have three components:

* A set-up - that initialises the test data or objects we intend to use for the particular test case we're interested in. In this example, we set up a DartsPlayer object with an initial score of 501, then take 3 throws, each scoring treble 20.

* An action - this is the code that we want to test. In this case, we're testing that throwing darts correctly changes the player's current score

* An assertion - we ask a question about what the output or outcome of the action should be in that particular set-up

Try it. I suspect you may find it makes a huge difference to how easy the going is, especially on more ambitious projects.

2. Write code other programmers can understand

Here's a fun fact for you: what do programmers spend most of their time doing? Reading code. It's estimated we spend between 50%-80% of our time just reading programs and trying to understand them. Understanding programs is the bulk of the work in programming.

And I'm not just talking about other people's code either. I've spent many a joyful hour looking at code I wrote - months ago, weeks ago, yesterday, before lunch - and wondering what the hell I was thinking.

Most of the programming we do is on programs that already exist. We're adding new features, changing existing features, fixing bugs, making it run faster or use less memory or disk space... There are all sorts of reasons why we spend most of our time wrestling with existing code. Add other programmers (hell is "other programmers"), and that effect magnifies to epic proportions. Working on projects with our friends, or collaborating with programmers out there on Teh Internets, makes readable code a very high priority. We're not just communicating with the computer, we're communicating with each other.

The best kind of code clearly tells the story of what the code does.

Look at this very simple example:

At first glance, it may not be entirely obvious what this code does. Programs give us an opportunity to make them more self-explanatory by choosing more meaningful names for the things in our code - functions variables, constants, modules and so on. If I refactor this code to make it more readable ("refactoring" is the art of improving our code to, for example, make it more readable, without changing what it does), I might end up with something like:

Some people - silly people - will try to convince you that the way to make programs easier to understand is through the use of comments. In prcatice, we find comments are often less than helpful. Firstly, they clutter up the code, which can make it even harder to read. And, like all documentation, comments can get out of step with the code being described. Comments can be an indicator that the code is difficult to read, and we've learned that it's better to try and tackle that issue directly rather than rely on comments or other kinds of documentation in all but the most extreme cases.

In the next blog post, we'll look at how we break our programs down, and a couple of simple principles for organising our programs that can make them easier to change.

Posted 3 years, 2 months ago on October 7, 2014