27. October 2014

You're already doing TDD

“I’ve always kind of hacked my code together and had the attitude like testing was for chumps.”

That was posted on Reddit the other day by someone, but it could easily have come out of my mouth a few years ago. This post is written for anyone who identifies with that statement and is wondering why they should bother with TDD.

My thesis is that you’re already doing TDD, you just don’t realise it. Because you don’t realise it, you’re not using any of the tooling that exists for it, so your life is harder than it needs to be.

When you write some code, I’m guessing your process looks a lot like:

  1. Think a bit about what the feature needs to do.
  2. Write some code.
  3. Run the code to make sure it did what you expected it to.
  4. Repeat steps 2 and 3 until it’s correct.
  5. Move on to the next thing.

When I write some code, my process looks like:

  1. Think a bit about what the feature needs to do. 1b. Write those thoughts as some code that will tell me when my code does what I expect it to do.
  2. Write some code.
  3. Run my helper code to see whether my code does what I expected it to.
  4. Repeat steps 2 and 3 until it’s correct.
  5. Move on to the next thing.

So, they’re pretty much the same, right? Only my process has a whole extra step! How inefficient! In practice, though, not so much.

The core is that your step 3 is really hard. How do you do it? Maybe you insert some debug logging to see whether some key variables are within an expected range. Maybe you look at the end user output to see whether it’s what you expected it to be. Maybe you step through your code with breakpoints in a debugger. To do this, you probably need to load up the interface and push some buttons. You probably needed to enter some information to create the state you need to exercise your code. It’s probably a pretty manual, labour intensive process.

My step 3 is really easy! I just run the code I wrote in 1b. “But didn’t it take forever to write all that code?” I hear you cry. Not that much, really. You get faster at it with practice.

It’s like any automation task. It takes a little bit of time up front, then you save time every time you need to do the thing. You automate all kinds of stuff already, right? You use a programming language that automates turning you instructions into assembly code. You use an editor/IDE that’s faster than a pen and paper. You use makefiles/build scripts to build your code and manage assets. You use a package manager to manage dependencies. A testing framework is just another one of these things.

Convinced? Great! Don’t get too hung up on ‘TDD’ the way the internet says you should be doing it. Just write some tests before you write some code. You can figure out where you stand on the religious issues later.

Now that you’re a convert based on the above, you also get all sorts of other great stuff! Remember when we wrote down our thoughts about what the feature should do? That’s documentation! You have a spec!

And we don’t throw those tests away now that we’re done with them. The next time we write another feature, we run them again! That way we can be sure the new feature didn’t break anything that worked before!

Also, when someone else wants to change the way your feature works, they don’t need to wonder what your code is meant to do. They can read and run the tests! Science!

25. July 2014

Node to go

On the server I mostly work in node.js, but I’ve been increasingly interested in Go recently. There’s plenty to recommend both platforms, but the things attracting me to Go are it’s ease of deployment and simplicity of ecosystem, among others.

Recently, I needed a utility to interact with the Cloudflare API. A simple dynamic DNS client that would set a CNAME record and keep it update when my ISP changes the IP address assigned to my home connection. It was a simple enough utility that I decided to write a version of it in each language.

The result is on github.

https://github.com/davidbanham/cloudflare_dyndns/blob/master/app.go

https://github.com/davidbanham/cloudflare_dyndns/blob/master/app.coffee

Each of the treatments individually is bad code. Neither of them is idiomatic for their platform. I’ve intentionally tried to keep them both the simplest way possible so they could each be similar in execution.

In the writing of them, I found it a lot easier to do the exploratory, hacking around stage in node. This is obviously primarily due to the fact that I’m vastly more experienced in it than Go. I think, however, it’s also down to the fact that node’s standard library is so much smaller. Something I tend to do a lot of when interfacing with a new API is making calls to it, then logging the response out to the terminal just to see what I’ve got. In node, this is just console.log. Everything is just console.log. In Go, I spent ages lost in the arcane invocations to fmt.Print and it’s variants. It turns out the magic words are fmt.Printf("%s\n", body). I would have been equally happy with os.Stdout.Write(body) but I didn’t know it existed at the time.

A large standard library is handy to have. I love node’s vibrant ecosystem and npm is a great resource of other’s people’s code. After having been burned badly by memory leaks in other people’s code, though, I’m increasingly reluctant to provide my dependency tree with too much fertiliser. If something is in Go’s standard library, I’ve got a reasonable assurance it’s solid.

The wonderful thing about Go is the security you get from the type system. If the thing compiles, it probably works the way you expect. In Java I constantly felt like I was wrestling the type system, but in Go it feels like we’re a team. The fact that the compile time is so quick is really wonderful, too.

I’ll be writing node for a while yet. THe size of the community and the industry adoption is growing every day and it’s a great place to be. I’ll definitely be keeping Go as part of my toolbelt, though, and using the best tool for the job at hand.

16. June 2014

Bad blogger, no biscuit.

After battling the broken comment submission on the blog for a while, only to then be told that registrations were down, this is a reply to this post about the NBN

Your parents are probably getting those speeds because that’s the plan they’ve chosen. You admit you have no idea what plan they’re on, nor even what technology their product is using.

Tip, if it was installed 12 months ago, it’s FTTP. The FTTN network is still mired in trials, and they’re delayed.

For a blog advertising a data-driven marketing consultancy, it would be nice if Daniel got some, you know, data.

The point of legislating against overbuilds in metro areas is that profits from the metro network are intended to subsidise the rural networks. This is, in effect, a redistributive tax.

Yes, it would probably be simpler to use the existing income tax system to achieve the same effect. This would also have the effect of ensuring that low income earners in metro areas do not subsidise the internet access of high income earners in rural areas. (I’m not saying this is the default case, but it’s a thing that will happen with the current model.)

That is actually an interesting discussion we can have! Much more interesting to look at both sides of the issue rather than just stating “Free market good! Monopoly bad!”

Yes, there are problems with both models. One of the big issues with FTTP was the rampant pork-barelling that took place and ensured that the first people to get the network were sparsely populated regional centres. There appear to be a lot more problems with the FTTN model, though.

We face very different challenges from New York and South Korea. We need a solution that makes sense in an Australian context given our population density.o

We also need discussion that takes us forward rather than just taking a crowbar to everything in sight.