How Programmers Program

Nov 24, 2009

Not From Start to Finish

As a beginning programmer, looking at finished example code can seem daunting. How, with any amount of experience, does someone know what key to type next? What is the thought process in someone’s head while they’re typing out new functions, classes, and algorithms?

Unless a programmer is retyping something that has been committed to memory, the characters aren’t typed in their final order. Finished code for anything other than the most trivial of examples typically involves dozens, sometimes hundreds of iterations, each of which amount to drafting, editing, and polishing.

A Steven King novel is an impressive thing to read. A Spielberg film is an impressive thing to watch. Every piece seems well planned, and every scene throws something new our way. The pure density of ideas presented can seem overwhelming to an aspiring creative. But that quality of content doesn’t just come together that way the first time, beginning to end. The final product came together only after countless drafts, aggressive editing, and years of attention paid to polishing every last detail.

Why would computer programming be different?

From the Outside In

The first time that I compile any videogame project, the first version is a black screen. The second version that I compile is a black screen that makes a sound, or displays a rectangle. The third version will perhaps make the sound when spacebar is pressed, or move the rectangle to the last place the mouse clicks. Until those things work right, the videogame project isn’t going to work anyway.

But that isn’t just how the process starts – that’s also how features get implemented. Whether planning went into which features are worth making (a good habit if you have enough experience to estimate how long different features will take, or how valuable they’ll be in the big picture), or whether it’s just time for hacking features together to explore and entertain creative whims (a good way to learn), the actual process is still incremental. A version is built with an unanimated character drawn on screen, the next version moves that character according to which control keys are pressed, the next version applies gravity to the character, followed by a jump ability, then collision with enemies, followed by hook up to animations, and so on. Between each step, there’s compilation and brief playtesting to make certain that the last executed layer does what it’s expected to do.

Enable Fast Iterations to Test Changes

Because of the iterative nature of this process, early on in development consideration should go into how to streamline the testing cycles. While the tendency of many beginners is to first make the logos, splash screen, and menus – again demonstrating the erroneous thinking that something ought to be made in the order it will be experienced in – I suggest working in the opposite order. Leave the interfaces and splash screens for last, when they’ll slow down testing the least possible cycles, letting the game compile/run directly into play mode as early as possible and keeping it that way for the bulk of the development time.

Errors Are a Sign of Progress, Not Failure

Another part of the process in how programmers program is hitting frequent errors and obstacles. Whether we’re setting up the development environment, writing core functionality, or extending existing functionality to tend to details, the process of programming is often a two-way dialogue with the machine.

We spend years in schools learning to associate red marks or answers marked wrong (especially to be redone!) as a sign that we have done something wrong. This thinking has no place in programming, particularly when the notification of what’s “wrong” just comes from the machine.

Your Patient Teacher

The compiler can be thought of as a teacher with infinite patience. The compiler is always happy to proof-read code, and after passing that grammar/spelling inspection, it will show exactly what the work so far does.

It’s a bad idea to wait until most of an work is done before making sure that it’s being done right. If starting in the wrong direction, it’d be wise to find that out asap before the mistake grows throughout the program. When it comes to asking real human beings to look over what we’ve done – whether we’re talking about parents, peers, teachers, or online forums – we have a carefully conditioned feeling that we should pester them only if we have to, because we have to respect their time and not interfere with their obligations.

The compiler doesn’t have any plans for later.

Matching {Braces} While Typing

Much of the math that we do “on paper” is a process of jotting as much as we can on the page so we can devote our mental energy to thinking through the steps of (a.) what else to jot on the page (and b.) what are the proper processes to advance what’s on the page to the next step. Even when we do mental math, most of us still wiggle our fingers to temporarily hang on to information (like carry digits) while we juggle other figures and steps in our head.

That’s how the most expert programmers program. It’s called “distributed cognition” by psychologists, so named because it distributes cognitive processes to include mechanisms outside the mind – but remembering the fancy word for it is less important than practicing it.

When typing a loop, function, or conditional (confused? see this entry about common programming terms), most programmers close braces pairs and quickly handle format indenting before the filling what goes on the inside. In other words, when I’m halfway through typing this:

for(int i=0;i<100;i++) {
  printf("The secret password is XYZZY");
}

It doesn't look like this:

