It is a truth universally acknowledged, that a readable codebase in possession of a good engineer, must be in want of comments. As manipulators of logic, we programmers (and sith, I guess) tend to have a habit of dealing in absolutes. You’ll often see “well commented” as a metric of readability on university marksheets and interview homework checklists. In the spirit of breaking that habit, I’m not about to argue against comments as a whole. Instead, I’ll show you how thinking of them as a last resort it can force you to deal with the root cause of confusing code- instead of just treating the symptoms.
If you’ve ever played Sea of Thieves, the game I’m working on as an engineer at Rare Ltd, you may have run afoul of skeletons firing cannons at you while you sail past an island, minding your own business. One of the first pieces of work I did here at Rare was programming the algorithm the skellies use to aim the cannon and provide a sense of emergent danger for players. In this article I’ll give you a peek behind the curtain at how we’d build up the moving parts of a gameplay feature. We’ll go step by step through how I designed the first version of this cannon aiming algorithm, which was released around E3 2017 to our Technical Alpha players. The code may have changed quite a bit in the year since we released it, so it may not exactly match the behaviour you can see in game now.
When you work on a large, constantly changing codebase with lots of other engineers, there’s a lot you don’t know about the person who will next change your code. They could be a new hire who isn’t yet familiar with the code standards. They could be an experienced programmer with a different opinion about code design. They could just be your future self, having a long day and prone to making errors. At their lowest common denominator, each of these people is a very fallible human being with a base level of programming understanding and a heap of cognitive biases- I suggest that you write your code for this person.
If you think of each class or set of functions you write as an API, you can anticipate what ways it could be misused or misunderstood and take preventative measures. This is so much quicker than it is for someone else to dig through the source files trying to understand why your function call isn’t returning what they expected. Imagine that the hazards in your code like a dereferenced pointer or a non intuitive return type are like physical hazards in the real world. If you owned public property with a big hole in the middle, you’d put up warning signs and maybe a fence to prevent people from falling in. Code has the additional challenge that people then have the authority (and maybe good reason) to come along and knock your fence down or fill the hole with sulphuric acid, but at least your fence says “people probably shouldn’t be allowed to fall in here”.
At Rare we tend to avoid using comments in the codebase, and very few files have any. This may be a matter of taste, but it definitely has the effect of encouraging you to learn to use all the tools at your disposal to make your code speak for itself. Here I’ll break down different types of “code hazard”, and how we can guard or eliminate them without relying on code comments or documentation.
It’s not exactly traditional to use automated testing in the game development process, but at Rare we’ve been developing our title Sea of Thieves with a continuous delivery method. This means we try and have a stable production-ready build at all times, and this relies on the automated tests running round the clock. Every time we check in a change to the build, it has to run against the current build and pass all the tests. If you want to learn more about how our games-as-a-service based development process, there’s a really interesting series of blog posts about it here , written by my colleague Jafar Soltani from the infrastructure team.
So what’s it like working at the pointy end of this continuous delivery model? It can feel like it’s all fun and games until you have to write the tests, or at least it did when I joined. One year, and several silly mistakes caught by simple unit tests later, I’m decidedly pro-testing. When your unit tests are part of the implementation and debugging process, it becomes a tool rather than an annoyance.