Gamasutra: The Art & Business of Making Gamesspacer
Sins of Game Programming #2 – Code Obfuscation
Printer-Friendly VersionPrinter-Friendly Version
View All     RSS
April 24, 2014
arrowPress Releases
April 24, 2014
PR Newswire
View All
View All     Submit Event





If you enjoy reading this site, you might also want to check out these UBM TechWeb sites:


 
Sins of Game Programming #2 – Code Obfuscation
by Michael Carr-Robb-John on 01/01/11 09:54:00 pm   Expert Blogs   Featured Blogs

The following blog post, unless otherwise noted, was written by a member of Gamasutra’s community.
The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.

 

One of my flaws for those that don’t know me is that I simply don’t remember everything. My brain it would appear is completely incapable of storing all the facts and information I ask it to. Over the years I have used different methods to help me remember, all with varying degrees of success.  My current system is to write everything down, I carry a black leather writing notebook with me and I take lots of notes. I use a P.D.A. for some things like contacts and mind maps but when it comes to making lists and notes, paper and pen have yet to be beaten.

One of the effects of this forgetfulness is that I couldn’t tell you the intimate details of a function I had written two weeks ago, let alone six months or a year ago without at least re-reading it and refreshing my memory. It is because of this that I consider obfuscated code a sin. This also fits nicely with working in a team of programmers where someone might have to debug and/or add new functionality to someone else’s code. The quicker it is to understand the easier it is for them to make the required modifications.

 

Descriptive names

Badly named variables and functions don’t help anyone. These examples I found in code that had shipped.

    int            m_MyMumIsBetterThanYours;

No it wasn’t a game about Mum’s… although I wander if there is a game there somewhere… hmmm... 

    bool           m_BumCheeks;

Enough said.

    float          m_Saving;

Is this a flag to indicate saving, in which case why a float? Or is it a percentage of save completed?

    void         * m_pAudioSample;

Not very useful, a much better way of doing this would be:

   SAudioSample  * m_pTheWarCry;

 

   int CCharacter::GetLife( int y )

Nothing wrong with this function… except why is there a variable passed in, and more importantly ‘y’ isn’t exactly very descriptive. Turns out this function did indeed get the amount of life and return it, while it was there it also updated the life value by applying the damage modifier to the life counter and also applied the adjustment of ‘y’. When this function wasn’t called every tick the whole life counter on the character broke!

 

Abusing ternary operations

Consider the following code remember that this would normally be on a single line so you would have to scroll to see the entire line.

   if (CPhysicsManager::Instance().RayCast(m_Position + (CVector::Up * METRES(2.0f)), m_Position – (CVector::Up * METRES(2.0f)), &contact_data, pActor->GetPhysicsActor() ? pActor->FindRealActor()->GetPhysicsActor() : NULL, ePhysicsShape_Static))

Would you have spotted the use of ‘?’ and ‘:’ inside the function parameter list?

Some coding standards I have worked with ban the use of ‘?’ and ‘:’ altogether mainly because it is easy to abuse and doesn’t take much to write code more nasty and tangled than the example above, however there are cases where I consider them to be fair enough and that is usually when the use is obvious. For example:

   m_Level = level_specified ? start_level  : default_level;

   result = a > b ? b : a;

 

English

There was a time when the length of our variable or function name would have a significant effect on the performance of the compiler. This however has not been the case for a very long time but some engineers seem to like using shorthand.

    int NmbrChars( );

vs.

   int GetNumberOfCharacters( void );

 

   int m_LCnt;

vs.

   int m_LifeCount;

English is my first spoken and written language I find it easier to read code that says what it is in English.

There are actually a few more items and examples under the heading of code obfuscation but this blog entry is long enough.


Related Jobs

Turbine Inc.
Turbine Inc. — Needham, Massachusetts, United States
[04.23.14]

Director, Analytics Platform Development
Gameloft Toronto
Gameloft Toronto — Toronto, Ontario, Canada
[04.23.14]

