Category: Code

Let’s Make a Game Engine!

I occasionally get asked about the game engine I wrote back at independent games dev Limebird Entertainment. Specifically, people want to know how you start such a massive project. 100,000 lines of code later, it’s easy to point at each and every subsystem you have, explain what they do and how, and what the important design decisions were. You could probably even explain the reasoning that led to it being created at some point.

A Blank Slate by kiwikewlio

But where do you start? When you’re sitting there with a blank slate, what’s on the first row? The problem here is you’re starting something massive that you probably know next to nothing about. Do you open up your editor and create a file? Which file? Or do you start designing your architecture on paper or a whiteboard?

It’s a reasonable question to ask, and also an utterly pointless question to ask. My answer is “anywhere”. The important part is not where you start, but that you start — and that you keep going.

Identify one piece of code you need, and start writing it. You’ll be facing a million decisions anyway — what build system do you put all your stuff into to get it all to build on all your target platforms? How do you set up unit tests for your code? What version control system should you use? How do you design system X? How does that fit with system Y? All of these questions are things you need to deal with, and the only way to deal with them is one decision at a time.

One of the important things to realize is that the normal way of working in a development team doesn’t really mean much in this situation. How do you prioritize one component against another when you’ll need them all to get anything at all? Do you even know all the components you’ll need? You may think you do, but you’ll find out you don’t. The important part is to get going and keep going until you can start iterating properly on your code base.

Still, some tips:

  • As your first code file, pick something you’re reasonably familiar with to get going. Regardless of the scale of the project, there’s going to be some small part of it that resembles something you’ve done before — do that first, to get up and running. It helps to be in familiar territory when compiling your first class, because that one first class is going to be where you get your environment up and running.
  • Don’t over-engineer. Stay well within the bounds of what you’re reasonably certain that you’ll need. At this point, you want to keep moving to new parts of the project, so you can quickly reach a point where it starts doing something you want — so don’t waste effort on things you might need down the line. This sounds like simple advice but is actually quite hard, since you have no idea what you’re doing at this point.
  • Accept that whatever you do will be replaced. You’re new to the things you’re doing. The first things you write will be incredibly uninformed and will undoubtedly be rewritten a few times as you learn about the system you’re writing. The important part is not that you write the perfect system the first time around, the important part is that you write the system and learn from it. Once it’s running, you can go back and fix it. Sometimes, the only way to get a system just right is to have done it once before.
  • Make it do something. You can write core systems and design your architecture all day, and even with unit tests and all kinds of fancy techniques to prove to yourself that it works, you dont’ actually feel it until you have something that runs. Even if what you have is just a simple rotating triangle, the thrill of having a rotating triangle in your own game engine is a lot better than seeing the TriangleRotationTest pass.

So where did I start? We had a very brief discussion on how our design would look like, and what code we needed on a very high level, and then set off coding. I remember coding up our first version of a 3×3 and 4×4 Matrix math code on my laptop at my grandparents cabin in the countryside that summer. It was somewhat buggy, and I didn’t really know what I was doing… but it got the ball rolling.

Programming Culture

I decided to learn Common Lisp.

After feeling like I’d somewhat gotten stuck in my programming development, I decided I needed to do something well outside my comfort zone in order to get off the plateau. So after a quick look around, I decided Lisp was probably a good target.

Then I decided not to learn Common Lisp.

Here’s why:

I’ve learnt a fair few languages in my days… some have been incredibly useful but scorned by others like Visual Basic, some are popular and have a great following like C++ or Perl. Some are small but surrounded by friendly enthousiasts, like Lua. Some are just generally strange but well documented, like tcl. All of these are different experiences to learn, because not only do the languages differ but their communities differ.

It’s a lot like learning to speak a new language and at the same time discovering the exciting culture that comes with it.

But some programming languages seem to have a more or less arrogant culture surrounding them. They tend to be small languages that claim to be revolutionary yet no one uses them. They’re small and they’ve been small for a long time. Lisp falls into this category. One article I read strongly asserted that after decades, the time for Lisp was just about to come. Soon, Lisp would be the mainstream choice. Pity the article was 20 years old, and the use of Lisp has hardly increased since.

Lisp

It’s weird that this is the case, if the languages themselves are so revolutionary as their followers claim. I’ve seen it with both Lisp and Smalltalk, and after going through it a second time, I think can explain why: Their programming culture has confused teaching with preaching.

And learning new stuff is really important when it comes to programming… which means teaching is equally important.

