Programming Style Guide
Related Jira Issues
https://unity3d.atlassian.net/browse/FNSDKEXT-14
https://unity3d.atlassian.net/browse/FNSDKEXT-184
Introduction
For the Windows libraries and the Unity package, Unity’s internal coding standard will be used. This standard is an extension of Microsoft's Framework Design Guidelines, which defines a number of rules not covered by this document, unless it is explicitly excepting a clause from Microsoft’s FDG.
For the Android libraries, Google’s Java Style Guide will be used, and Unity’s style guide will be adapted where appropriate to Java-specific semantics and language constructs.
Definitions
camelCase: *words capitalized, except the first
PascalCase: all *words capitalized
UPPERCASE: all letters in all *words capitalized
*A “word” may only contain letters and numbers (no underscores or other symbols)
Encoding
Text file encoding should use UTF8 with no BOM, using LF (unix) line endings
Tabs should use 4-wide tab stops, using spaces only (no tab characters)
Lines should not contain any trailing whitespace
End of files should always include a single newline
Files
The style and standard of any imported libraries or external code should be maintained
Use PascalCase for file names, typically matching the name of the dominant type in the file (or if none is dominant, use a reasonable category name).
Naming
Use PascalCase for all symbol names, except where noted.
No ‘Hungarian notation’ or other prefixes, except where noted.
Spell words using correct US-English spelling.
Use descriptive and accurate names, even if it makes them longer. Favor readability over brevity.
Avoid abbreviations when possible unless the abbreviation is commonly accepted.
Acronyms are PascalCase, unless they are exactly two letters, in which case they are UPPERCASE. (ex. GetCpuCycles(), IOStream)
Do not capitalize each word in so-called closed-form compound words. (Microsoft’s FDG example)
Use semantically interesting names rather than language-specific keywords for type names (i.e. GetLength > GetInt).
Use a common name, such as value/item/element, rather than repeating the type name, in the rare cases when an identifier has no semantic meaning and the type is not important (i.e. newElements > newInts)
Type Naming
Make type names unambiguous across namespaces and problem domains by avoiding common terms or adding a prefix or a suffix. (ex. use 'PhysicsSolver', not 'Solver')
Avoid unnecessary prefixes/suffixes, even when other types in the namespace have a prefix (ex. use 'LightEstimationData', not 'ARLightEstimationData', even though 'ARSession' exists)
Avoid naming types after terms that represent different concepts in different domains (ex. use 'AndroidInput', not 'Input')
Do not use namespaces to enable reusing an existing type name, as resolving conflicts in user code requires using aliases or fully qualified type names.
Methods and Parameters
When a method takes one or more arguments that imply a binary condition, consider the following options:
If the method name clearly conveys a binary condition, then use a bool argument (e.g., void SetActive(bool active))
If the method name conveys a condition that could conceivably have more than two states:
You can create multiple named method variants (e.g., void Repaint() and void RepaintImmediately(), T GetComponent() and T GetComponentReadOnly()).
(+) Avoids adding new enumerated type to the API surface.
(-) Increases number of named methods (and thus number of search points in API reference).
(-) API surface will grow if support for new modes is added later.
You can create a single method and add an enum for the condition (e.g., void ApplyChanges(InteractionMode mode = InteractionMode.UserAction)).
(+) More robust to future support of additional modes.
(+) Single named API point communicates common intent, parameter conveys implementation/execution details.
(-) Adds more enumerated types to the API, which may not be widely used.
In most cases, prefer overloads rather than additional methods with different names (e.g., void GetItems(List<T> items) and void GetItems(T[] items, int length) instead of void GetItemsDynamic(List<T> items) and void GetItemsPreAllocated(T[] items, int length)).
Readability Examples
HorizontalAlignment instead of AlignmentHorizontal (more English-readable)
CanScrollHorizontally instead of ScrollableX ('x' is somewhat obscure reference to the x axis)
DirectionalVector instead of DirVec (unnecessary and use of nonstandard abbreviation)
Common Abbreviations
param (parameter)
arg (argument)
id (identifier)
db (database)
ok (okay)
Spacing
When dealing with whether to put spaces before open parenthesis:
If it looks like a function call, no space (function calls, function definitions, typeof(), sizeof())
If it opens a scope, add a space (if, while, catch, switch, for, foreach, using, lock, fixed)
No spaces immediately inside any parens or brackets (e.g. no 'if ( foo )' or 'x = ( y * z[ 123 ] )')
Comma and semicolon spacing as in English ('int a, float b' and 'for (int i = 0; i < 10; ++i)')
Exactly one space is required after the // in a C++ style comment.
Do not add a space between a unary operator and its operand (!expr, +30, -1.4, i++, --j, &expr, *expr, (int)obj, etc.).
Do not add spaces around member access operators (a.b, a->b, etc.).
Spaces are required both before and after all other operators (math, assignment, comparison, lambdas, etc.).
Wrapping
Wrap code once it gets to around 120 columns wide to keep side-by-side diffs sane (not a hard limit; use your judgment).
When necessary, break lines after boolean operators in conditional expressions, after ';' in for-statements, and after ',' in function calls
Comments
Documenting the 'why' is far more important than the 'what' or 'how'.
Document anything that would surprise another engineer (or yourself in six months when you've forgotten it).
/*C-Style comments*/ are not permitted. They are reserved for commenting out big hunks of code locally (never to be committed).
No "divider" comments (i.e. long ----- and ////// comments just to break up code).
No "category" comments (i.e. // Functions // Private Data // Globals etc.).
Only use /// (triple slash) comments if you are writing xmldoc, and never for ordinary comments that you want to stand out
Usings
Located at file scope at the top of the file, never within a namespace.
Three groups, which are, top to bottom: System, non-System, aliases. Keep each group sorted.
Strip unused 'usings' except the 'minimally-required set', which is marked with *required below.
Only use aliases when required by the compiler for disambiguation, and not for hiding rarely-used symbols behind a prefix.
Always drop explicit namespace qualifications on types when a 'using' can be added (i.e. almost all of the time).
using System; // | Not required, but strongly encouraged
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Company.BuildSystem; // | Start of non-System group
using Microsoft.Win32;
using UnityEngine;
using Component = UnityEngine.Component; // | Start of aliases group
using Debug = UnityEngine.Debug;
namespace UnityEditor // | Full contents of namespace indented
{
Enums
Use a singular type name, and no prefix or suffix (e.g. no E- prefix or -Enum suffix).
Constant names should have no prefix or suffix.
Do not specify constant values unless absolutely required (e.g. for version-safe protocols - rare).
enum WindingOrder // | Drop redundant access specifiers (leave off 'internal' at file scope)
{ // | Opening brace is always on its own line at the same level of indentation as its parent
Clockwise, // | Code within the braces always indented one tab stop
CounterClockwise,
Charm,
Singularity, // | Trail last element in a list with ','
} // | Closing brace is on its own line at same level of indentation as parent
// | Put exactly one blank line between multi-line types
Flags Enums
Use a plural type name, and no prefix or suffix (e.g. no E- prefix and no -Flag or -Flags suffix).
Constant names should have no prefix or suffix.
Use column-aligned bit shift expressions for the constants (instead of 2, 4, 8, etc.
public enum VertexStreams
{
Position = 1 << 0,
Normal = 1 << 1,
Tangent = 1 << 2,
Color = 1 << 3,
UV = 1 << 4,
}
Interfaces
Name interfaces with adjective phrases, or occasionally with nouns or noun phrases.
- Nouns and noun phrases should be used rarely and they might indicate that the type should be an abstract class, and not an interface.
Use 'I' prefix to indicate an interface.
Ensure that the names differ only by the 'I' prefix on the interface name when you are defining a class-interface pair, where the class is a standard implementation of the interface.
Methods
Give methods names that are verbs or verb phrases.
Parameter names are camelCase
Classes
Name classes and structs with nouns or noun phrases.
No prefix on class names (no 'C' or 'S' etc.).
Fields
Use prefix + PascalCase for non-public field naming.
Prefixes: m_ = instance field, s_ = static readwrite field, k_ = const
Also prefix static/instance readonly with k_ if the intent is to treat the field as deeply const.
Drop redundant initializers (i.e. no '= 0' on ints, '= null' on ref types, etc.).
Never expose public fields which are not const or static readonly. These fields should be published through a property.
Use readonly where const isn't possible.
Events
Do not declare new delegate types. Use Action<...> instead.
Do not expose public delegate fields. Use events instead.
Include one participle-form verb in the event name (generally ending in -ed or -ing, ex. occurred, loading, started, given)
*EventArgs struct parameters are not necessary, but they should be used if the data sent to the event has the possibility of needing to be changed. [FDG Exception]
Parameterized Types
When only a single parameterized type is used, naming it 'T' is acceptable.
For more than one parameterized type, use descriptive names prefixed with 'T'.
Consider indicating constraints placed on a type parameter in the name of the parameter.
Structs
Name classes and structs with nouns or noun phrases.
No prefix on class names (no 'C' or 'S' etc.).
Structs may be mutable, but consider immutability when appropriate. [FDG Exception]
EventArgs
Always use structs for EventArgs types, and never extend System.EventArgs [FDG Exception]
Make EventArgs structs immutable
See the event example above for when to define EventArgs structs.
Attributes
Mark up all attributes with an AttributeUsage, as narrow as possible.
Postfix attribute class names with "Attribute".
Exceptions
Postfix exception class names with "Exception".
Do not inherit from ApplicationException