ID:120873
 
Be sure to check out:
Programming Tips #1 - If Statements
Programming Tips #2 - Making Progress
Programming Tips #3 - Design
Programming Tips #4 - Datums
Programming Tips #5 - Organization
Programming Tips #6 - Procs & Organizing Code


When you first start programming, the problem you're trying to solve is "how do I write code that'll do ______?". Initially you're happy just to get something working, who cares what the code looks like. But when you try to develop a complete game this indifference can become a problem. As your code gets messier and messier, the project becomes harder to work on - you're more likely to write code that has bugs and they become harder to track down and fix. Eventually it'll get to the point where you're wasting a lot of time, don't feel productive, and are more likely to stop working on the project.

As a more experienced programmer, instead of asking "how do I do ______?", you should start asking "what's the best way to do ______?". In this post we'll look at how comments and whitespace can greatly improve the readability of your code.


Comments and Whitespace


By now you should have realized that these articles aren't about telling you how to write code to do certain tasks. Programming isn't just about how to write code that works, it's about how to write code that works and is easy to manage. Implementing a special attack doesn't do you any good if the code is a mess, you forget how it works a couple of days later, have to re-code it so you know how it works, and get fed up and quit.

Whitespace and comments don't affect what your code does, but they do affect how easily you can read and modify it. This article describes some good ways to use comments and some bad habits to avoid. Let's look at an example that does almost everything wrong:

mob
proc
get_target()//this gets a target
var/mob/target//the current target
for(var/mob/m in oview(5,src))//for every mob in view
if(target)//if target is not null
if(m.health<target.health)//if m.health is less than target.health
target=m//set target to m
else
target=m//set target to m
return target//return the target mob

Comments and whitespace should only enhance readability.

Putting comments directly after each line makes the code harder to read.

The code should explain itself whenever possible.
Comments should only explain what the code can't say itself.

Most of the statements in this proc are very simple and we don't need comments to explain them. Many of these comments explain what the code does, but that's already made clear by the code itself. The line "target=m" means that target is set to m, adding a comment that says "set target to m" doesn't add anything. Another bad comment is after the second if statement - it explains exactly what the code does by using words to explain what the < operator means.

Your code will often be the most concise description of what it does, you just can't write a comment to explain what "target = m" is doing because that code explains itself. Your code can explain what happens but not why it's happening, so your comments should focus on explaining that instead.

Whitespace can be used to indicate the scope of the comment.

Instead of putting each comment on the same line as the code, put comments before code. If you need to, group lines of code together (don't have blank lines between the lines) to indicate what lines the comment applies to. This way you don't need to comment about every line, you can have one comment that explains a precise section of code.

Whitespace should be used to separate operators and arguments.

youcanprobablyfigureoutwhatthissentencesaysbutfiguringoutthe meaningisonlypartofit. Code has to be maintained - you may need to revise this proc later on. The more easily you can see what the proc is doing and how it works, the more easily you can work with it. If I wanted to rewrite the first sentence in this paragraph it'd be easiest to delete it and start over - because it doesn't have spacing it's hard to work with.

Being more readable also helps to identify problems. youcanreadwhatthisentencesaysbutitshardertofindmistakes. When you read code that's messy you're not really reading the code - more often you're looking at the code and making guesses about what it does based on a quick glance. You probably didn't realize the compacted sentence in this paragraph was missing an "s". The same thing can happen when you write messy code. Instead of seeing the obvious mistake your eyes just skip right over it.

Whitespace can be used to separate blocks of code.

A blank line can be used to make a clear split between two sections of code that do different tasks, or between a body of a block statement (if statement, for loop, etc.) and the next line of code outside the block. If you have many nested blocks you can also put a comment at the end of a block to indicate which block is ending.

Here's a fixed up version of the same code:

mob
proc
// find the weakest target within 5 tiles of the mob,
// returns null if there are no targets
get_target()
var/mob/target

for(var/mob/m in oview(5, src))

// if we already have a target, only select m if it's weaker
if(target)
if(m.health < target.health)
target = m

// otherwise we have no target and automatically select m
else
target = m

return target

The first comment explains what the whole proc does. While the code does explain itself and the proc name is rather descriptive, this comment explains the important details and spares you from having to read the whole proc.

The second comment describes the three lines after it. It explains those lines in terms that the code doesn't use. It's not just using plain language to say exactly what the code is doing, it explains why the code is doing that to acheive work towards a larger goal.

The third comment also describes why we're making that assignment instead of simply restating what the code already says.

Whitespace is used consistently around operators and between arguments. There are also some blank lines within the code to separate the loop's body, to improve overall readability, and to indicate what sets of lines the comments apply to.


Comments aren't used to make up for ugly code. You should write code that's as clean as possible and doesn't need comments to explain it (some of my other articles have examples of this). Comments are there to say things that your code can't say - why you wrote the code that way, why the code does what it does, what you'd like to later change about it, etc.

Comments and whitespace aren't essential to make your code work, but if you've been reading my programming articles, by now you've hopefully realized that writing code that works is only a small part of the problem. You don't have to use comments and whitespace exactly as I've shown here, but if you're not using them at all then you'll run into problems. If you want to make a game that's more complex than Tic-Tac-Toe, you'll need to write code that you can easily modify later.
As always, ideas for additional topics are appreciated.

Here are the articles I have in the works:
#8 - proper use of certain statements (if, for, while, etc.)
#9 - how coding things certain ways can make the map editor easier to use
#10 - a recap that ties together #1, 4, 5, 6, 7, and 9
Personally, I feel that writing the obvious comments is helpful if you're learning to code. Even if you know what it does, put the comment there so if you go for help on the dev forums people know what you're trying to do. I also think that using comments to explain even the most simple of things

var/list/L = list() // Define L to be an empty list


makes it easy to keep track of where you got lost, as well as re-iterate the coding knowledge you have. I had to re-learn a bunch of list operators because I left for 6 months and I'm like "How do I do this again?" But overall pretty nice.
I think that still fits with what the article says. The comments should tell you something the code doesn't, and if "L = list()" doesn't say to you "define L to be an empty list" then write the comment. The goal is to make these comments be unnecessary by being more familiar with DM. Comments need to be maintained too. Just like you might go back and update code as things change, you may need to update comments too.
You should probably be commenting on why you're defining L as an empty list rather than restating what the code already tells you. Take note of other procs which assume L has already been initialized, things like that.
From a previous post:

"Another suggestion I'd really like to see, best way to handle Cutscenes single and multiplayer."
Truseeker wrote:
From a previous post:

"Another suggestion I'd really like to see, best way to handle Cutscenes single and multiplayer."

I'm trying to stay away from very specific topics like that. There's no "best way" to handle cutscenes because it depends on the features you need. I can discuss the best way to write clear if statements because some methods are definitely clearer than others. I can't discuss the best way to implement a specific feature because there are so many ways to implement it.

What are the problems with creating cutscenes? maybe I can find some more general topics that will help you.
I didn't notice the s, but I sure did catch that cunning apostrophe!

Good article, anyhow!
Truseeker wrote:
From a previous post:

"Another suggestion I'd really like to see, best way to handle Cutscenes single and multiplayer."

There was a Dream Makers article several years ago (2007-8ish) that dealt with just that. I think it was by Gughunter, look it up!