Let’s back up a bit… I learned Lua. If you try it, your first move will probably be a google search and you’ll find books online and help pages that in a friendly tone go “here’s lua, have a try, plunge in”. But when you try to learn Smalltalk, the same method will get you pages on why Smalltalk’s design is great. Starting to browse forums about Smalltalk, most of the discussions I ended up reading were about how God Alan Kay certainly didn’t mean for object oriented programming to look like C++ (“lol, what a thought”).

The same thing happened to me when I tried to learn Lisp. Finding several books online was not a problem, Google kindly sent me to a site on learning lisp, and following the advice on that site I started reading through a book online, and in parallel started reading a couple of sample chapters of another book. The sample chapters gave me nothing — some code examples, some interesting stuff, but mainly the focus was on why Lisp is so much better than all the other languages.

When I was halfway into chapter two of the book, it had still not finished motivating why Lisp was such a wonderful language, that the absence of a syntax really is the only way to extend a language and build bottom-up rather than just top-down and how you worked in a completely new way with Lisp and that all other languages were nothing but shallow copies and could your language really do this? And at that point I gave up.

The only feeling I get from this furious defense of the language is a feeling of uncertainty. Why do you need to tell me it’s so superior when all I want is to be shown how it works? Surely actually showing me would be the best way to convince me, especially once I’ve already taken the interest and initiative to go looking for a place to learn?

I have no doubt that Lisp is a good language. I’m still interested in functional programming languages. But I’d rather take on one where the culture and community is open-minded and busy doing kick-ass things with their language rather than telling others how kick-ass it is (or worse, how everything else is crap).

Oh well, F# looks interesting. In the meantime, I learnt a different language and did some really cool stuff.

The Fine Art of Being an Asshole in All the Right Ways

Wtf?

We do code reviews of all code that’s about to be checked in. It’s interesting to see the different approaches to code reviews different coders have. Many (especially junior) programmers tend to lack the self confidence required to go about a code review in an effective manner.

Let me explain that — why would a code review require self confidence? Well, a code review will go over a large amount of code at times, and your job as the reviewer is to find any question marks that might possibly cause any kind of trouble. This is, apparently, a problem for many programmers when they review the code of another (usually more senior) programmer, since pointing out potential errors or problems is seen as somewhat sensitive. I know many coders get very emotionally attached to their code.

You would think this should be something which happens only to junior programmers, but I’ve seen this happen with relatively senior programmers as well. It’s more about character than it is about experience I guess. The reasoning is “I don’t understand this, but this guy’s smart so it’s fine” or something similar, sometimes connected to how much code there is to go through and how long that would take.

However, the quality of a code review is directly proportional to how much you can disconnect your own respect for others. Your task is to understand everything you get shown, and to be the most nitpicking, hard-to-please obsessive-compulsive asshole the earth has ever seen for as long as the code review lasts.

Sound like something you don’t want to do? I hope so. But remember, you’re doing a service here… if there are bugs, someone is going to find them. We have QA people who specialize in finding bugs and piling them up on your desk, producers with a great attention to detail, and if nothing else you can bet someone will find it and it’ll end up on youtube. I don’t know about you, but at least I’d want to see my errors pointed out to me before I check them in.

So here are my tips for doing a code review:

  • Understand everything. If you don’t understand something, make the reviewee explain it again in a different way. Chances are, you aren’t understanding because there’s something strange going on, or because what’s been done is unnecessarily complicated. Either way, if you don’t understand something you can’t guarantee that it’s right. Part of the purpose of a code review is for the reviewee to explain his thinking, and while doing so make for a possibility that he or she discovers errors as well.
  • Be picky. Point out all details, from naming convention errors to coding standard misses to comment spelling errors. Whenever something gets checked in, the cost of changing it is a lot higher. Often the details may be the things that are wrong, and being picky forces you to notice such things.
  • Look at everything. Resist the temptation to skip files where only small things have changed, but like I mentioned above, the details can often be what’s wrong. I can’t begin to count the amount of code reviews I’ve done where we’ve found inverted if conditions and equally dangerous things. The relevant code is simply a missing exclamation mark, but the consequences are far reaching, and if you had skipped the file because it had almost no changes in it, then you would have missed it.
  • Endure. If you feel like you’re being a pain in the ass, think of it as a great favor since the amount of potential bugs you’re stopping is high. It’ll also act as an incentive for the reviewee to focus more on code quality for next time.

