GameMonkey Script

GameMonkey Script Forums
It is currently Mon Oct 15, 2018 11:39 am

All times are UTC




Post new topic Reply to topic  [ 4 posts ] 
Author Message
PostPosted: Tue Apr 22, 2008 3:35 am 
Offline

Joined: Mon Dec 15, 2003 1:38 pm
Posts: 707
I thought I'd write a few thoughts on coding standards and practices.

1) Make a habit of using rules, but break the rules when they decrease value.

Coding standards are important. They allow multiple programmers to collaborate on a since project and work with each others code in an efficient and conflict reduced manner. I believe that coding standards should be minimal and that each rule should add significant value. The benefit must significantly outweigh the cost, otherwise the value will not be appreciated, or the people using it will lose morale. This follows through to API design, but that's another story. The basic idea is to make coding so simple and painless it becomes almost fun.

If you tell staff, use asserts and logging as much as possible, don't expect them to do so if you have an API that looks like:

INITIALIZE_LOG(current_file); // At top of every .cpp file, after #includes.

SomeLongClassName::LogToFile(LOG_AT_LEVEL, Color::Blue, "Finally I get to write something"); // Long names and extra parameters

CUSTOM_ASSERT( count < MAX_COUNT, "count is out of range" ); // Compulsory extra parameters

You might say, what about when it is useful to add more comments and decorations to asserts and logs? Sure. Provide alternate functions, macros or overloads to do that, but the most common usage should be so simple it is painless.

Something like this would have been better:

LOG("Write file '%s'", fileName); // Debug build compiles this code, short and minimal, var args for formatting text
ASSERT( count < MAX_COUNT ); // Assert implementation prints "count < MAX_COUNT" along with line, file etc.

The thought here is that every extra character, or extra step required to add debugging code to a program will reduce the likely hood of a programmer actually using those essential features. Visualizing what is going on in a program and checking for unexpected behavior is critical for writing solid code.

Now, back to coding standards...

A strict standard may say that a Case statement must look like:
Code:
switch ( someValue )
{
  case ERROR_ONE:
  {
    int localVar = 3;
    DoSomething(localVar);
    break;
  }
  default:
  {
    assert( !"unknown someValue" );
    break;
  }
}

That code looks like a good way to do things. It uses braces to prevent coding errors, and has default to catch unexpected value. White space and vertical layout make it easy to read.
But what if you simply wanted to return error strings from a list of about 100 error codes? The value in terms of avoiding coding mistakes is lost by the effort to maintain and read the code. So we break the rules and write:
Code:
switch ( errorBalue )
{
  case ERROR_ONE: errorString = "ERROR_ONE"; break;
  case ERROR_TWO: errorString = "ERROR_TWO"; break;
  case ERROR_THREE: errorString = "ERROR_THREE"; break;
  ... many more similar lines ...
  default: errorString = "Unknown Error"; break;
}

The point of this thought was to say that rules are good, but don't be pedantic about applying them.

2) C was about types, C++ is about ownership... The controversial scope prefixing standard.
I was introduced to this standard at my second job, a studio that used C++ and had a strict coding standard. Prior to this I had only coded C and ASM for a studio that had no coding standard at all. Within two weeks I appreciated this small rule and enjoyed the benefits thereafter.
Here's some Q & A to explain. These are questions (excuses) from real people I've met, with my answers following:

Q. Nobody uses that style anyway.
A. Its actually one of the most popular styles used by C++ programmers. Companies including Microsoft and nVidia use this standard, or at least quantities of their publicly release source code does.

Q. But it's too much to type, all this prefixing.
A. Two letters is all that is ever used. They don't accumulate like hungarian notation.

Q. Hungarian notation is so last decade.
A. It is. This isn't hungarian notation. That was for C programmers who used basic types. C++ is about encapsulating functions and data into user types, so prefixing variables with their type no longer makes sense. Scoping, however is a different issue.

Q. I haven't used it before so It'll take me ages to get used to it.
A. Most programmers will take two to five working days to become consistent using this style.

Q. It's unnecessary, just use descriptive variable names.
A. Hahahahahaha. Oh, you still need to do that.

Q. There's too much work to do this.
A. What! All you got to do is prefix members with m_, arguments with a_ and the odd static with s_. Thats it. Yeah, you could use g_ for globals, but we don't use globals.

Q. It's hard to read with all those prefixes.
A. The underscores allow the brain to focus quickly on the variable name beyond the underscore. Reading this code fluently will take minimal practice.

