Lazy Foo' Productions


Writing Readable Code

Last Updated: Jul 31st, 2020

It may not seem important, but any good programmer needs to know how to make readable code. Here you'll get some basic tips to make your code easy on the eyes.
In your intro to C++ class you probably never bothered with it, but making your code readable is important. Besides the fact that when you get into the real world you're going to have other people use your code, having your source code be neat and organized greatly increases your ability to debug your code.

It may not seem like it now, but when dealing with programs that have thousands of lines of code (ie: Video Games), having your code be a cluttered mess is going to be a pain when trying to fix something wrong with your code. Also when asking for help with your code, people tend to be less willing to assist you if your code makes them dizzy.

There's 4 major points to having neat code:

1) Properly indent and space your code

void Dot::handle_input()
{
//If a axis was changed
if(event.type==SDL_JOYAXISMOTION)
   {
  //If joystick 0 has moved
 if(event.jaxis.which==0)
  {
 //If the X axis changed
 if(event.jaxis.axis==0)
 {
  //If the X axis is neutral
  if((event.jaxis.value>-8000)&&(event.jaxis.value<8000))
 xVel=0;
 //If not
else
  {
//Adjust the velocity
if(event.jaxis.value<0)
xVel=-DOT_WIDTH/2;
else
xVel=DOT_WIDTH/2;
 }    
 }
 //If the Y axis changed
 else if(event.jaxis.axis==1)
 {
//If the Y axis is neutral
if((event.jaxis.value>-8000)&&(event.jaxis.value<8000))
  yVel=0;
  //If not
  else
   {
  //Adjust the velocity
  if(event.jaxis.value<0)
  yVel=-DOT_HEIGHT/2;
else
yVel=DOT_HEIGHT/2;
}
}
}
}
This is the input handling code from my Joystick tutorial only with different spacing. It's missing a bracket for it to compile. How long does it take you to find it?

Now here's the same chunk of code with the same missing bracket. How long does it take for you to find it here?
void Dot::handle_input()
{
    //If a axis was changed
    if( event.type == SDL_JOYAXISMOTION )
    {
        //If joystick 0 has moved
        if( event.jaxis.which == 0 )
        {
            //If the X axis changed
            if( event.jaxis.axis == 0 )
            {
                //If the X axis is neutral
                if( ( event.jaxis.value > -8000 ) && ( event.jaxis.value < 8000 ) )
                {
                    xVel = 0;
                }
                //If not
                else
                {
                    //Adjust the velocity
                    if( event.jaxis.value < 0 )
                    {
                        xVel = -DOT_WIDTH / 2;
                    }
                    else
                    {
                        xVel = DOT_WIDTH / 2;
                    }
                }    
            }
            //If the Y axis changed
            else if( event.jaxis.axis == 1 )
            {
                //If the Y axis is neutral
                if( ( event.jaxis.value > -8000 ) && ( event.jaxis.value < 8000 ) )
                {
                    yVel = 0;
                }
                //If not
                else
                {
                    //Adjust the velocity
                    if( event.jaxis.value < 0 )
                    {
                        yVel = -DOT_HEIGHT / 2;
                    }
                    else
                    {
                        yVel = DOT_HEIGHT / 2;
                    }
                }
				
        }
    }
}
I'm sure the difference is clear. Having everything inside the function indented allows you to clearly see where the function begins and ends. Having the statements and conditions neatly spaced allows them to be more readable. Having if/while statement with properly placed brackets and indenting the statements inside allows to clearly see the structure of the program.

There are no official rules for spacing in C++. You're free to use what ever rules you're comfortable with. Make sure to not only have everything clearly spaced, but make sure you're consistent.
    //If not
    else
    {
        //Adjust the velocity
        if( event.jaxis.value < 0 )
        {
            yVel = -DOT_HEIGHT / 2;
        }
        else
        {yVel=DOT_HEIGHT / 2;}
    }
So don't do this where your spacing scheme changes from line to line. Spacing standards don't do you any good if you don't follow them.

2) Give your variables/objects/classes/functions/etc descriptive names

//Some variables
int pH = 0;
int pP = 0;
int pS = 0;
Can you tell me what these variables are just by looking at them?
//Some variables
int playerHealth = 0;
int playerPower = 0;
int playerScore = 0;
How about these? I'm sure it's pretty obvious.

Using descriptive names allows you to see what something is quickly. This means not having to constantly reference variables/objects/classes/functions/etc names which saves you time.

When you have large projects, you're not going to be able to memorize every variable/object/class/function/whatever. Naming every one properly is going to help out a lot as your projects get larger.

3) Develop a naming standard