Think of yourself as the guardian of quality, personally responsible for the quality of the code you’re reviewing. Imagine that you’ll be the one yelled at if the code is broken, or the one who’ll be put to fix it.

The end result will be much higher quality code.

Human Stack Overflow

It’s interesting to every now and then stop what you’re doing and take a look at (and some time to think about) how you do things. The human brain is incredibly good at some things, and incredibly bad at others, so it makes sense trying to maximize the amount of time you spend doing things in ways that the brain is good at.

I find that I’m good at executing algorithms on a low level, where each component is easy to execute. For instance, doing the laundry would easily be described as an algorithm of sort laundry, put clothes in machines,  wait until done, move clothes to dryer, wait until done and finally sort clean clothes. All easy steps leading to an easy total procedure. Not fun, but easy.

stackHowever, when steps become complicated I soon hit my own internal stack limit and overflow it. For instance, today I started out investigating how to do something new with our pathfinding middleware. I read the docs, and went to take a look at the examples. The examples gave me an error and crashed, so I had to look up why. Turned out I needed a new license file compiled into the examples. I downloaded the license file from the support site, and tried to compile the examples. The compiler gave me a DirectX include error, so I went to install the DX SDK. After finding the setup package, the installer told me I needed to reboot.

It seems like a sequential set of problems to solve, but actually it’s a recursive process. I was rebooting to solve a compiler error to fix a license problem to run an example to learn more about how to implement a feature. That’s quite a stack depth, and in some cases the stack can simply overflow. When this happens, you solve some problems you’re working on, but then somewhere along the line realize that you forgot whatever it was that caused you to start solving that last problem.

This used to happen to me when I was writing a game engine for the Velox concept game. My colleague at the time even wrote a couple of small scripts to be able to push and pop things off a stack on his workspace in order to get around the problem.

You don’t even need a hard programming problem for it to occur. Have you ever found yourself starting out cleaning the apartment, but then ending up sorting through all your old papers you found in a stack somewhere? In the end, you’ve missed the target of cleaning the apartment, because you built up too deep a the stack and lost track of the original work item.

This whole thing is also a part of the explanation to why the human brain is so horrendously bad at context switching, and why programmers hate being interrupted and asked to work on something else for a bit. You not only have to put aside what you’re doing right now, but your entire stack of reasons you’re doing it.

My colleague absolutely did the right thing. Explicitly keeping track of your work stack is important, because it lets you easily remind yourself of what you’re doing. It takes a bit getting used to, but definitely increases your productivity in the long run.

But Bad Programmers Will Abuse It!

I recently had an interesting argument with some collegues about the merits of properties as a language-supported construct. If you haven’t heard of the property (or “smart field”) concept before, here’s a quick intro:

A property is a class field that acts like a variable, but encapsulate get and set methods. This means that from the outside, you can do something like:

a.field = 10;

but what actually happens is that the method “field set()” runs:

public int field {
    set {
        m_field = value;
    }
}

If you want a more exhaustive look at properties there’s a good explanation of C# properties at C# Station.

Ever since my days long ago coding Visual Basic (ugh), I’ve been a fan of the property concept. In my view, it provides language support for something we do anyway — providing accessor methods for private data fields, doing away with something that breaks the natural expectation of how to do things… normally I assign a value using the assignment operator, now I have to call a set function.

Worse, without properties you’re in a situation where you have to either provide set and get methods for all fields for consistency, or start out with public data fields and be ready to change all calling code if you need to do some additional checking on the value being set. Nearly everyone goes with option 1, so we end up doing the tedious extra work of typing out default get and set methods, or using refactoring tools to write them for us. Either way, the code gets cluttered with stuff we didn’t really have a specific use for.

So coming back to the discussion we had about properties, what are the reasons that people don’t like them? The argument can basically be summed up as this: “But people can put all kinds of stuff in that method. If I assign a variable, I assume it’s only going to save a value, not do something heavyweight.”

So essentially, bad programmers will abuse the feature, thus it’s bad. Well… we already do this, it’s just not built into the language. Someone can calculate the next unknown digit of π or brute force a solution to a 1024-bit RSA key in your setField() method just as they can in the field set() method. In both cases, you’re going to expect a simple value assignment, possibly with some safety checks.

The bottom line is, no language is going to protect you from the abuse done by unskilled programmers. Funnily, the argument tends to come from coders who work primarily in C++, which must be the best language possible if you’re looking to set traps for yourself. You can do really horrible things to your fellow C++ coders using operator overloading, but that doesn’t make operator overloading a bad feature.

WordPress Themes