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
, andpublic
. - Only allow the lowest level of access needed, e.g. Default to
private
. - Use
properties
overpublic
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.
- Use the
- 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
anddevelop
. - 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 themaster
branch. - From the
develop
branch, create afeature
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 thedevelop
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 arelease
branch from thedevelop
branch. - Test the
release
branch, and merge any necessary bug fixes back into therelease
branch. - When the
release
branch is ready, merge it back into both themaster
anddevelop
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.