/
Programming Style Guide

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

Related content

Abstract Communications Interface
Abstract Communications Interface
Read with this
Code Documentation Methods and Standards
Code Documentation Methods and Standards
More like this
Android BLE Communications Interface Design
Android BLE Communications Interface Design
Read with this
Software Design Template
Software Design Template
More like this