Welcome back! We’re going to get into how logically organize your code in this section of the collaborative coding guidelines - refer back to the previous two articles for the guidelines on variables and functions.
Tuning Variables Instead of Magic Numbers
Programmers often refer to hard-coded constants as “magic numbers”. Writing literal numbers into your code is bad in a few ways - it’s a little unclear what you mean, and if you want to make a change to that literal number, you have to find it in the code. These kinds of numbers come up related to physics tuning, character weight, time for actions to happen, they’ll be all over your code, and in games they’re often the numbers you want to tweak or change the most.
Instead of hard-coding those literals into your code, you should make these class-level variables, all together in the same place at the top of your files. That way, they’re easy to find, and tweak as necessary as you continue to work on your game.
Guideline: No magic numbers - instead, use constant, class-level variables.
Reduce Nesting Where Possible:
This is an easy way to make your code much cleaner and clearer to understand - if you have any conditional that has more than one “else-if”, you’re going to have a lot of nesting and repetition - and it won’t be immediately clear the relationship between these various tests. Instead, it’s often better to replace these nested if… else statements with a switch statement, especially if using an enum.
Guideline: Use switch statements wherever they make sense.
Elses can often be confusing, especially if the if statement only contains one thing - you have to return to the if statement above to figure out what’s happening inside of it. Take, for example, this code for adding an item to a players inventory:
It’s not immediately clear what causes the text to be shown, and the conditional for whether or not an item can be added to the inventory is probably not necessary when we’re trying to read our code. If we move that logic into the “AddToInventory” function, and have the function return whether or not the item was actually added, we’ll get the following code:
This code is much easier to read, and has the added benefit of the logic for whether something can be picked up in the AddToInventory function, a more logical and easier to place it for future adjustments.
Guideline: Replace else’s with return values if possible.
The final tool to reduce nesting is to remove large “if” statements that contain most or all of the code in a function. Highly inlined and nested code is hard to read and requires us to read it like a computer and not like a human.
It’s not that the above code is impossible to understand - but it definitely takes time, and if you want to add to or change the code, you have to read the entire function to make sure you’re putting checks in the correct places. You can do this by returning early in the function, rather than adding more indentation to your project.
What’s especially great about returning early in a function to reduce nesting is that if you choose at any point to add more conditions or checks, you can just slot them into the above function. This logic works for any kind of process where you’re checking a condition for everything in a function - just return on the opposite of the condition:
Guideline: Avoid highly nested code by falling out of functions early.
Keeping Your Code Clean
This section just has a few key rules:
Be consistent with braces and indentation. You don’t have to follow the conventions, but you do have to be consistent. This is one of the most common places I’ve seen student issues - they’ve accidentally left a block of code without realizing it because their indentation wasn’t consistent.
Delete code instead of commenting it out. This one is particularly hard for new students, but if you develop good version control habits, you can use version control to get your code back if needed. Having huge blocks of commented out code makes your scripts very hard to digest and understand, and as a result your more likely to make mistakes.
Specific to C# / Unity: Use #region tags to organize your code. Separate out the sections of your code using region tags, especially if your code gets over a hundred lines long. And reorganizing your code into these regions will help you think critically and review the work you’ve done. I recommend “Variables”, “Tuning Variables”, “Monobehavior/Unity Functions”, “Public Functions”, and “Private Functions” as regions to begin - but follow whatever conventions make sense to you and your project.
Reorganize and refactor your code regularly, and make a “clean commit” before and after reorganizing. You aren’t done working on the code for the day until you’ve reorganized your code and made sure it’s legible. You wouldn’t turn in an essay for school that was every idea you had in the order you had it, and you shouldn’t send your collaborators all the functions typed in the order you thought of them.
That's it for now - come back next time for some architecture specific guidelines!