Technical Artist
Muti Labs
Muti Labs — Santa Monica, California, United States
[04.23.14]

Senior Game Engineer
Digital Extremes
Digital Extremes — London, Ontario, Canada
[04.23.14]

Programmers






Comments


Megan Fox
profile image
Absolutely, completely agreed. Even ignoring the memory consideration, you need to write sane code simply so that your coworkers can understand it, or so that whoever eventually inherits your system won't wish to find you and kill you in your sleep. Ditto for taking the time to write comments that make sense.



... and you think your code is purely for yourself? That it will never see the light of day? Not a good bet. On two separate occasions in the last year alone, I've dusted off 4+ year old hobby code for production use, and once my "hobby" engine actually got inherited as the production engine.

John Purdy
profile image
I just love how you called a bool m_BumCheeks. That's pretty awesome, and I do the same thing if no one else sees the code

Salman Jafferjee
profile image
Forget obfuscated code, unless I comment my own unobfuscated code I wont know why I wrote a particular loop or variable. I find that being clever is more of a headache in the long run.

Alan Copeland
profile image
While I agree with the content, I was initially misled by the title. Obfuscation really means something else in the professional software world:



Wikipedia -

"Obfuscated code is source or machine code that has been made difficult to understand for humans. Programmers may deliberately obfuscate code to conceal its purpose (security through obscurity) or its logic to prevent tampering, deter reverse engineering, or as a puzzle or recreational challenge for someone reading the source code. Programs known as obfuscators transform readable code into obfuscated code using various techniques. Code obfuscation is different in essence from hardware obfuscation, where description and/or structure of a circuit is modified to hide its functionality." - http://en.wikipedia.org/wiki/Obfuscated_code

Michael Carr-Robb-John
profile image
My dry sense of wit might be showing a little, I think the title was spot on. ;)

Andre Mukudai
profile image
I think your mention "or as a puzzle or recreational challenge for someone reading the source code." says exactly the same thing Michael said. No?

Andrew Grapsas
profile image
I agree with Alan, I wasn't certain what the content of this blog post would be about :) Interesting how the content somewhat matches the title!



Love the post, though. I couldn't agree more. I've encountered confusing naming in every codebase I've ever worked in. All too often, a team's standards will be ignored by one or two programmers, causing the codebase to be split in style and often confusing.



Having standard naming conventions and a "clarity first" mentality really, really helps!



Also, reviewing legacy code as conventions change is very, very useful.



...Working with programmers that barely speak English has been one of the most confusing coding challenges. Variable names tend to make little sense, be misspelled, and coding style is non-existent.

Michael Carr-Robb-John
profile image
Hi Andrew,



Deciphering Japanese technical manuals and doing localisation programming is about the limit of my encounters with other languages while programming.



I've worked with programmers from non-English speaking countries in the past but they have all had a good grasp of English and certainly wrote outstanding code (comments in English with better grammar than I), they also possessed good communication skills. Just out of curiosity how did the project go? Was the communication barrier an issue, how did technical discussions and planning happen?

Simon Ludgate
profile image
You must not be a fan of TinyMUSH code, but it's fun to write stuff like



