Programming Style Guide
Introduction
This page outlines common FlatRedBall coding standards for consistency and clarity these should be followed when writing code for any first-part FlatRedBall game, FRB Editor, FRB Engine, or any other FRB application. In other words, if you are checking in any code to a FlatRedBall repository, follow these standards.
General Programming
Brackets
With the exception of single-line getters and setters in properties, brackets should be on their own lines.
Correct:
Incorrect:
Incrementing and Decrementing Values
The ++ and -- operators for incrementing and decrementing should always occur on their own lines. Correct:
Incorrect:
Exception: Compound statements are ok in for-loops:
Use temporary variables to avoid complex statements
Each line of code should do one thing. Do not use method calls inside of other method calls, or complex logic inside of other blocks of code.
Correct:
Incorrect:
Limit use of "value"
The "value" keyword in properties is necessary for setters, but it should be used as little as possible inside properties. The reason for this is because it makes migrating code outside of properties into separate methods more difficult. In practice this usually means that the field represented by the property should be set first, then it should be used in any code that follows.
Correct:
Incorrect:
Class Layout
Access Modifiers and Static
Access modifiers should be listed prior to modifiers such as static.
Correct:
Incorrect:
Regions
For readability all members in a class should be organized by type and surrounded with the proper regions. The following skeleton region structure shows how classes should be organized. Note, this is not required for smaller classes:
Structs as Fields
Structs should not be exposed as properties. Although most C# guidelines discourage exposing fields, structs are an exception because properties expose structs by value.
Correct:
Incorrect:
Similarly automatic properties should not be used for structs. Incorrect:
The reason this is not permitted is because exposing structs through properties prevents the user from modifying the individual components of the struct. The following code is only valid if the Position member is a field:
Exceptions
The exception to this rule is if the member in question mirrors other members, and when one is changed, calculations must be performed to determine the other. For example, the PositionedObject's RotationMatrix property mirrors its RotationX, RotationY, and RotationZ properties. The two must always be synced. The only way to guarantee this is to force RotationMatrix to be a property. When it is changed, the individual rotation components are calculated. This is a very rare situation, so this exception is rarely used.
Comments and Documentation
XML Documentation
When adding methods to a class, triple-slash documentation should be added (type "///" on the line before a method and the XML skeleton will be added). This is especially important for public members within the engine, as this documentation will be compiled with the engine and used for intellisense hints.
Comment code that deviates from expected structure
Comments should be used any time code deviates from what a programmer might expect. Also comment any time code is written a particular way to avoid a "gotcha" Correct:
Comment *any* change to already-written code
If code was written one way, then later changed, this *must be commented*. This is very important for maintainability. The reason for this is because any code that you are changing was written a certain way because the original author thought it was the best way. If you're changing code for whatever reason, then you're essentially saying "No, the code you have written is wrong." Any future reader will benefit from knowing the justification for the change. It's best to leave the old code there, but have it commented out so that future readers can see see what was changed along with why. Be sure to add the date of the change using a written-out month as opposed to numbers because different cultures have different order for numerical month and date (IE 1/2/10 may mean January 2 or February 1 depending on the culture).
Use the capitalized word UPDATE: when modifying already-modified code
If code has already been modified once but is being modified again, use the word UPDATE: with the date to indicate why it is being modified again. This enables future readers to have an immediate history of code changes when coming across the code.
Class, Enum, and Member Naming
The following section defines conventions when naming variables:
Properties and Methods should be capitalized
Correct:
Incorrect:
Avoid abbreviations and non-descriptive variable names
With a few exceptions, variables should not be abbreviated. Err on the side of longer names when in doubt. Auto-complete will aid you when writing long variable names, and most if not all FRB users will be using an IDE with auto-complete support.
Correct:
Incorrect:
Exceptions
Method arguments should be lower-case
Correct:
Incorrect:
Consts and Enums should be upper-case like Properties
Correct:
Incorrect:
Exception: const variables inside methods can be lower-case.
Variables should be nouns, Methods should be verbs
Naming your variables (fields, properties, method arguments) as nouns and naming methods as verbs will make your code read more like natural language, ultimately making it more expressive.
Correct:
Incorrect:
Exception: "Activity" is understood as a common method name, although the word "activity" is a noun.
Patterns
Methods should only have one exit point
Methods should not have return statements in the middle of the method.
Incorrect:
Correct:
Exception: "Early-outs" are allowed if they are at the beginning of the method and marked with a very obvious comment. Early outs should be self-contained and should not carry over into code with else statements:
Information-adding Exceptions should be in DEBUG blocks
Exceptions can be added to help give the user additional information on why a piece of code is failing. However, these should be added in #if DEBUG blocks. The reason is because additional if-statements can slow performance - especially in deep engine calls which may be executed in a tight loop. The exception will eventually be thrown in release, it may just be less informative than in DEBUG. But that's okay because the general pattern is that we exchange performance for information in debug, but release is intended to run as fast as possible.
Incorrect:
Correct:
Last updated