Q. It's hard to type underscore characters.
A. It's done using the right hand, with the little finger on the right shift and the middle finger on the top '-' key. A couple days of use and you won't think twice about the effort. No RSI law suits will be necessary.

Q. I just hate the whole idea.
A. Yes, of course you will until you use it and see first hand the benefits.

So, you're about to maintain some code written by a ex-employee, and you are under time pressure as always...
Consider glancing at this code snipit, pretend it is part of a much larger piece of code:
Code:
for( index = 0; index < numPoints; ++index)
{
  verts[offset + index] = points[index];
}
offset +=  numPoints;
totalProcessed += numPoints;

Now lets change it a bit:
Code:
for (index = 0; index < a_numPoints; ++index)
{
  m_verts[m_offset + index] = a_points[index];
}
m_offset +=  a_numPoints;
s_totalProcessed += a_numPoints;

Wow, but just glancing at the code you know which variables were parameters passed to the function, which are locals, which are members and static members. That's saved us a few bugs from making assumptions, and we all know never to ASSUME because...

Q. But why...?
A. Stop whining and just do it.

3) Be willing to learn from others. Over the years I've had the privilege of working with some brilliant programmers, and programmers who have developed good practices. It is important to have an attitude of willingness to learn and emulate those good practices.
These two practices stand out:

.1) Trace your code once. Try to cover all code paths, stepping through with the debugger. You will see exactly what your code is doing, not what you thought or hoped it would do. You only need to do this once, just after you write the code, but this single practice will eliminate 99% of all bugs at the time when they cost they least to fix. It will take self discipline to do this because it is not a fun activity and it is tempting to move straight on to the next task.

.2) Visualize everything. Use text file logging, on screen logging and on screen drawing to show what is happening in your game, application or algorithm. For 3D applications, this means providing an API which can be used from almost anywhere in code and has the ability to persist or just show up the next frame. This practice takes the guess work out of developing and debugging individual algorithms or whole applications. For example, a game might add a single line of code to an update function Debug::PlotBox(origin, extents, Color::Green); to show the trigger boxes on some entities. While developing a BSP construction or tracing algorithm, plotting lines and boxes with a persistent debug helper will allow you to see the algorithm work one step at a time and finally fly around the result in 3D, observing its integrity.


Top
 Profile  
Reply with quote  
PostPosted: Tue Apr 22, 2008 5:09 am 
Offline

Joined: Tue Apr 22, 2008 5:03 am
Posts: 1
Great list Greg. Having worked with you I can say that 97% of the time you managed to convince me (through logic and intelligent discussion) to follow your standards, and I believe I'm a better programmer for it.

I have the following random comments:

Quote:
Q. It's hard to type underscore characters.
A. It's done using the right hand, with the little finger on the right shift and the middle finger on the top '-' key. A couple days of use and you won't think twice about the effort. No RSI law suits will be necessary.

Just to get picky. You are actually supposed to use the opposite hand for the modifier key (in this case 'shift') as you use to press the main key. This reduces RSI as your hand doesn't need to contort. Either way, I found it took a little under 6 hours to get used to the underscore syntax and a little under a month before I stopped forgetting to put them in.

Another question that I heard:
Q. But in this day of IDE's you can mouse over a variable to get it's info.
A. Firstly this takes more time, and what hardcore programmers out there use a mouse anyway! It also gives you less information about scope and more about type (which was a floor of Hungarian notation).

Quote:
Be willing to learn from others

Couldn't agree more. Follow this and everything else will fall into place.


Top
 Profile  
Reply with quote  
PostPosted: Tue Apr 22, 2008 8:24 am 
Offline

Joined: Mon Dec 15, 2003 1:38 pm
Posts: 707
Thanks for your feedback Doolwind, and welcome to the forum :) You are right about the underscore typing. I just wrote down the method I use, which come to think of it does stretch the fingers a little. That could explain the RSI pain I sometimes feel in the elbows and wrists. Either that, or 22 years of daily keyboard use. By the way, I enjoy reading your blog.


Top
 Profile  
Reply with quote  
PostPosted: Mon May 05, 2008 1:45 pm 
Offline

Joined: Fri Nov 24, 2006 9:50 am
Posts: 165
Great post - I agree with pretty much all of it - here we use a slightly different prefix for arguments and member functions but they are still distinguishable at first glance just like yours.

We also have prepared internally a list of dos and don'ts which is like a tip book for programmers listing all the normal pitfalls that a lot of programmers come across with C++ that we add to from time to time.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 4 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group