in C++, Data-oriented design, iDevBlogADay, Software engineering, Test-Driven Development

The Always-Evolving Coding Style

This is my first entry into #iDevBlogADay. It all started very innocently with a suggestion from Miguel, but the ball got rolling pretty quickly. The idea is to have one independent iPhone game developer write a blog entry each day of the week. At first we thought we would be hard-pressed to get 7 developers, but it’s starting to seem we might have multiples per day!

Check out the new sidebar with all the #iDevBlogADay blogs. We’re also putting together a common RSS feed if you want to subscribe to that instead.

Writing is addictive, so don’t be surprised if this once-a-week minimum turns into multiple-times-a-week.

 

matrix.jpgEvery developer who’s been working on a team for a while is able to tell the author of a piece of code just by looking at it. Sometimes it’s even fun to do a forensic investigation and figure out not just the original author, but who else modified the source code afterwards.

What I find interesting is that I can do the same thing with my own code… as it changes over time. Every new language I learn, every book I read, every bit of code I see, every open-source project I browse, every pair-programming session, every conversation with a fellow developer leaves a mark behind. It slightly changes how I think of things, and realigns my values and priorities as a programmer. And those new values translate into different ways to write code, different architectures, and different coding styles.

It never happens overnight. I can’t recall a single case where I changed my values in a short period of time, causing dramatic changes to my coding style. Instead, it’s the accumulation of lots of little changes here and there that slowly shifts things around. It’s like the movement of the Earth’s magnetic pole: very slow, but changes radically over time (although maybe just a tad bit faster).

Why Talk About Coding Styles

Coding style in itself is purely a personal thing, and therefore, very uninteresting to talk about. However, in its current form, my coding style goes against the grain of most general modern “good practices”. A few weeks ago I released some sample source code and it caused a bit of a stir because it was so unconventional. That’s when I realized it might be worth talking about it after all (along with George bugging me about it), and especially the reasons why it is the way it is.

Before I even start, I want to stress that I’m not advocating this approach for everybody, and I’m certainly not saying it’s the perfect way to go. I know that in a couple of years from now, I’ll look back at the code I’m writing today and it will feel quaint and obsolete, just like the code I wrote during Power of Two Games looks today. All I’m saying is that this is the style that fits me best today.

Motivation

This is my current situation which shapes my thinking and coding style:

  • All my code is written in C and C++ (except for a bit of ObjC and assembly).
  • It’s all for real-time games on iPhone, PCs, or modern consoles, so performance and resource management are very important.
  • I always try to write important code through Test-Driven Development.
  • I’m the only programmer (and only designer).
  • Build times in my codebase are very fast.

And above all, I love simplicity. I try to achieve simplicity by considering every bit of code and thinking whether it’s absolutely necessary. I get rid of anything that’s not essential, or that’s not benefitting the project by at least two or three times as much as it’s complicating it.

How I Write Today

So, what does my code look like these days? Something like this (this is taken from a prototype I wrote with Miguel of Mystery Coconut fame):

namespace DiverMode
{
    enum Enum
    {
        Normal,
        Shocked,
        Inmune,
    };
}

struct DiverState
{
    DiverState()
        : mode(DiverMode::Normal)
        , pos(0,0)
        , dir(0)
        , o2(1)
        , boostTime(0)
        , timeLeftInShock(0)
        , timeLeftImmune(0)
    {}

    DiverMode::Enum mode;
    Vec2 pos;
    float dir;
    float o2;

    float boostTime;
    float timeLeftInShock;
    float timeLeftImmune;
};

namespace DiverUtils
{
    void Update(float dt, const Vec2& tiltInput, GameState& state);
    void Shock(DiverState& diver);
    void StartSprint(DiverState& diver);
    void StopSprint(DiverState& diver);
}

The first thing that stands out is that I’m using a struct and putting related functions in a namespace. It may seem that’s just a convoluted way of writing a class with member functions, but there’s more to it than that.

By keeping the data in a struct instead of a class, I’m gaining several advantages:

  • I’m showing all the data there is and how big it is. Nothing is hidden.
  • I’m making it clear that it’s free of pointers and temporary variables.
  • I’m allowing this data to be placed anywhere in memory.

