Big project code architecture

November 10, 2012 | Filed under: programming

I actually wrote some new code for Gratuitous Space Battles today, and in doing so, I had to do a bit of chin-stroking and thinking about the general code structure of the game. GSB is not my latest game, so the code I write now for new stuff is more polished and better designed, but even so, I’ve coded about a dozen games from scratch before GSB, so it should be fairly good.

..and yet…

One of the best lessons you learn, mostly from experience, is how to arrange classes and objects in your code so that its fairly modular and not ‘closely-coupled’. In C++, what this amounts to is you shouldn’t have a lot of classes constantly using get() and set() calls to talk to the private members of other classes. Separate objects and basically separate for a reason. The hardest decisions to make in code are the big architectural decisions about what objects sit inside others, and who inherits from what. I’ve been coding in C++ for decades now, and I still know I often get it wrong. This stuff is really important.

For example, there is a class is GSB called SIM_Ship, which contains all the gameplay related stuff for a ship (totally separate from the visual representation of the ship which is entirely different and in a totally separate class). In an ideal world, that ship class would be pretty self-contained, without a ton of connections to other objects.

The problem is, over time, I’ve ended up adding stuff to that class that bloats it and makes the code messy. For example, it has a function in there to shake off limpet mines. This is a bad idea. The limpet mine code should all be within SIM_LimpetMine. SIM_Ship not only shouldn’t get involved with the limpet code directly, it shouldn’t even be aware that the concept of a limpet mine exists. That stuff should be modular, residing elsewhere and making use of generic functions and hooks within the ship code from a distance…

Sometimes that doesn’t work in practice because of optimisation and speed considerations, but often, the reason stuff ends up in the wrong place and the code gets confused and messy is that the coder is just adding ‘one more thing’ and doesn’t think its worth going to the trouble right now…

But when you are starting a big new project, its good to keep these issues in mind. Assume you will have 5x the code you think you will have, and then plan the code architecture accordingly.

13 Responses to “Big project code architecture”

  1. Fargo says:

    Hmmm… suddenly I feel like I’m doing it all wrong. =)

    On a serious note, have you found any particular resource that focuses on object structuring? Be it a book, website, old man on a mountain?

  2. cliffski says:

    Code complete was the best book I’ve read on the subject.

  3. Fargo says:

    Awesome, I’ll check it out. Thanks!

  4. kikito says:

    > the coder is just adding ‘one more thing’ and doesn’t think its worth going to the trouble right now…

    That’s called “incurring in technical debt”. It’s ok to do it sometimes, if you need to get something done quickly. But you *will* pay it, sooner or later.

  5. Have you considered an entity component system instead of oop?
    aka composition over inheritance, where an entity HAS A “proximity detonation behavior” (or whatever granularity you chose to divide your entities into) instead of IS A “mine”.

  6. Gnoupi says:

    Ah, yes, “adding one more thing” to something which was originally super modular and beautifully designed.

    Of course it’s nothing, the commercials just asked you for an added feature to show to the client, next week. Something small, but critical, you understand.

    Fast forward 3 years of this diet, and you get some yummy spaghetti code.

  7. cliffski says:

    I do some of that entity stuff to be honest. I’ve never been properly schooled in any of this stuff, read one book on OO a long time ago. In many cases, I’m concerned about performance, and some of the really purist approaches add insane amounts of bloat.

  8. Karl von Wargamer says:

    I can really recommend the ‘Gang of Four’ book (Design Patterns from Erich Gamma et al). It deals with OO in classic application development (like game programming).
    The patterns are solutions to recurring problems like how do you distribute responsibilities between your classes, what logic to move out from a class in order to have maintenable code etc.

    Not a panacea but contains much stuff which keep getting re-invented today, like the ‘entity component systems’.

  9. Albert1 says:

    Aren’t you over-engineering it?
    People tend to expect too much from objects – they get to the point in which having non-member functions at all is considered unapcettable.
    I’m coding my game (a retro FPS) in plain old C and this is what I’ve found along the way:
    – most of the fields used by a kind of entity are generally needed by othet kinds as well, except for some player-only statistics so at the moment I’m using a single entity structure: if I’ll ever end up with something resembling a sparse matrix, then I’ll split, rearrange… whatever. Every subclass you add is complexity, is code to manage, to keep synchonized.
    – relying on typeinfo (usually hand crafted in C++, which is time consuming) is generally bad: I think is generally better to have separate arrays for players, monsters, pickups instead of a single mess of everything with anything – if something changes its role in the game, I simply remove it from one table and insert it into another table
    – in the visit of the player’s node I manually run a check on pickups, to see if he/she touches anything, a check on monsters to keep/change their state, etc.
    I know this approach is sooooo low-tech, so primitive, and maybe one day I’ll have to change it, to use a smarter approach, but I think that’s wrong to start with the ultrasmart way – brute force pays off more often than many would like to admit!

  10. cliffski says:

    Well it depends how sprawling the code gets. A ship object in GSB is a HUGE thing, that has so many features and capabilities, and so much data, that it really helps with code legibility to split it into a whole bunch of different objects, both in terms of contained objects, and other objects that the SIM_Ship class inherits from (such as basic world object stuff).

    it’s spaghetti like as it is, without bunching that all into a single object.

  11. Albert1 says:

    By the way, how much of the code you wrote for GSB made into GTB? I really think that these days the root of all evil is no longer premature optimization: it’s the restless strive to write reusable code, when we all now that much of the code we write today won’t be used in the next one.

  12. cliffski says:

    Actually quite a bit of code re-use did happen there. All of the input, graphics and GUI library made it over, but the sound system changed, the graphics stuff was extended quite a bit, and there was a bunch of other changes, but I definitely reused a lot of stuff.

  13. Albert1 says:

    On inheriting vs composing: I think that one of the best book I read on this subject is “Object-oriented programming in ANSI C” by Prof. Axel-Tobias Schreiner, freely downloadable at http://www.cs.rit.edu/~ats/
    Note: the page shows the cover of the german edition, but the PDF is in english.
    Not only it shows how to do OOP in a language not designed for that, but the chapter on Callbacks has an interesting discussion on delegation, and when to use it instead of abstract base classes. With some work, you can do that also in C++, which doesn’t natively support delegates. Another good book is “Object-Oriented Game Development” by the british programmer Julian Gold. While I don’t particularly like OOP, I have to admit that probably C++ isn’t the best language at that. I happen to like D – it’s how C++ was meant to be. D support delegates and having them built into the language, along with interfaces, etc, really changes the way you approach problems. By the way: how long it takes to compile the entire C++ codebase of GTB?