Programming Standards and Guidelines - alexitsios/Calamity GitHub Wiki

The terms Standards and Guidelines are used interchangeably throughout this document.

Introduction

What is this?

  • An important document for programmers to review and reference throughout development.
  • It's important to note that these are Guidelines, not rules.
  • It's a tool to help us all work together efficiently.
    • Any member of the team may suggest changes to the guidelines at any point during development.
    • Suggested changes will be discussed and finalized after consensus with the team.
    • Let's make something that works best for all of us.

What are programming guidelines and why do we need them?

Programming guidelines help ensure that code is consistent and easy to understand, regardless of which team member wrote it. This leads to faster code comprehension and improved productivity, especially for team members with less experience. The goal is to be able to read and understand code at a glance. It should be easily understandable even by those who do not know programming. The guidelines also serve as a good starting point for new team members to quickly understand our code structure. Additionally, adhering to programming guidelines can reduce the time spent on reading and understanding code, which can ultimately lower maintenance costs and development time. Overall, programming guidelines benefit both individuals and the team as a whole.

Benefits of programming standards:

  • Improves ease of team integration and code comprehension.
  • Enhances code quality, efficiency, and ease of maintenance.
  • Simplifies code complexity.
  • Decreases development cost and time.

Drawbacks of not establishing clear programming standards:

  • Each team member may adopt their own programming styles.
  • Creates a more complex codebase structure.
  • Difficulties in maintaining and debugging code.
  • Increased development time and time for code comprehension.
  • Can result in reduced team motivation and cause burnout.

Code refactoring:

  • Don't go out of your way to change the existing code base to fit the guidelines.
  • Apply guidelines to every new line of code and every area of the code you work with moving forward.
  • The goal is not to undo finished work or waste time redoing what's already done.
  • Code must conform to guidelines for new pull requests to be merged.

Programming Best Practices

  • Review the code architecture page to see the architecture and systems we'll use.
  • Follow SOLID principles to the best of your ability. Ask for help when you need it!
S - Single Responsibility Principle (SRP)
O - Open-Closed Principle (OCP)
L - Liskov Substitution Principle (LSP)
I - Interface Segregation Principle (ISP)
D - Dependency Inversion Principle (DIP)
  • Utilize Unity's component system and our ScriptableObject architecture for a Composition over Inheritance design pattern.
  • Use namespaces, grouped by system or similar-functionality. Our namespace prefix is Calamity, e.g. namespace Calamity.NameOfAFramework{}
  • Always denote access modifier scope. Generally, keep it to protected, private, and public.
  • Only allow the lowest level of access needed, e.g. Default to private.
  • Use properties over public variables, e.g.
//Another script cares about this
public float boo;    // Standard public variable    

//Can be read by anything but only set locally
public float Boo {get; private set; }    // Property

// If it's to be accessible from the inspector add SerializeField attribute
[SerializeField]
public float Boo {get; private set; }
  • Avoid "hard-coding" data whenever possible. Serialize data and set values through the Unity inspector to be designer-friendly.
    • Use the [SerializeField] attribute to expose private fields to the Unity Inspector.
    • Use the [HideInInspector] attribute to hide public fields from the Unity Inspector.
  • Don't abbreviate. Use descriptive names for classes, methods, and variables. Describe things accurately so anyone can understand at a glance.
  • Rename things often, whenever needed to more accurately describe something.
    • Do so with right click and “rename” in Visual Studio. This will update all references.
    • Add [FormerlySerializedAs] attribute when renaming serialized fields. Avoids breaking references in the Inspector.
  • Use enums and constants with descriptive names instead of magic strings and numbers, e.g.
// Unclear 'Magic' variables (bad)
float gravity = 9.8f;
float jumpHeight = 2.5f * gravity;

// Use descriptive constants instead (good)
const float EarthGravity = 9.8f;
float jumpHeight = 2.5f * EarthGravity;

Performance Considerations

  • Use Unity’s Update() method and its variants minimally. Every call is expensive.
  • Debug.Log() and its variants should be used for debugging purposes, not as a print window for development.
  • Use object pooling to reduce garbage collection and improve performance.
  • Use static variables sparingly. If there's an easy alternative, use it instead.
  • Variables and fields that can be made const should always be made const.
    • If const isn’t possible, readonly might be a suitable alternative.
  • Use strings minimally. Ideally, strings should only be used for printing to the UI.
    • If we keep strings contained to a limited area and filter all output strings through a single access point, it will help later if we consider doing regional localization.
  • Avoid Boxing variables as objects, e.g.
int x = 42;
object obj = x; // boxing occurs here

Programming Style Guide

Naming conventions:

  • Use PascalCase for class names, methods, enums, constants, static variables, and public variables, e.g. PlayerController.
  • Use camelCase for private variable names, e.g. moveSpeed.
  • Prefix private fields with an underscore, e.g. _health.
  • Don't use snake_case, e.g. jump_height

Code formatting:

  • Use tabs for indentation.
  • Use one statement per line.
  • Use braces on a new line, e.g.
private void ExampleMethod()
{
    // code here
}

Commenting:

  • Use inline comments sparingly and only when necessary.
  • Use XML documentation comments for all public methods and fields, e.g.
/// <summary>
/// An example method to demonstrate XML documentation using the summary, param, and returns tags.
/// </summary>
/// <param name="x">First value to sum.</param>
/// <param name="y">Second value to sum.</param>
/// <returns>Sum of x and y as an int value.</returns>
public int SumValues(int x, int y)
{
    int z = x + y;
    return z;
}

Git and Version Control

  • Follow a Gitflow branching model (details below).
  • Use descriptive commit messages with a summary log of changes you've implemented.
  • Pull frequently and merge changes regularly to avoid merge conflicts.
  • Have other members of the team review your work to ensure quality and consistency.

Gitflow branching model:

  • This model is based on two main branches: master and develop.
  • The master branch represents the production-ready builds.
  • The develop branch serves as the main branch for ongoing development.

Gitflow pipeline involves the following steps:

  • Create the develop branch from the master branch.
  • From the develop branch, create a feature branch titled as the 'feature name' for each new feature or bug fixes you'd like to add.
  • Once a feature is complete, the developer creates a pull request to merge the feature branch back into the develop branch.
  • Automated testing: (Use of automated testing hasn't been finalized for Calamity) Automated tests are run on the programming changes to ensure that they meet the defined quality standards.
  • Code review: Before a pull request is approved, after automated testing, it will be reviewed by other team members to ensure that it meets Calamity's standards and follows best practices.
  • When the develop branch has enough features to warrant a release or build, create a release branch from the develop branch.
  • Test the release branch, and merge any necessary bug fixes back into the release branch.
  • When the release branch is ready, merge it back into both the master and develop branches.
  • Tag the master branch with the new release version.

This workflow helps keep the master branch stable and production-ready at all times, while still allowing for ongoing development in the develop branch. It also allows for easy collaboration on new features and bug fixes, as each feature or fix is developed in its own branch before being merged back into the main branches.

⚠️ **GitHub.com Fallback** ⚠️