Naming standards are rules on how to name variables, functions, classes, constants, etc. Having standardized naming allows you to quickly identify whether something is a class/constant/variable/etc.

Here's the basics of my naming convention for example:
//I name my constants in all caps with words separated by underscores
const int MY_CONSTANT = 0;

//My variables are named in lower camel case.
int myVar;

//My functions are names in lower case with underscores separating the words.
void my_function();

//I name classes using capital camel case.
class MyClass;
Like spacing, there's no language wide C++ standard for naming. So you're free to create your own.

I'd also like to mention that some people also use prefixes to help them identify variable types. I personally don't do this but some of you might find this useful so I'll throw some examples out there.
//The "ptr_" prefix can be used to identify pointers
int* ptr_myPointer = NULL;

//Some people use prefix to identify the scope of a variable.
//"g_" can be used for global variables
int g_myGlobalVar = 0;

//"l_" can be used for local variables
int l_myLocalVar = 0;

//"m_" can be used for class member variables
int m_myMemberVar = 0;
Again it's up to you to develop a naming standard that works for you.

4) Properly comment your code

Commenting is also something that doesn't seem too important, but as your projects grow it will prove to be useful. They come in handy when working on a project with multiple programmers. They'll also help you remember what a piece of code does or how it works, which is useful when you don't see a piece of code for a while. Considering some programs can take a while to finish, it can happen where you forget what a piece of your code does. You'll be glad you commented your code when that happens.

When I say properly comment your code, remember there is such a thing as over commenting.
//Initialize x
int x = 0;

//Initialize y
int y = 0;

//Add 10 to x
x += 10;
This is some pretty bad over commenting. I can tell that x and y are being initialized and I don't need comments to tell me that. It's also obvious that 10 is being added to x in the 3rd statement.

Commenting like this is just a waste of your time.
//The offsets
int x = 0;
int y = 0;

//Move to the right
x += 10;
This is much better. The comments tell us what x and y actually are and what adding 10 to x does. Also notice that the initialization of x and y aren't individually commented. You don't need to comment every line of you code. Only comment what needs to be commented.

I have to admit that even this and the code I make for the articles and tutorials is over commented. The reason is that the code isn't "real" software, it's learning material and its purpose to help people learn. The commenting style is made to help explain the code to people who are fairly new to programming and SDL. When you're in the field, you and the people you work with will (hopefully) be experienced and know what they're doing. Over commenting can get fairly annoying for other people that read your code.
SDL_Surface *load_image( std::string filename ) 
{
    //The image that's loaded
    SDL_Surface* loadedImage = NULL;
    
    //The optimized surface that will be used
    SDL_Surface* optimizedImage = NULL;
    
    //Load the image
    loadedImage = IMG_Load( filename.c_str() );
    
    //If the image loaded
    if( loadedImage != NULL )
    {
        //Create an optimized surface
        optimizedImage = SDL_DisplayFormat( loadedImage );
        
        //Free the old surface
        SDL_FreeSurface( loadedImage );
        
        //If the surface was optimized
        if( optimizedImage != NULL )
        {
            //Color key surface
            SDL_SetColorKey( optimizedImage, SDL_SRCCOLORKEY, SDL_MapRGB( optimizedImage->format, 0, 0xFF, 0xFF ) );
        }
    }
    
    //Return the optimized surface
    return optimizedImage;
}
Here is some over commented code that you know as the surface loader used on the site. Now how much commenting should go into something like this?
//Loads, optimizes and color keys image from the given path
SDL_Surface *load_image( std::string filename ) 
{
    SDL_Surface* loadedImage = NULL;
    SDL_Surface* optimizedImage = NULL;
    
    loadedImage = IMG_Load( filename.c_str() );
    
    if( loadedImage != NULL )
    {
        optimizedImage = SDL_DisplayFormat( loadedImage );
        SDL_FreeSurface( loadedImage );
        
        if( optimizedImage != NULL )
        {
            SDL_SetColorKey( optimizedImage, SDL_SRCCOLORKEY, SDL_MapRGB( optimizedImage->format, 0, 0xFF, 0xFF ) );
        }
    }
    
    return optimizedImage;
}
Your comments should just summarize what going in the code like this. Because everything is given a descriptive name and is properly spaced, a programmer who's never seen this piece of code should easily be able to figure out how it works with a little help from the documentation. If there was a complex or fairly large algorithm here, you might need additional comments, but always remember that comments should summarize not try to give statement by statement documentation.

Worrying about all this stuff may sound like a waste of time, but eventually this stuff will come naturally. You can either learn the importance of neat code the easy way or the hard way.
If you have any suggestions to improve this article, It would be great if you contacted me so I can improve this article.