Code Convention - vonix-id/styleguide GitHub Wiki

Code Convention

Table of Contents:

Overview

Coding conventions/guidelines are a set of guidelines for a specific programming language that recommend programming style, practices, and methods for each aspect of a program written in that language. These conventions usually cover file organization, indentation, comments, declarations, statements, white space, naming conventions, programming practices, programming principles, programming rules of thumb, architectural best practices, etc. These are guidelines for software structural quality. Software programmers are highly recommended (in most cases, enforced) to follow these guidelines to help improve the readability of their source code and make software maintenance easier.

[!WARNING] Offenders and rule breakers will get slapped.

cat-slap

Indentation

We use spaces, not tabs.

Regarding whitespace, follow the approach below (ordered by priority):

  1. For whitespace insensitive languages (e.g. Java, Kotlin, C#, C++, XML, HTML), spaces should be set to 2.
    1. 2 spaces allow for more to fit in a single line.
    2. Modern text editors and IDEs (such as VSCode Bracket Pair Colorization feature) have solved this code scope readability issue.
  2. For whitespace sensitive languages (e.g. Python), spaces should be set to 4.
    1. Readability is the primary concern.
  3. Follow language's guideline/specification on the recommended number of whitespace.

Notable exceptions include:

  • YAML's spec recommends 2 spaces (directive #3), but is a whitespace sensitive language (directive #2).

Line Length

We use 100 characters as the standard line length (hard wrap), as it provides the best balance of:

  • Maximizing code per line.
  • Maximizing readability on laptops and other smaller screens.
  • Reducing code complexity per line.
  • Reducing arbitrary line breaks.
  • Enough space for side-by-side editor/comparison.
  • Enough space for navigation views in IDE.

Other Examples:

  • 80 characters:
  • 120 characters (or more):
    • Support for modern widescreen monitors.
    • Prevents comfortable side-by-side view on 14"/16" laptop screens.

Newline at End of File

Mostly due to historical reasons, every text file (including JavaScript source files) should end with a \n or "newline" character.

Coding Style

to err is human

Since human makes mistakes, we use tools to enforce coding style consistency. The enforced coding rules are in:

File Documentation
.editorconfig Defining coding styles for the text editor.
.gitattributes Files and paths attributes used by Git.
.gitignore Specify untracked files to ignore by Git.
.markdownlint.json A Node.js style checker and lint tool for Markdown/CommonMark files.
.prettierrc Opinionated code formatter.
checkstyle.xml Checkstyle is a development tool to help programmers write Java code that adheres to a coding standard.
detect-config.yml A static code analyzer for Kotlin
intellij_codestyle.xml IntelliJ importable code style scheme.
tsconfig.json The file specifies the root files and the compiler options required to compile the project.

CSS Units

  • We strongly prefer the responsive/relative rem unit over the fixed px units.
  • To make calculating sizing easier, define the default base style so that 1rem is equal to 10px (instead of 16px).

Image

When possible, always use:

  • WEBP for pixel-based image formats.
  • SVG for vector-based image formats.

enum vs string

  • If your set of parameters is limited and known at compile time, use enum. (e.g. sex, types, etc.)
  • If your set of parameters is open and unknown at compile time, use strings. (e.g. name, address, identifiers)

comments

These are the 10 rules/best-practices[^1] for writing code comments:

[^1]: Best practices for writing code comments (Stackoverflow, 2021)

Rule 1: Comments are not Version Control

It was fine in the 80s (when there are no version control systems), but today it is a code smell.

❌ Example:

// ********************************************************************
// * Logger helper                                                    *
// *                                                                  *
// * 2005-03-01 First Version, Anders Abel                            *
// * 2007-08-17 Added Console Output, Anders Abel                     *
// * 2009-12-15 Removed file output, John Doe                         *
// *                                                                  *
// * Usage: Call Logger.Write() with string to be logged.             *
// ********************************************************************
public static class Logger
{
  public static void Write(string message)
  {
    //using(StreamWriter writer = new StreamWriter("c:\\temp\\log.txt"))
    //{
    //    writer.WriteLine(message);
    //}
    Console.WriteLine(message);
  }
}

Rule 2: Comments should not duplicate the code

Comments that add no information have negative value because they:

  • Add visual clutter.
  • Take time to write and read.
  • Can become out-of-date.

❌ Example:

i = i + 1; // Add one to i

Rule 3: Good comments do not excuse unclear code

Common misuse of comments is to provide information that should have been in the code. A simple example is when someone names a variable with a single letter and then adds a comment describing its purpose:

❌ Example:

private static Node getBestChildNode(Node node) {
  Node n; // best child node candidate
  for (Node node: node.getChildren()) {
    // update n if the current state is better
    if (n == null || utility(node) > utility(n)) {
      n = node;
    }
  }
  return n;
}

✅ Example:

private static Node getBestChildNode(Node node) {
  Node bestNode;
  for (Node currentNode: node.getChildren()) {
    if (bestNode == null || utility(currentNode) > utility(bestNode)) {
      bestNode = currentNode;
    }
  }
  return bestNode;
}

As Kernighan and Plauger wrote in The Elements of Programming Style:

"Don't comment bad code — rewrite it."

Rule 4: If you can't write a clear comment, there may be a problem with the code

Kernighan's Law:

Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.

Instead, rewrite the code to something you understand well enough to explain or, better yet, that is straightforward.

Rule 5: Comments should dispel confusion, not cause it

A story from Steven Levy's Hackers: Heroes of the Computer Revolution:

[Peter Samson] was particularly obscure in refusing to add comments to his source code explaining what he was doing at a given time. One well-distributed program Samson wrote went on for hundreds of assembly-language instructions, with only one comment beside an instruction that contained the number 1750. The comment was RIPJSB, and people racked their brains about its meaning until someone figured out that 1750 was the year Bach died, and that Samson had written an abbreviation for Rest In Peace Johann Sebastian Bach.

Rule 6: Explain unidiomatic code in comments

A judgment call needs to be made as to whether code requires explanation. When learning Kotlin, I encountered code in an Android tutorial of the form:

if (b == true)

I immediately wondered whether it could be replaced with (as one would do in Java):

if (b)

After a little research, I learned that nullable Boolean variables are explicitly compared to true in order to avoid an ugly null check:

if (b != null && b)

I recommend not including comments for common idioms unless writing a tutorial specifically for novices.

Rule 7: Provide links to the original source of copied code

Including a reference to the source enables future readers to get the full context, such as:

  • What problem was being solved?
  • Who provided the code?
  • Why the solution is recommended?
  • What commenters thought of it?
  • Whether it still works?
  • How it can be improved?

❌ Example:

// Magical formula taken from a stackoverflow post,
// reputedly related to human vision perception.
return (int) (0.3 * red + 0.59 * green + 0.11 * blue);

✅ Example:

// Converts a Drawable to Bitmap. via https://stackoverflow.com/a/46018816/2219998.

Rule 8: Include links to external references where they will be most helpful

Links to standards and other documentation can help readers understand the problem your code is solving.

✅ Example:

// http://tools.ietf.org/html/rfc4180 suggests that CSV lines
// should be terminated by CRLF, hence the \r\n.
csvStringBuilder.append("\r\n");

Rule 9: Add comments when fixing bugs

Comments should be added not just when initially writing code but also when modifying it, especially fixing bugs.

✅ Example:

 // NOTE: At least in Firefox 2, if the user drags outside of the browser window,
  // mouse-move (and even mouse-down) events will not be received until
  // the user drags back inside the window. A workaround for this issue
  // exists in the implementation for onMouseLeave().
  @Override
  public void onMouseMove(Widget sender, int x, int y) { .. }

Not only does the comment help the reader understand the code in the current and referenced methods, it is helpful for determining whether the code is still needed and how to test it.