Developer experiences from the trenches

Developer experiences from the trenches

Start of a new post

Good Code Doesn’t Tolerate Bad Data

Mon 07 April 2014 by Michael Labbe
tags code 

When something is not right in your game’s simulation, complaining loudly to the developer-culprit as early as possible roots out issues. Production code that tolerates failure at a data processing level while producing a completely errant play experience saves no time.

If a developer commits errant content and time goes by, the cost of fixing it goes up. The developer may have forgotten the intricacies of their contribution, or worse, be on a different project. The content may need to be regenerated from source files in a manner that is either unclear or is not available to the person who deals with the bug. The symptoms of the bug may be disconnected from the problem. For example, I have seen a non-normative bitrate in an audio file corrupt a stack, becoming a time consuming issue to track down.

When you realize a subtle warning was added to a programmer-facing debug log that stated the issue, but was ignored by the developer who added the file, it is time to look for better solutions.

Throwing assert messages when an invalid programmatic state is hit is a common practice for trapping code logic errors. Extending this diagnostic trip-up to content issues for non-programmers is a useful tool for getting in developers faces at the right moment in time — when the developer is trying out their new content for the first time.

What can a content alert do for you?

  1. Provide validation that content is consistent with the engine’s expectations. For example, if a PNG has a corrupt header, there is nothing wrong with the PNG loader logic. It’s just dealing with questionable data. Sure, it could probably display something if the rest of the file is structured properly, but this is indicative of a bad file and you need to get this up in developer faces before they move on to other challenges.

  2. Test code that runs as soon as possible. If you have a cooking stage that runs over your content, throw your alerts then. If you do not, do it at level load. Validate everything.

  3. A way of passing a diagnostic message on to the content creator as soon as possible. Short circuit the QA/bug tracker loop for content creators (level designers, artists, audio engineers). This saves time by providing the opportunity for a specific diagnostic message that gets to the root of the issue. Bug reports from QA describe the symptom of the issue and usually lack direct diagnostic messages. This is much quicker.

Real-World Content Asserts

Resource r = LoadResource();
if ( r.GetBPP() != 32 )
    ContentFail( "Resource has invalid bitdepth" );

ContentFail is a preprocessor macro which, in developer-friendly builds, accumulates a descriptive list of issues for the content creator.

How to implement ContentFail in C

You know which builds are going to developers and which are going to the end user. Use conditional compilation to optionally throw a message up in front of the user.

#if ENABLE_CONTENT_DIAGNOSTICS
#define ContentFail(msg) (void)(HandleContentFail( __FILE__, __LINE__, msg ) )
#else
#define ContentFail(msg) ((void)0)
#endif


void HandleContentFail(
     const char *file,
     int line,
     const char *failmsg )
{
    /* Append failmsg to diagnostic list here */
}

In this implementation, ENABLE_CONTENT_DIAGNOSTICS is on for all builds going to developers and, presumably, off for ship. You accumulate a list of issues and push them to a dialog box after a level load, treat them as compile warnings in a build process or purposely sound an alarm in the cook process.

One benefit of compiling out the content asserts in release builds is avoiding the fear that you are adding a ton of diagnostic strings to shipping code. Go nuts here — be as descriptive and as helpful as possible.

None of this is particularly fancy, complicated or tricky to implement in any language. It amounts to adopting a philosophy of enforcing correctness as early as possible in the design of your tools.

Edit: thanks to @datgame for pointing out a bug in the example code. It has been fixed!

More posts by Michael Labbe

rss
We built Frogtoss Labs for creative developers and gamers. We give back to the community by sharing designs, code and tools, while telling the story about ongoing independent game development at Frogtoss.