so I’ve been reading this altdevblogaday thing and couldn’t resist having a go! but, oh the agony, what to talk about? So, I was sitting there, on a sunny beach as it happens, knitting (I kid you not), very badly, and I realised: like playing a musical instrument, like any learnt skill, in knitting, muscle memory makes a huge difference. practice makes perfect. or at least, practice makes less crap.
and this is true of coding, and game development, at all levels – from code to architecture to design to vision. one of the things I’ve noticed about great coders (of which I am not yet a member) is that their code smells really, really nice. they just produce code that is readable, less buggy, robust to changes around it, easy to refactor – so many things. why is this? it’s extremely hard to quantify or enshrine in a set of rules – many people have tried, with varying degrees of success.
It seems to me that as you practice, as you get good, you develop a spidey sense that tells you when you’re going down the wrong route. the interwebs is LITTERED with advice about patterns and antipatterns – reduce state! don’t duplicate code! dont use goto! – but for each of those rules, there are counters: duplicate state for efficiency! duplicate code to reduce plumbing! do use goto to avoid horrid indentation or more clearly show the execution path! – etc ad nauseam. The real key is not the DO or the DONT – the point is that great coders develop this weird, uncanny, freaky sixth sense about when to make a rule, and then when to break it. In that sense, this article/rant is a sort of unauthorized spiritual brother of Dylan’s excellent earlier post on the importance Aesthetics in game coding (/aesthetics-and-the-art-of-being-anal-for-the )
The coder I think of most in this respect is mediamolecule’s David Smith. He’s responsible for his fair share of smelly bugs, but in general his code has this – I dunno – gorgeous shape to it. A delicate fragrance of beauty. It’s often so succinct, so short and readable, and not in the perl-golf-line-noise kind of way, that sometimes I’m left browsing around it looking for where the CODE is. I expect to find some horror lurking at the deepest recesses of a physics engine or hand written parser, and instead find a series of neat interlocking parts with no fat and no mess. By the way, he’s quite a good knitter & crochet-er too.
I first met dave at Lionhead studios, where he was a young gun coding away on Fable and I was a slightly more jaded but equally young gun experimenting with R&D projects. It was back in the era when physics engines were all new and shiny, supposedly impossible to write (oh the classic FUD of middleware. but I digress), and as a result there was a slew of pretenders to the throne that now seems to be safely sat in by Havok (which is, by the way, by all reports, a very fine piece of middleware – though I have never used it myself). Having woefully and n00bishly bought into the FUD, I wanted to pick me a middleware to solve all my physics woes. But which one? I knew dave’s resume to lionhead had included absolutely no industry experience but also an exceptionally interesting physics based driving game – so I sent him an email asking him if he’d help me evaluate various physics middleware that I was contemplating using for a toy game project called ‘the room’ (consisting at the time of only me and an artist – Mark Healey, also a founder of MediaMolecule). Dave replied about 48 hours later with a rather scathing deconstruction of my front runner’s middleware demo program (which was, if I recall, lots of little chairs falling into a messy pile at what seemed like an impressive frame rate). Along with his critique came some source code and an executable – that recreated the demo, faster, with more stable stacking, and, well, almost no code. Or at least, none that smelt bad. I was flummoxed. Reading his attached code, there was just so little there! I could understand it, or so I thought. It was actually easier to read and understand, than the code to exercise the rather crufty API of the (now-defunct) middleware. of course it captured a bunch of subtle and not obviously visible experience encoded in the order he chose to integrate, or the particular magic values, or whatever. but I think it was more the aesthetic (there’s that word) of the code, and the approach to it, that really, really appealed more than the fact it worked so well, that ‘got’ me.
I’ve learnt a lot from dave since (and violently disagree with him often, so in case he’s reading – you’re not perfect dave! you’re wrong! etc) – and for the longest time I tried to emulate his style: state is the root of all evil, get rid of it, or encapsulate the places that change it; OOP is the devils work – especially in a world where most of the meat of the code involves two or more objects interacting, rather than one object rendering itself as a webpage; simple, functional-where-possible and direct-procedural code is beautiful; but it was only when I started internalising these ideas to the extent that they formed an inner ear buzzing noise whenever violated, that I started to improve as a coder.
You see, the thing is, it’s one thing to say ‘practice makes perfect’, but its another to know WHAT to practice. If you’ve ever learnt a tricky piece on the piano, you’ll know the temptation when practicing to play the bit you can already do, start feeling really awesome because you’re definitely the next Glenn Gould, and then hit that passage that you can’t play yet. You either go on, or go right back to the start so you can play the easy bit again. (‘ah, it feels so good’) That’s crap practice. Good practice is really hammering on the bit you CAN’T do, until you understand what you need to improve, and then, actually improve. Blood sweat and tears is part 1, knowing to apply it on the painful bits is part 2. Part 3 is presumably profit…
I’m rambling again. Sorry. Here are the things I try to think about when I’m practicing coding, to guide me towards the hard bits – which practicing by the way, includes professional coding just as much as hobby coding: (this list by the way serves as an internet-remembered list of things that I will come back to and curse that I dont even follow my own advice. hypocrisy!)
* firstly, and MOST IMPORTANTLY, remember: the cost of re-doing something is TINY. code is CHEAP. really, really cheap. Especially if you wrote it, even better if recently. Lost your harddrive? devstudio crashed? GREAT! You’ll do it better second time round. Corollary: there is NO SHAME in revisiting old code and rewriting it as you go. In fact, do that lots! And as above, go back over the MOST PAINFUL bits, not the least painful ones. this isn’t fancy refactoring, this is just iteratively noticing a spray of x+1s and realising that if you just stored x+1 instead of x, they’d all go away. doh! This is realising that that horrific mess of 5,000 lines of C code has a user-observable result of rand()%3, and therefore it should just be replaced with… rand()%3.
This is realising that source control has elephant memory, and it’s time to delete that function you never use that’s there in a comment ‘for reference’. DELETED.
* the above point works at all scales too: single functions, single lines, and entire systems. NEVER, EVER, EVER be afraid to rewrite a whole system if it is causing even moderate amounts of scary undefined pain and crash bugs. I can’t stress this enough, and you should to yourself, and your peers, and your boss, and your mum, and your cat. the cost of just soldiering on with poor or ugly or legacy or messy code ‘because it’s really complex to rewrite’ or ‘because nobody really understands it’ is HUGE AND ONGOING, and the cost of rewriting it is probably MEDIUM AND SHORT LIVED. even the new bugs you introduce, will be fresh and relevant and you’ll be around to fix them. infinitely better. Unfortunately, this is the most terrifying maxim to actually follow when in the thick of development, and I have violated it enough times to know the pain. But every time I have gone ahead and rewritten, the short term pain has ALWAYS been justified. 100%. one day, I will learn.
* another point about rewriting: be prepared to know & love your data structures. some of the most successful refactors (or, most successful codez first time around) revolve around having just the right data structure representing their state. a lot of people think of refactoring as changing variable names or moving where API boundaries are, but an equally valid type – especially in constrained environments like consoles – is to reconsider a system in terms of its data structures, and be bold enough to change them. perhaps you realise that a particular kind of hashmap would really beat the redblack tree you are using, or that those backpointers should not be needed, if only you could get rid of that api call that is the only one that needs them, or whatever. the resulting rewrite is typically extensive but extremely satisfying. the spidey sense (and reduction in lines of code) will tell you when you’ve got it right.