The fact that the functions are part of a namespace is not really defensible; it’s pure personal preference. It would have been no different than if I had prefixed them with DriverUtils_ or anything else, I just think it looks clearner. I do prefer the functions to be separate and not member functions though. It makes it easier to organize functions that work on multiple bits of data at once. Otherwise you’re stuck deciding whether to make them members of one structure or another. It also makes it easier to break up data structures into separate structures later on and minimize the amount of changes to the code.

Probably one of the biggest influences on me starting down this path was the famous article by Scott Meyers How Non Member Functions Improve Encapsulation. I remember being shocked the first time I read it (after having read religiously Effective C++ and More Effective C++). That reasoning combined with all the other changes over the years, eventually led to my current approach.

Since everything is in a structure and everything is public, there’s very little built-in defenses against misuse and screw-ups. That’s fine because that’s not a priority for me. Right now I’m the only programmer, and if I work with someone else, I expect them to have a similar level of experience than me. Some codebases written with a defensive programming approach have an amazing amount of code (and therefore complexity) dedicated to babysitting programmers. No thanks. I do make extensive use of asserts and unit tests to allow me to quickly make large refactorings though.

Another thing to note that might not be immediately obvious from the example above is that all functions are very simple and shallow. They take a set of input parameters, and maybe an output parameter or just a return value. They simply transform the input data into the output data, without making extensive calls to other functions in turn. That’s one of the basic approaches of data-oriented design.

Because everything is laid out in memory in a very simple and clear way, it means that serialization is a piece of cake. I can fwrite and fread data and have instant, free serialization (you only need to do some extra work if you change formats and try to support older ones). Not only that, but it’s great for saving the game state in memory and restoring it later (which I’m using heavily in my current project). All it takes is this line of code:

oldGameState = currentGameState

This style is a dream come true for Test-Driven Development (TDD). No more worrying about mocks, and test injections, or anything like that. Give the function some input data, and see what the output is. Done! That simple.

One final aspect of this code that might be surprising to some is how concrete it is. This is not some generic game entity that hold some generic components, with connections defined in XML and bound together through templates. It’s a dumb, POD Diver structure. Diver as in the guy going swimming underwater. This prototype had fish as well, and there was a Fish structure, and a large array of sequential, homogeneous Fish data. The main loop wasn’t generic at all either: It was a sequence of UpdateDivers(), UpdateFish(), etc. Rendering was done in the same, explicit way, making it extra simple to minimize render calls and state changes. When you work with a system like this, you never, ever want to go back to a generic one where you have very little idea about the order in which things get updated or rendered.

Beyond The Sample

To be fair, this sample code is very, very simple. The update function for a reasonable game element is probably larger than a few lines of code and will need to do a significant amount of work (check path nodes, cast rays, respond to collisions, etc). In that case, if it makes sense, the data contained in the structure can be split up. Or maybe the first update function generates some different output data that gets fed into later functions. For example, we can update all the different game entities, and as an output, get a list of ray cast operations they want to perform, do them all in a later step, and then feed the results back to the entities either later this frame or next frame if we don’t mind the added latency.

There’s also the question of code reuse. It’s very easy to reuse some low level functions, but what happens when you want to apply the same operation to a Diver and to a Fish? Since they’re not using inheritance, you can’t use polymorphism. I’ll cover that in a later blog post, but the quick preview is that you extract any common data that both structs have and work on that data in a homogeneous way.

 

What do you think of this approach? In which ways do you think it falls short, and in which ways do you like it better than your current style?

30 Comments

  1. There are so many other related topics to a post like this that we could turn the comments into an entire set of posts, so I’ll be a little brief here and save the Big Stuff for future blog posts.

    I completely agree that code styles (should?) evolve over time as you come across better ways of doing things. I really don’t understand why developers cling so tightly to their styles as if they can never be changed. If there’s a better way to do something, why not adapt and fold it into how you do things going forward? Perhaps the fear of change is so great that developers think it will be a big time hit in the short-term. I find this not to be the case because the change are so small, you almost don’t notice them. Sure, there’s a little time needed to get used to the new way, but the long-term gains far outweigh the time spent now.

    Conversely, one of traps you can fall into once you do adopt something new is that it’s *really* hard to resist the urge to go back and change ALL the code you ever wrote (or at least recent projects). 🙂

    What I love about your style (and something I will definitely start doing on new projects) is the use of namespaces and encapsulation.

    Where I think it falls short, but it might be because it’s only an example, you didn’t mention it so I probably should, is that there’s no documentation. I’m not a fan of having comments just for the sake of comments, so I’m not suggesting that, I’m referring to reminders in-a-way on how to use the module. The need for you might be much less than others since it’s just you coding, but I would think a reminder would be handy to have later for maintenance when you need to add a feature/fix bugs/whatever.

    Thanks again for the superb post.

  2. Just to be pedantic, your DiverState struct is not a POD type. It has a constructor (and so, technically speaking, treating it as a plain series of bytes to be read and written with fread/fwrite or memcpy is undefined behavior — of course, in the real world, it’ll most likely work, but it’s not technically a POD and so you can’t technically do POD-like things to it).

    One thing I’m curious about is how you handle memory management (or resource management in general). Manually pairing new/delete, malloc/free, fopen/fclose, or with smart pointers and RAII objects using destructors to clean up?

    Anyway, it looks nice and clean. My code tend to be more, well, templated and generic, but on the whole, it’s not miles apart from yours. I’d feel much more at home in code like this than I would in the heavily OOP’ified mess you see so often.

    I have one other question though.
    I seem to remember (from your blog and/or twitter that when you started doing iPhone development) that you just couldn’t get over how awesome Objective C was, and used it *everywhere* for everything. Now your code is C and C++, with “a bit of” Obj-C. What happened?

    Or was it always that way, and I’m just imagining things?

  3. Have you noticed if your current style really became prominent before or after going indie? I’m wondering, if it did develop before going indie, how well did it scale architecturally in larger projects with multiple developers working on the codebase?

  4. @Bob,

    Thanks! I agree that going in major refactoring crusades to retrofit your style/architecture is a big danger. I’ve learned to leave things alone and just make things better as I write them or change them. That means sometimes I’ll have 2-3 different styles going on at once in the same codebase. Big deal. Seriously, as programmers that’s an itch we want to scratch, but it adds zero to the final product.

    Comments: There ain’t none, baby! I deal with it in two different ways: name functions accurately (and keep them small), and write unit tests during TDD. I’ll usually end up having a one-line comment every 5-10 files, usually with the URL of a place I got an algorithm, or explaining why I did something the way I did.

    @jalf,

    True, it’s not a true POD. The undocumented assumption is that the constructor is just initializing variables to default values for convenience. I do just fread whole chunks of memory and cast them to a GameState structure and I’m ready to go.

    For the most part, I don’t do memory management. Or rather, I do, but it’s statically allocated. Wow, that reminds me I need to post the column I wrote for GDMag on that topic. Maybe tomorrow. But the answer is that I preallocate arrays of structures like those along with a count of how many there are. When one of them is “destroyed”, I just copy the last one on its place and decrease the count. That way they’re always sequentially laid out in memory (at the expense of some wasted memory, but that’s pretty minimal in the grand scheme of things).

    I still think ObjC is awesome (compared to C#), mostly because of its great interop with C/C++. But on the whole it removes me from the hardware and the memory layout and it doesn’t offer significant advantages to switch to it for everything. I’m happy to use it for UIKit, but I’m keeping the rest of my code in C.

  5. @Jedd,

    Yes, my coding style has definitely changed since going indie three and a half years ago. Realizing that everybody who could possibly change that code is just as smart/experienced as you and is in the same room as you makes a huge difference. Also, not having a truckload of designers and content creators needing to data-drive everything also makes a huge difference in the architecture and simplicity of the code.

    Frankly, sometimes I feel like what I’m writing is closer to the Basic programs I used to write growing up than some of the code I’ve had to write for big companies. And I’m having as much fun as I did 25 years ago!

  6. My code style has also evolved a lot in the last 2-3 years. I write the enums like you, in a proper namespace (well, until C++0x class enums come along :).

    I’ll have to try your way of writing the functions to manipulate the data, instead of storing it all in a class which can quickly turn into a mess.

  7. Noel, your style surely has changed a lot during the years, comparing to GPG samples for example (like timer, with OO/inheritance/virtuals). Is it mostly related to the fact you work on different kind of projects now? Would you still use it in a bigger project when working in a big team?

  8. Funny you mention that the first thing jumping out is the struct! I bet most old school C/C++ guys would be looking at the enum wrapped in a namespace.

    I used to code (when still using hungarian):

    enum ESomeEnum
    {
    ESomeEnum_SomeValue
    };

    But it was only until I started using C# for tools that I found how nice and clean having SomeEnum.SomeValue is just so much clearer.

    And this let me also to the convention that all enums written today would be:

    namespace SomeEnum
    {
    enum Enum
    {
    SomeValue
    };
    }

    Using SomeEnum::SomeValue is just so much nicer and guarenteed* to be conflict free. And if you have to pass or store the enum (not in an int) using SomeEnum::Enum says what it does on the tin.

    These days I am really trying not to re-write my older code just because my coding style changed. I have also been in that trap where I rewrite an entire engine (unfinished one), get distracted with life and other stuff, come back to the unfinished project and see just how out of date the coding style is to my current one…and thus start repeating the refactor just for coding style loop.

    If you guys haven’t watched “Session 138 – API Design for Cocoa and Cocoa Touch” from WWDC 2010, I highly recommend you do. I am starting to adopt some of the Apple coding style (after initially looking at it and thinking, my word it is ugly!, funny how perceptions change).

  9. @Nero, Yes! No kidding. That code (from 2001?) is a perfect exampe of how radically my style has changed. At my worst phase, I even had a brief affair with Boost and smart pointers. I apologize to anyone affected by that :-b

    To be fair, I would probably change my style a bit on a large team (unless everybody was familiar with this style already). But I wouldn’t go very far from it though. And frankly, if high performance is a major goal, you pretty much have to do something like this for modern platforms to make good use of memory access and multiple processors.

  10. I also agree that writing your model (data driven) in such a way to make it easy to
    save or load an entire state to disk by just simply fread/fwrite the entire memory contents is so much quicker.

    When I was working on Burnout Paradise all our data (not art etc.) was written
    in this manner. Our structures could even include pointers that would be saved
    relatively to things being pointed to and then restored on load.

  11. @Andre

    rewriting code is a bad idea. there could be to many bugs introduced

    @Noel
    The struct idea…is nice ..I liked to do this OO technique in C

    http://www.bolthole.com/OO-C-programming.html

    As Noel already mentioned..you update method in a gme will more likley look like

    UpdateFish();
    UpdateBoats();
    UpdateSky();

    instead of

    Update(ObjectList *);

    where you go thru a object list…for that meta class Object .

    you definitely has more to write..and read….but I agree….you know what’s going on!

    Hey, a blog article without downloads: Where’s the source code 🙂

  12. Comming from a past in big game studios, which it sounds like you also do, my one reservation would be the data saved to disk. In all my experience, there ends up being tons of data saved and it is impractical to either a) offline convert all the data to a new in-memory layout or b) save a version number in the file and maintain the code that can load old versions when they are encountered.

    My current solution to the problem is to save data to disk in a typeless or mostly typeless format (bencode, as used for .torrent files, as an example) and a runtime mapping from named data items to the struct members. In that way, the only versioning to maintain is lists of old data names and what new member they map to, if any.

    On a mostly aesthetic basis, I also go the opposite way on comments. In my way of thinking, it’s almost always possible to find an aspect of any line of code that is not explicit in the code itself, and that is therefore beneficial to add a comment with that information. My code can has two narratives when read: the comments tell the what and why of what’s happening, and the code tells the how of it. In the end, I don’t all that often need the comments to figure out a piece of code later, but it happens often enough that way that I feel it is worth it.

  13. @AdamH, You’re totally right about the pain of converting the binary format straight into a new binary format. Normally the way I deal with that is to have something else that externally generates the latest binary format (from level files, or XML layouts, or procedurally, or whatever). But the runtime *only* loads the binary format, which keeps things much simpler (and faster!)

    Sometimes you have to maintain binary formats though (I will in my current project), so I’ll just bite the bullet and add an upgrade path. Before that, I’ll add enough padding that I can add new data without having to change anything though 🙂

    As for being lots of data saved, I haven’t found that to be too much of a problem. Yes, it bigger than it could be, but disk space is plentiful and it makes things simpler and faster.

    I hear you on the comments, but the eternal problem is that comments and code will get out of sync. Using unit tests as documentation ensures that never, ever happens.

  14. Could you elaborate on this:
    “I’m making it clear that it’s free of pointers and temporary variables.”

  15. My code is now of a similar style, but I still tend to slip back into putting far too many functions as members. Herb Sutter (referencing the Meyers’ article you linked to) gives the example of reducing std::string down to something much simpler with lots of non-member non-friend functions in his Exceptional C++ books (and presumably on his gotwa site, though I haven’t checked).

    I’m especially a big fan of the Enum technique as mentioned above by you and @Andre; the code base I work on is huge (C++ financial analytics), and it just makes reading it and understanding it considerably easier.

    My problem, though, is that I’m not great at thinking up names for classes and namespaces, so I tend to end up with lots of ‘Widget.h’ and ‘WidgetHelper.h’ and ‘WidgetUtils.h’ files/namespaces which just annoys me for reasons I can’t quite put my finger on. Presumably some kind of ‘code smell’.

    On a slightly and tenuously related note, the Gendarme, and FxCop utils for .NET code pick out functions that can be made static non-members (just look for anything that isn’t this./this->/Me.). And String.IsNullOrEmpty isn’t generic, but it is a static non-member, so even large class libraries follow similar styles.

    Finally, I’m gradually drifting towards following, as needed, the various principles described here: http://www.butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod

  16. @Arelius, By keeping all the data visible on a struct, you know there’s nothing hidden that can’t be serialized (pointers are the biggest culprits). Also, by naming it a struct, and not just a class with all public members, I’m really emphasizing that it’s POD (except for the constructor like a few people pointed out).

    I’ll try to put up a reprint of one of my Game Developer Magazine columns later today about data references and what alternatives there are to pointers.

  17. Hi,I’m mostly a one-man team of programmers at the moment and have found that such a liberating [and scary at times] experience. I’ve also sort of discovered this particular habit of mine which I basically break objects into data [properties/attributes] and interfaces [functions working on the data], although I usually still prefer to embed the struct inside a complete object which inherits from the interface. My rule of thumb, after reading Meyers amazingly awesome ‘Effective C++’ is that if a function needs to work internally it belongs in the class [object] and if not, out it goes to the namespace scope, I usually end up with very small objects…
    As for enums, the problem I find with using namespaces is that they cannot be closed completely [meaning anyone, anywhere, can add stuff to them] which is why I stick the enum into a struct and make the ctor/dtor/copy private and unimplemented.
    Other than that I’m wondering if template metaprogramming can also somehow have some benefits with helping to describe data/function interactions…?

  18. I’m not sure how this is different than exposing the class declaration. in fact an advantage(problem) with structs is that it is easier to hide the entire struct decl completely in a private cpp.

  19. Technically a struct is pretty much the same as a class with everything public. I’m just using it to reinforce the idea that it’s just POD. And I’m certainly not trying to hide anything. Exactly the opposite: I’m putting the data out there so there’s nothing hidden.

  20. I was just wondering how you handle private methods?
    If a particular public interface for your POD is complicated enough that breaking it into ideologically smaller functions seems reasonable, then how do you keep those smaller functions out of the public scope?
    I would think of just defining them private within the class, but that completely breaks the idea you’re using here. Maybe making a nested “::private” namespace that you hope nobody uses?

  21. @Aaron, Good question. All data is public, but I do have some “private” methods. They’re mostly smaller, convenience functions that I use internally to avoid one mega-function. What I do is declare them in the cpp file inside an anonymous namespace. So nothing there is exposed to the outside, but it’s avaialble to the code in the cpp file. Works great.

  22. Hey Noel,

    The link for test driven development is going to your office tools for starving startups.

    Cheers!

    Jeff

  23. do you define any particular interfaces using classes, or are all functions non-member namespace-bound functions which accept the State [property] struct they are related to?

  24. Thanks for the heads up, Jeff. I just fixed the link.

    @Amir, I don’t have any interfaces using classes anymore. There’s no need if you have no polymorphism. All my functions are non-member functions, usually in a namespace. Sometimes they’re associated with a struct, and sometimes they operate on multiple bits of data so they aren’t strongly tied to a particular struct.

  25. Again, thank you for this, definitely inspired some code changes. And more important gave me yet another perspective on looking at the Code/Data dichotomy.
    The only thing here with structs that I would provide as well would be a copy constructor and assignment operator, but that’s only because I don’t like having the compiler creating functions for me…

  26. “How Non Member Functions Improve Encapsulation” – this one has completely changed my coding style as well 🙂 I finally has found the support for this coding style in your post, big thanks for that!

  27. @Barry, I also used to have irritating FooHelper, FooUtils static classes which always ended up having lots of pretty heterogeneous stuff. I think static classes simply don’t scale well for storing helper stuff. The best solution IMHO is to split static god like helper classes into specific modules with free functions sharing the same namespace.

    For example, in one project there was NavigationHelper which had routines for working with grid along with routines performing search queries. Splitting it into find_utils.h and grid_utils.h(and a couple of some other) modules and converting all static methods into free functions sharing “navi” namespace greatly simplified the maintenance burden.

  28. Noel,

    I actually really like this style of yours, unusual as it may be. It’s not far off from my own, though a lot of my functions are still member functions.

    One thing I’m curious about though, in regards to using this style with TDD: how do you create mock objects? With all of your functions external to the struct, I don’t see how you can create the appropriate virtual interfaces. Virtual functions also feel contrary to the open, clean style you have, but I don’t know another way of implementing them.

    Caleb

  29. Hi Noel;

    I like your style. Mostly because it is so similar to mine. Lol. In my T.A.N.K. Arena Battle iPhone game (and the free T.A.N.K. LITE), I use simple structure declarations; without any functions. Functions are pretty much private, inside c or m files, not exposed in h files, not members of any object. All of my data is in one of two types of static arrays of structs: 1) “read only definition prototypes” and 2) “pool of instances”. Definitions are kept in source files, created by off-line tools and linked in. Pool is just a static array (full of garbage until it is needed).

    The weapon system is a good example of this. There are no classes or objects for that. Just 1) a set of bullet definition structs, and 2) an array of un-initialized instance bullet structs. When trigger is fired, a) I have the speed, lifespan, damage-amount, mesh-id and trail-effect-id values in the definition structure, b) “activate” an instance in the pool (set a flag in the array element), and c) save the definition id in this active instance, set the initial position and direction, and spawn an effect. On each time-tick BulletUpdateCollision(bulletPool, obstaclePool, tankPool) looks at each active instance and determines if something was hit. Second function BulletUpdateLocation(bulletPool) updates position and orientation of each of the remaining instances. Third function BulletDraw(bulletPool) draws them. Same for TANKS, GUNS, PARTICLES, OBSTACLES, SOUNDS, etc. (note that each such category has an h and m file, e.g. ParticleManager.h and m, but more on Managers later, maybe).

    Note that since everything is in static memory, the game never does any alloc/dealloc or any such nonsense. You know exact memory footprint before the game even loads. No memory leaks, no zombies, no stale pointers, and no constructor/destructor code since it would be extra useless code. The whole game, code, meshes, definition, etc fit into 1.2MB (ok, I lied, textures use 2MB and sounds 0.25MB and are allocated at load time, and music is streamed, but nothing else). And it is lean and mean and pretty fast. And yes, it is Data Driven design (I think).

    George

Comments are closed.

Webmentions

  • Games from Within | Remote Game Editing July 21, 2010

    […] implementation of the system I’m using was written 3-4 years ago. As you all know by now, my coding style and programming philosophy changes quite a bit over time. If I were to implement a system like this today, I would do it quite […]

  • Games from Within | Managing Data Relationships July 21, 2010

    […] columns I wrote for Game Developer Magazine, but I wasn’t finding the time. With all the recent discussion on data-oriented design, I figured it was time to dust some of them […]