for(int i=0;i<100;i++) {
  printf("The secre

It looks like this:

for(int i=0;i<100;i++) {

}

The distinction looks subtle, but what about when nestling two loops to perform a computation over all entries in a two dimension array, and checking with a conditional inside them, all within a function? Still, each matching right-brace "}" is typed immediately after the corresponding left-brace "{", so that the code is typed in the following order from 1st to 11th:

int some2DArray[100][100]; // from early in code...

void ValidateTheArray() { // 1st line typed

  for(int y=0;y<100;y++) { // 3rd line typed
    for(int x=0;x<100;x++) { // 5th line typed

      if(some2DArray[y][x] == -1) { // 7th line typed
        // TO-DO NEXT: type 10th line(s)
      } else { // 8th line typed
        // TO-DO LAST:type 11th line(s)
      } // 9th line typed

    } // 6th line typed. Matches 5th line
  } // 4th line typed. Closes braces from 3rd line

} // 2nd line typed, Right half of 1st line typed

Closing out the braces and doing indentions before filling inside them in this case means fewer things to remember while thinking through what needs to be done inside the nestled loops. We thought about that part, put it down in code (like jotting numbers down for long division), enabling us to forget about it while we focus on writing the code at the innermost scope.

This is a particularly powerful habit because a mistake in matching braces can be one of the most difficult for the programmer, or even the compiler, to accurately diagnose. Because a mismatched brace changes what parts of the code relate to one another, the compiler may think that the error is someplace else far away in the code, or even give the unhelpful "expecting right brace at end of program" which means there could be a "}" missing anywhere in the code. Time not spent getting frustrated tracking down these hard-to-fix but easy-to-avoid code errors is time that can instead be spent productively iterating on functionality.

Scaffolding: Temporary Work Improving Lasting Work

The last part we'll cover here on how programmers program is to take advantage of the concept of scaffolding. Scaffolding in everyday use, for anyone less familiar with the term, refers to the temporary layers of ladders and wood-planks stacked in metal frames around the outside of a building while it's under construction, giving workers easy reach to everything. Once the building is completed, the scaffolding is torn down and removed, leaving behind a structure which could not have been built as efficiently or with as much attention to detail had scaffolding not been used.

What I call scaffolding, in the world of programming, is what most developers call "debug output". The idea is to temporarily include extra lines of code to help make visible the otherwise invisible calculations and flow of the program. Print statements (printf in C/C++), trace statements (ActionScript 3), log statements, and the like outputting information to the console like, "starting function GameDraw", "loading background image Swirl03", or "left mouse click detected" are examples of this.

Debugging

A good debugger and debugging environment, when available, provide this same functionality through breakpoints, although depending on the language, environment, and platform, a good debugger may not always be available. Breakpoints pause the program at a given instruction, enabling the program to advance one step at a time, observing numbers and changes in memory. This method, when available, is particularly well-suited to making sense of obscure technical bugs.

Breakpoints, like debug print statements or visualization of internal states, are removed or disabled from the game or source code before shared. Debug elements are not needed by the time a game or source code can be shared, because like the scaffolding around the new building, they have already been put to use in ensuring that the project itself came together.

Visualizing this information in-game can also be helpful sometimes when rooting out questions about real-time functionality that takes place across multiple frames which could be difficult to read from lines of text, such as drawing the player as a different color rectangle based on whether the collision code currently thinks that the player is on the ground.

Internal Tools

The greatest example of the scaffolding concept is the development of software that simplifies the development of software - level design tools, weapon/unit stat editing tools, animation tools - programs that enable design problems to be solved using design tools instead of through programming. Though they're (usually) not shipped with the final game, this additional programming work makes it possible for the game to be finished sooner and better. In smaller games - including most of my old 2D tile-based projects - sometimes the easiest way to build the level editor is to introduce it as a level editing mode in the game itself, hiding that functionality for the final release. That way the same assets (graphics/sounds), rendering code, and level formats are the same for both playing and editing as the code base develops.

When looking at example source, or playing a finished game, rather than thinking about how the entire program could have come together at once (a daunting task no matter how much experience someone has!), be thinking instead about how scaffolding of debug statements could verify aspects of the program while working on it, or about what the first few crude features would be developed and tested after the empty screen compiles. Test, then repeat.

Start Focused on What's Interesting

Think about music composition - the refrain or underlying tune is likely to be worked on before the beginning or end. Or a story might be built around one or more intense climactic scenes, which will need to be packaged between build up and resolution before being ready for others.

When an idea jumps into mind for a videogame, starting to write what the final videogame code might be like from start to finish - complete with rigorous class definitions for everything and all the trappings of a finished game's functionality - just doesn't make sense. Get the bare core working with as little code as possible at first, then layer and iterate.

(Originally posted as GameDevLessons.com Vol. 8 Sec. 1)



Learn and practice team game development with Gamkedo Club.
Membership worldwide. Professional support. Proven process.




Subscribe by e-mail to receive weekly updates with Gamkedo.Community interviews and YouTube training videos for game developers!



Comments are closed.

All contents Copyright ©2017 Chris DeLeon.

Site production by Ryan Burrell.