&cmd-where-group me=$+where/group:@pemit me=+Where/group list:[iter(iter(sort(iter(lwho(),switch(loc(##),#-1,,[loc(##)]/[name(##)]))),[switch(first(%q 0,/),first(##,/),[%q1] [last(%q0,/)] [last(##,/)],[setq(1,first(##,/))][!])][setq(0,##)]),switch(gt(strlen(##),5),1,%r[name(first( ##))]: [rest(setunion(##,))]),!)]



and expect to get a valid use out of it :P

Michael Carr-Robb-John
profile image
I see the intellectual challenge, but it certainly isn't my cup of tea. ;)

Manoj Sahu
profile image
Oh wait, its more difficult to understand, i will rather prefer to write whole game once again. ;)

Kassim Adewale
profile image
These illustrate one of the many points that cryptographic inline game codes tend to collide with normal code during a game development, where DRM is being used.



DRM code alone is hell, not to talk of a normal game code that looks like protection.



In a team-work game development, I may innocently translate "int NmbrChars( );" as a hash function that convert number to char for some array shifting routine and return rotated number, but "int GetNumberOfCharacters( void );" is 100% straightforward.



Just because of code clarity, I hardly use the ternary operator.



You wonder what goes on in the mind of the programmer that inordinately code:



int m_MyMumIsBetterThanYours;



May be one of those programmers that eat while coding.

Owain abArawn
profile image
What, are game coders assessed a fine for each comment line written, or something?



Descriptive comments are far more effective at documenting the purpose of a line of code, a variable, or a procedure/function than verbose naming conventions. The more complex the line of code, the greater the need for a descriptive comment. Personally, I find that long and involved variable/function names tend to obscure the underlying logic of a piece of code more than they provide clarification.



If you explain what you are doing in English (or the language of choice) in the comments, and make ample use of white space and indentation to clarify your logic, you will be far better off than defining



int YetAnotherLongWindedFunctionName (int withUnnecessarilyVerboseParametersAsWell);

Ernest Huntley
profile image
I actually worked with a group where comments were essentially not allowed. The lead engineer believed that they just caused "code clutter" and, instead, insisted that we "use the source control system" in order to understand changes and additions... fail

Corey Holcomb-Hockin
profile image
Code Complete is a good book on this sort of thing. Its been a while since I read it so I'm pretty rusty.

Michael Carr-Robb-John
profile image
Agreed, "Writing Solid Code" by Steve Maguire is also highly recommended.

Michael Compton
profile image
Something that might yield benefits is to take a leaf out the functional programming camp, your example of regarding int CCharacter::GetLife( int y ) is a prime example of how abuse of imperative programming can make it impossible to adequately predict the behaviour of a given program.



Functions should really become like little black boxes that have known behaviour and can be depended upon to do what they say on the 'tin'.



I'm not saying you should suddenly jump into Haskell, certainly not my cup of tea anyway, but there is a lot to be learned from the style, referential transparency is a big win for predictability and maintainability and code reuse.



Test Driven Design might also all you to produce more reusable components, but this maybe a lot more open for debate.

Robert Basler
profile image
This is actually feedback on the "Programming Sins" article you penned in Game Developer magazine. While I enjoyed the article, your section on "Not Failing Gracefully" is just wrong. Defensive programming is a terrible idea. And I know where you are coming from, because that's what I was taught 20+ years ago in school.



That said, I'm with the sound library author, games should crash. Early and hard. If a game crashes, then QA puts in a bug on it and the bug gets fixed. Before the game ships.



Ideally there are asserts when running a debug build to give the programmer some info on why it crashed, but the crash is needed to bring attention to the bug.



Crashes are also great for the programmer because if the game crashes for the programmer adding a new feature or modifying something that works, that tells them that there is a bug in what they are doing.



Validating pointers just adds code paths that will be rarely used, and likely never tested. It makes your executable bigger, slower, and that untested code adds even more bugs.



Validating data, clipping them to valid ranges then soldiering on is a horrible idea. You are hiding bugs rather than being forced to fix them. You're taking garbage in and generating garbage out deliberately. Bugs should be fixed not hidden. If your input data is not what you expected, then either fix the data or fix your program to handle the input and provide correct outputs.



For programmers, heavy use of ASSERT to validate preconditions for functions (such as your NULL pointers and out of range inputs) is very helpful for debugging, but these tests should never make it into an end-user's hands.



Now when it comes to anything the USER might input, then absolutely you should validate their input, but for anything that you control, you should have QA find the bug and fix it before you ship your game.



I even wrote a short post on this here: http://www.onemanmmo.com/index.php?cmd=newsitem&comment=news.1.21
.0


none
 
Comment: