About reusable code, a decade later

The past

I’ve been working as a programmer for over a decade now, most of that time I’ve spent in the games industry. And starting as a junior programmer in 1999 at neo software (which would later become Rockstar Vienna) I’ve always met fellow programmers preaching that code should always be written with reusability in mind.

The astonishing thing though was, that very often teams would throw away their whole old codebase and restart from scratch, because the next engine will be “the” one, where all old mistakes will be corrected. Apart from engines intended to be used as middleware (Renderware, Havok, Unreal etc.) I’ve seen only little reuse of game code in my professional life.

Now, while I am working mostly on my own, I’ve revisited the question of what really defines reusable code for me in my current situation as a solo developer. And the conclusion is quite different to what my vision of reusability was when I started my first baby steps in C++ in the last millenium.

In the past I tried to build systems. I had started an engine in my pre-parent spare time (the infamous chengine) back then, as a learning experience. In my opinion it was actually quite a good first shoot at well designed code. I did things like this (among others):

  • typedef a lot of standard types like Float, Int32, etc.
  • have lots of template code to keep things generic (Vectors, Matrices for all dimensions, going as far as doing expression templates because they were “da cool thing to do, man”)
  • encapsulate everything neatly, so I’d only deal with Meshes which would again use all my nice custom types

If I’d reuse my old engine, then it still compiles and works fine. I’d do many things differently now, but still by definition it would be reusable.

The present

Fast forward to present day. I’m now in the process of building tech for my iOS projects and I decided not to use my old engine, because the next engine will be “the one”, where all old mistakes will be corrected. …. STOP!

I was kidding, that’s not what I am doing. I’m not even writing an engine/system/library anymore, I’m making projects. But still I try to make my new code reusable or as I prefer to call it interoperable. Some will ask: “What does this crazy man mean by interoperable?!?”

One example: For “Pocket Nature” I need a particle system. I had a particle system in chengine, but it was so integrated that I would have had to deal with my templated Vectors, scene nodes and god knows what. I went with Spark instead.

Another example which I’ve already mentioned here: I had a perfectly working wavefront .obj importer in chengine. But again it wasn’t usable standalone, it was part of the whole system, deriving from MeshImporter returning a mesh, etc. Again, I went with 3rd party code instead.

So, … reusability to me has a different meaning now. It means

  • Write code that can easily interface with any external library
  • I solely use built in types like float, int, etc. (because in 99% of cases the libraries will typdef Real, Float, GLfloat to float anyway).
  • Functions should be able to take Classes, types from external code easily.
    • Simple example: write code for getting a Vector3 length as float vector3Length(float*) because no matter what, nearly all CVector3, Vector3 types will be castable to a float*
    • For geometry I try to be as generic as possible, vertices, uvs, normals, tangents, etc. all accessible as simple arrays. For rendering I can then store in VBOs etc. but I’ll for now always keep simple PODs around.
  • Use standard C when possible. No more own cosf, sqrtf wrappers
  • Use C instead of C++ when possible (easier to interface with C++ and ObjC). Also C code has less tendency to “grow into a system” by accident.
  • No templates – yes, NO templates. Why? Because compiling standard C/C++ code from 3rd party libs is most of the time painless. Templates on the other hand often result in nice hieroglyphic renditions of “War and Peace”
  • Make code usable standalone. Ideally everything should be usable without dependencies on other code. E.g. for collision/intersection, I would like to have Intersection.h/Intersection.c which don’t depend on anything else. Ideally not even Vector3 or planes. Functions would look like IntersectionType intersectPlaneRay(float* normal, float offset, float* point, float* dir). You get the idea.

In short: I try to write code that can easily interface with the outside code-universe. My prime example for interoperable code is OpenGL which obviously interfaces with many 3D engines. All parts should depend as little on the rest as possible (think of Code-Lego), so I can throw away parts when I get smarter (or wiser) in the future without having to kill the whole system again. For now I’ve even duplicated small helpers or #defines if I want to reduce dependencies (need SQRT_TWO in a function implementation, then redefine as static in the .c file instead of pulling in something like math_defines.h).

Did it work out so far? I don’t know yet. I am in the process of implementing it while I do my projects. I haven’t even done all the points I’ve mentioned above. Currently my Pocket Nature code is a mixed mess of chengine code, 3rd party libs and tutorial code from Apple. It’s a clean mess, but a mess nevertheless. But I intend to more and more switch my code to the described model.

Is this the ideal approach? Hell, no. It is what I am trying out now because I think as a solo dev who depends on trying out many libraries (I’m definitely not a “not invented here” guy) this is necessary. I have to use whatever libs I can find to save some time, so I can draw art, tweak sound effects, make trailers, do some web design, cook meals for my family, watch my son’s martial arts performance etc.

In the end I think that’s also the design principle behind many long running successful libraries like OpenGL, zlib, tinyXML, … You can plug them in without pulling in a huge system. The goal I want to achieve is that if I’ll work on a project in the future within a completely different code base and need e.g. a .3ds importer and sphere/plane collision that I can pull in two header and C files without anything else.

(If any tech director reads this, who might interview me in the future after my failed iOS-millionaire experiment: Obviously this whole post is only a joke, I’ll promise to behave and write nice code that fits into your company’s engine.:))

I hope, what I’ve written makes sense to some of you. Make sure to tune in 10 years later when I’ll post “Interoperable code, the most stupid idea, I’ve ever had.”

Share this:
  • Stefan Reinalter

    Two notable examples of interoperable code:

    Doug Lea’s dlmalloc: ftp://g.oswego.edu/pub/misc/malloc.c
    Sean Barrett’s stuff (stb_image, stb_vorbis, stb_truetype): http://nothings.org/

    I like the approach. You just take a single .c/.h file, and that’s it.

    • GottfriedChen

      Nice! Thanks for the links, especially Sean Barret’s stuff will definitely come in handy one day.

      • Stefan Reinalter

        You’re welcome!

        I use dlmalloc in the Molecule Engine, and have heard nothing but good things about stb_image.

  • Pod

    404 on the “write games not engines” link