You Didn’t Need It
You Ain’t Gonna Need It is pretty much a guiding principle of mine in more recent years. The concept of ‘future coding’ is very easy to fall into. You anticipate a need for something so you try and cater for it early; kind of like risk mitigtion. The problem with all of this is that things change. The age old philosophy that Change is the only constant in life cannot be avoided. You find new ways of doing something, an assumption you made turned out to be wrong, a new feature is required, an old one is thrown away - all this stuff has happened during the years I’ve been a profressional programmer and they will continue to happen long after I’ve hung my keyboard.
My mindset, however, wasn’t always like this. I used to believe it was the job of a software engineer to anticipate all of these things and create something that was generic for all of time. Future coding was a core concept and it’s very evident in this old codebase.
With this project I’ve got the unique opportunity to revisit the past and see of the future coding decisions I made. We are in the future right now and none of those decisions and ideas have stood the test of time. There is very little to be ‘proud’ of in this codebase, except that maybe something is visible and moving around the screen. It’s rough, but it’s a rudimentary 3d game whereby I load raw assets and display them in response to a user’s input. These days, that’s an achievement given you could accomplish the same thing in 10 minutes with Unity or Unreal.
Minimum Viable Product
THe MVP is a concept you hear a lot about in the agile circles. It’s essentially about creating the bare minimum you need to in order to achieve a goal.
With this in mind, I’ve decided that I’m going to set my current goal on stripping back everything that doesn’t contribute to the current active featureset of the game. All the stuff that was there in spirit but commented out because it doesn’t work, or is missing will go.
The current featureset is therefore:
- Load model
- Load ship data
- Render model on screen
- Model has a bounding box (I’m keeping it because it’s visible)
- Move model in response to keyboard input
- ‘Animate’ model on movement
If it’s not in that list, it’s not in the live codepath. If it’s not visible or materially contributing to the current features, it will be removed. If it’s an over-abstraction of a concept, it will be removed.
If you’re skeptical about lean development principles, look away now - I’m not taking any prisoners. Perfectly ‘good’ code will be removed.
Out with the old
Some stats before we begin:
cloc | Complie time --------|------------- 4168 | 00:00:56.54
First up, the finite state machine that is a baseclass for the entity class. It’s a strange decision to have made anyway, especially considering it’s not actually used anywhere. Chopped.
I came across this when I was cleaning out the smart pointer system. It’s total trash. Essentially a CPU particle system that treats
particle as an object. And each particle is allocated on the heap. Each particle used to be an IMMO. The only way this could have been any worse would have been to have treated each particle as an entity.
Removing it was trivial. I deleted the whole
include\fx directories and compiled. Nothing changed. It is completed unreferenced.
That’s 500 lines of shitty code gone. I’m glad that this whole system is consigned to the garbage heap.
The log system is initialized and never written to. Not on error, nothing. It’s completely unused. The code is garbage; it’s an unbuffered log that writes directly to the filesystem.
It’s going. And with it, the
Singleton class, as that’s the only use of the singleton.
The game runs at 700 fps; when I need to profile I will. The profiler system was removed. Wasn’t used - don’t need it at this point.
My nice speedy optimization of hashing strings into ints for blah blah blah. Didn’t need it.
The whole system for firing weapons isn’t hooked up. If you remember from a previous post, the weapon system didn’t seem to have survived the migration to this current codebase from an older one, so it was commented out and referenced missing classes.
I’ve deleted the whole thing, including pulling out any references to it in comments or update loops.
File containing random utilities that aren’t used. Deleted.
Quad class. Deleted.
Game class has a concept of a
IGameState stack - states can be pushed to and popped from the stack, triggering enter or leave logic. The problem is that there is only one GameState, which is the
PlayState. As a result, the stack isn’t required.
Furthermore, after removing the stubbed methods that are called on this state, the only one that actually did anything was the
updateState method. Looking at this code, it does nothing that can’t be done inside the
Game::update method, it’s a pointless abstraction. So I refactored the logic from
Game and deleted it.
As it stands right now, we load a couple of textures into the game and do nothing with them. The models aren’t textured; there’s no particles and no UI. As a result, the whole texture and image system can be stripped out completely without affecting anything. If I need this in the future, I would likely do it in a different way - using
SDL for image loading and likely using shaders in the rendering pipeline.
As a result, I removed the entire texture and image loading system. Turns out that the rendering system didn’t even handle textures anyway - there was no OpenGL code to remove.
Removing Dead Code
There’s a bunch of code that deals with ‘managing’ objects. Loading them, retrieving them, removing them. The problem is that this isn’t called anywhere, so it’s dead and can go.
I had a
Timer class that wasn’t used anywhere. Gone.
Entity class has a bunch of dead code. Message handlers that are wired up but do nothing. Gone.
Remember I talked about the entity id “freelist” concept that was in here? The code was bugged and it’d end up picking the next id anyway. That whole thing can go.
What followed is just a general cleanup of methods that never got called, or if they did, were completely empty. Interestingly, a bunch of the cleanup code can be removed because I’m handling lifetime of objects correctly now.
Here’s the stats after the cleanup exercise:
cloc | Complie time --------|------------- 2284 | 00:00:29.46
I’ve almost halved the lines of code and reduced the compile time by a further 25 seconds.
What’s more, the ‘game’ is exactly as functional as it was before. Sure, we’ve lost a bunch of systems and engine type code, but it was all doing absolutely nothing. It had no point in existing other than to take up compile time.
What’s fun is comparing where we were at the start of this series with where we are now:
| Start | Now | Difference --------|---------------|-------------|----------- cloc | 5863 | 2284 | -3579 Compile | 00:03:00.35 | 00:00:29.46 | -00:02:31
I’ve removed over 3500 lines of code and shaved 2 minutes and 31 seconds from the compile time, whilst retaining the same playable version of the game.
Makes you think, huh?
There’s a couple of small, mechanical things I want to clean up before I think about what to do next. But that’s for another post.