Skip to content

MegaMek Coding Style Guide

SJuliez edited this page Sep 1, 2024 · 25 revisions

Consistency is an important factor in code readability. Any code submitted to MegaMek, MegaMekLab, or MekHQ should follow the coding style outlined here. Anything not covered in here can probably be left up to the coder's preference, but if there is any doubt the Google Java Style Guide is a good source.

Note that MegaMek has been around for decades and has had many contributors over the years. Not all of the current code base adheres to these guidelines. These are the guidelines for new code, and old code is being brought into compliance gradually. Note also that despite the general state of the code we are not looking for contributions that only mean to modernize the code without addressing a specific issue (in other words, refactors), especially as a first time contribution.

Source File Structure

All source files must begin with a block comment that contains a copyright notice and the text of the license, such as the following:

/*
 * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved.
 *
 * This file is part of MegaMek.
 *
 * MegaMek is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * MegaMek is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with MegaMek. If not, see <http://www.gnu.org/licenses/>.
 */

Wildcard imports are permitted.

Formatting

Braces

Braces follow the Kernigan and Ritchie style. The opening brace comes at the end of the line with the class declaration, method declaration, or control statement, separated from the closing round bracket by a space. The end brace is on a line by itself unless followed by a reserved word that is part of the block or connects a multi-block statement (else, catch, finally, while).

Examples:

class Foo {  
    // class definition  
}  

if (booleanExpr) {  
    // do a thing  
} else {  
   // do a different thing  
}  

Braces are never omitted following if, else, for, while, or do, even for a single statement or an empty block:

if (booleanExpr) doSomething(); // wrong

if (booleanExpr) { //right  
    doSomething();  
}

Empty blocks may appear on the same line if not part of a multi-block (if/else or try/catch) statement:

public void maybeDoTheThing() {} // ok  

try {  
    defuseBomb();  
} catch (WrongWireException ex) {} // not ok  

Indentation

All block indentations are four spaces. Never tabs. Each case block in a switch statement should be indented one level.

Whitespace

A space should be used within a line in the following circumstances:

  • Between a reserved word and a parenthesis or a brace.
  • Between a parenthesis and a brace.
  • On both sides of a binary or ternary operator, with the exception of a method reference (::) or the dot separator (.).
  • After a comma

Parentheses

When building boolean expressions using multiple operators, the component expressions should be grouped explicitly:

if ((a == b) && (c == d))

rather than

if (a == b && c == d)

If the number of extra parentheses makes the expression hard to read, consider introducing local boolean variables.

Text String Handling and Localization

Any text strings displayed in the UI, either as UI elements or Report strings, should be stored in the appropriate messages.properties file to facilitate localization efforts.

Identifiers

Classes

Names of classes, interfaces, and enums should always be UpperCamelCase, with the first letter of every word capitalized and all other letters lowercase.

Variables and Methods

The names of methods and variables (including fields, local variables, and named parameters) should be lowerCamelCase, starting with a lower case letter and having the first letter of each additional word capitalized. The this. keyword as a prefix should only be used where necessary (e.g. in this.name = name).

Constants

Constants should be in all caps, with an underscore used to separate words. This includes fields that are declared static final and enum values.

Modern Java

We strive to use modern Java code. Still, it is important to keep in mind that the most concise code is not always the most readable. As many developers have to work with the code, it should prefer readability over being clever. Good ways to improve readability are:

  • use descriptive names for variables and methods: AmmoType ammoType instead of AmmoType at (write code for humans, not computers)
  • use intermediate boolean variables for complex tests, or
  • factor out to methods. This can be very useful to hide streams
  • add javadoc comments to methods and classes; write the javadoc for those who do not already know what the method does and do not want to read the method's code

Streams and Optional

Streams can be very useful and very concise. However, their readability is debatable and their preferred form comprises multiple lines. Therefore, preferrably

  • streams should not be used directly within the test expression of an if () statement
  • when applicable, stream results should be stored in variables with descriptive names or placed in methods with descriptive names

Optionals can in some places improve the code, especially when used as a method return value, by forcing the caller to deal with the possibility of an empty return value. However, in other places they can be more cluttersome than helpful. Therefore, they should be used, but judiciously.

Comments and Documentation

JavaDoc

All public or protected methods and classes should be documented with a JavaDoc comment, but is good practice to do so for package and private methods as well. Exceptions can be made when in trivial cases where it is obvious what the method does, such as basic setters and getters, but it is better to err on the side of over documenting. It is not necessary to repeat the documentation when overriding a method that is documented in the parent class unless the method is overridden to do something that is not covered in the documentation of the parent class.

Annotations

When overriding an inherited method, the @Override annotation should always be used.

Clone this wiki locally