In General

These are the essential styles serving as the main pillar for all other language-specific styles.

#1 - Respect Readability and Owner

  • RESPECT the local coding style. Period.

Before you start coding, observe the existing source codes and seek out for existing code styles inside the repository. Remember, at the end of the day, it is the owner (or maintainers) who will be reviewing your codes, respect them. If there isn't any, make a discussion with them to clear things out.

Rationale

  1. "Just because I enjoy fireworks does not means I want to light your living room in a blazing fire. No one likes it. No one wants this type of person."

#2 - Never Act Smart Even for the Silly Question

  • When in doubt, STOP, RESEARCH, ASK! DO NOT act smart and assume things.
  • Answer/Acknowledge any question, be it silly. You wouldn't know it is vital or risking losing $125mil.

It’s better to ask now compared to correcting 1000+ lines of codes you created. It’s okay to be smart but don’t act smart. Use common sense to solve a question or a problem.


Rationale

  1. "we are in the industry of managing information. If we make one wrong mistake, it is going to cost us a bomb, just like a qualified engineer!"

#3 - Functionalize and Write Testable Codes

  • Keep the code compartmentalized, modular, clear, and testable.
  • Any codes that are not testable even by the means of manual testing should not be committed at all.

Keep the code back-tractable, like from main to other core functions, then internal functions, etc. This way, it’s easier to figure out what is your code doing. Example in BASH:

#!/bin/bash
################################
# User Variables               #
################################
VERSION="0.0.1"

################################
# App Variables                #
################################
action=""
message=""

################################
# Functions                    #
################################
print_version() {
        echo $VERSION
}

run() {
        if [[ "$message" == "" ]]; then
                echo "I see no message. Did you say something?"
                return 0
        fi
        echo "$message"
}

################################
# CLI Parameters and Help      #
################################
print_help() {
        echo "\
PROGRAM NAME
One liner description
-------------------------------------------------------------------------------
To use: $0 [ACTION] [ARGUMENTS]

ACTIONS
1. -h, --help                   print help. Longest help is up
                                to this length for terminal
                                friendly printout.

2. -r, --run                    run the program. In this case,
                                says the message.
                                COMPULSORY VALUES:
                                1. -r \"[message you want]\"

                                COMPULSORY ARGUMENTS:
                                1. -

                                OPTIONAL ARGUMENTS:
                                1. -

3. -v, --version                print app version.
"
}

run_action() {
        case "$action" in
        "h")
                print_help
                ;;
        "r")
                run
                ;;
        "v")
                print_version
                ;;
        *)
                echo "[ ERROR ] - invalid command."
                return 1
                ;;
        esac
}

process_parameters() {
        while [[ $# != 0 ]]; do
                case "$1" in
                -h|--help)
                        action="h"
                        ;;
                -r|--run)
                        if [[ "$2" != "" && "${2:0:1}" != "-" ]]; then
                                message="${@:2}"
                                shift 1
                        fi
                        action="r"
                        ;;
                -v|--version)
                        action="v"
                        ;;
                *)
                        ;;
                esac
                shift 1
        done
}

main() {
        process_parameters $@
        run_action
        if [[ $? != 0 ]]; then
                exit 1
        fi
}
main $@


Rationale

Making modular executable functions allow:

  1. compartmentalized white-box testing in various languages
  2. describes the codes' execution blocks without needing commenting
  3. made reading a source code uni-direction manner
  4. provides a metric for the needs of when to packaging functions into library, and easily migrating them
  5. all codes should be testable. If it is not, heed the warning of bad and satanic codes.

#4 - Indentation

  • Use TAB ("\t") over SPACE (" ").
  • Adjust to 80 columns width or 1:10 ratio so that you maintain maximum of 3 indentations per lines.

Rationale

  1. It acts as a natural cyclomatic complexity sensor
    • If you need more than 3 tabs per line, it signals that you are going to produce a complicated nesting functions or programs.
      • Heed that warning and break it into smaller parts with function or subroutines.
  2. Clearer, readable codes
    • With 8-spacing, it illustrate a clearer spacing and make it easier to read. Some of us codes from 5am to 10pm (~15 hours) on a daily basis. Make sure your codes facilitates readability.
  3. Tab was designed for indentation
    • TAB is meant for indentation. It was designed by default so use it instead of spacing. That’s 1 byte over 8 bytes in terms of size. Your code editor should render them correctly anyway.
  4. You are going to adjust your editors anyway
    • When there is an indentation issue, you are going to adjust the editor's indentation display anyway.

#5 - Indentation Patterns

Rationale

  1. Use line and indentation efficiently.
  2. Keep the scrolling vertical-only, not horizontal (no single-line inherit codes).


Pattern for Switch Cases

switch (keyword) {
case 'A':
        do_something;
        break;
case 'B':
        do_something_else;
        break;
default:
        do_default;
        break;
}

Keep the case same indentation as switch. You don’t need additional indent for something like part of the overall syntax.


Pattern for If Else Cases

If it is one-line action:

if (condition) do_this;

If it is multi-line actions or multi-conditions:

if (condition) {
        do_this;
        do_something_more;
} else if (condition) {
        do_that;
} else {
        do_something_else;
}

If the else is a default routine in a function, then do not write it. Always check for specifics and respond and exit/return early instead of nesting and wasting indentation:

#####################################################################
# You are checking false condition. Exit/return early when possible # ##################################################################### 
if (false condition) {
        do_false_handling; 
} else {
        do_default;
}
exit 0;


#######################################
# A Better way (and save indentation) #
#######################################
if (false condition) {
        do_false_handling;
        exit 1
}

# anything from this line is true
do_default;
exit 0;

Another example, instead of:

if err != nil {
        // error handling
} else {
        // normal code
}

write:

if err != nil {
        // error handling
        return // or continue, etc.
}
// normal code



Pattern for Looping

for (i=0; i<5; i++) {
        do_something_repeatedly;
} 

for item in list {
        do_something_repeatedly;
}

while (i != true) {
        do_something_boring_repeatedly;
}

while true {
        do_to_infinity_and_beyond;
}

Keep in clear, short, and simple. Watch where to put SPACE before, inside and outside the conditions depending on languages.

Avoid do ... while if available. It simply means you couldn’t be bothered with readability checking for looping and waste indentations and brain juice.

Avoid unconventional keyword provided by the language to keep the learning curve flat, like until. Use the conditions smartly.

#6 - Break Long Lines

  • Keep maximum columns at 80 characters for wide range of editors compatibility including vim.
  • While reading, you would want to make your codes scroll in a single direction dimension, rather than 2.
  • Break at higher syntactic level.

There are 2 types of long lines breaking:

  1. breaking the code
  2. breaking long string / data types

Example in bash:

# BAD - Long Code
./program --super-long-arguments value1 --super-long-arguments2 value2 --super-long-arguments3 value3

# GOOD
./program --super-long-arguments value1 \
        --super-long-arguments value2 \
        --super-long-arguments value3



# BAD - Long String
./program --super-long-arguments "extremely long values that I have no idea what I'm typing here"

# GOOD
./program --super-long-arguments "\
extremely long values that I have no idea what I'm typing here"



# BAD - Break mid-statement
currentEstimate = calc(currentEstimate + x *
    currentEstimate) / 2.0f;

# GOOD - Break at higher level
currentEstimate =
    calc(currentEstimate + x * currentEstimate) /
        2.0f;


Rationale

  1. Maximizes editors compatibility to minimize contributors' adjustment horror
    • The more convenience you provide, the easier for contributors to contribute back (and happily)
  2. Keep it simple for code reviews
    • 1 scrolling direction dimension is better than 2, as we can see how your code works from either top-bottom or bottom-up.

#7 - Naming Convention

  • There should only be 1 convention per source code, or per repository
  • No Hungarian notation in ANY convention
  • For private naming convention, you can use simplified alphabets or maximum of 2 words that are short and on point
  • Choose CamelCase convention if the name is short (max 2 words) and concise
  • Choose snake_case convention if name is long and carries many meanings.

Rationale

  1. Maintain Preferences
  2. Keep things simple and not mixed up


CamelCase Convention

  1. Use UPPERCASE_SNAKE_CASE for global convention.
  2. Use CapitalizedCamelCase for public accessible API, variable, or function.
  3. Use lowercaseStartCamelCase for private accessible API, variable, or function.
  4. Avoid _startingUnderscoreCamelCase as it creates confusion.

Example:

var (
  // SELECTED_LANGUAGE only works in en-US
  SELECTED_LANGUAGE = "en-US"
)


func internalAddAlgo(x int, y int) {
  ...
}

// Add is a function to add x and y mathematically.
func Add(x int, y int) {
  internalAddAlgo(x, y);
}


snake_case Convention

  1. Use UPPERCASE_SNAKE_CASE for global convention.
  2. Use lowercase_snake_case for public accessible API, variable, or function.
  3. Use _starting_underscore_snake_case for private accessible API, variable, or function.
    1. Exception: when the language is offering public / private keywords. In that case, use those keywords instead and stick to lowercase_snake_case for private functions.

Example:

extern *char SELECTED_LANGUAGE = "en-US" // tell the world only works in en-US


int __internal_add_number(int x, int y)
{
  ...
}

// Add is a function to sum x and y mathematically.
int add(int x, int y)
{
  return __internal_add_number(x, y);
}

#8 - Variables and Functions

  • Avoid global variables unless absolute necessary.
  • A function should use a maximum of 5-7 variables inside it including function parameters. Anything more is creating a long functions. Break them into small pieces or redefine a proper data structure.
  • Write in a way that a first year high school student can understand the function.
  • Function always takes default value from user, disallowing nil, null or none as a parameter.
  • For languages which offers braces {, adhere to its coding convention. Otherwise, it is preferred to be:
int add(x, y) {
        return x + y;
}


Rationale

  1. If you need more than 5-7 variables in a function, you’re doing something wrong and probably want to split it into smaller functions.
  2. If you can't write the code where a first year high school student can understand, then the code is a problem and complex. Break it down to the level of comprehensions.

#9 - Comments

  • TELL WHAT not how.
  • FIX THE BAD CODE instead of explaining them with comments.
  • Use the long comment syntax if available.
  • Stick to one commenting syntax convention (choose the multi-line version)

To measure whether you need a comment always think this:

Good codes has a lot of comments; bad codes needs comments. - Dave Thomas and Andrew Hunt


Example:

/* this is clearer, simple to remember than using // in languages like C */

/* 
 * This is also clearer
 * for multi-line comments
 */



# This is another commenting style

# This is the longer
# multi-line
# version


Rationale

  1. It is a waste of time explaining bad codes anyway.
  2. Keeping 1 convention reduces learning curve loads.

#10 - Silence is Gold

  • Keep the output (stdout) as quiet as possible.
  • Use the correct output channel like stderr or log status messages into a file.

Example in BASH:

Add() {
        echo "$((1 + 2))"
        return 0
}

1>&2 echo -n "This is a status message. Doing 5 + 3 = "
Add 5 3


Rationale

  1. Comply to Operating System convention.
  2. Use the right channel doing the right thing.

#11 - Return Values

  • Keep 0 integer value as SUCCESS.
  • Any non-integer numbers indicates failure with identity defined your error table.


Rationale

  1. Respect the standard convention.

#12 - Filenames

  • Always append .extension.


Rationale

  1. Respect the standard convention, even for the sake of Windows users.

#13 - Write for Clarity, not Brevity

  • Write for human to read and maintain, not for compiler.
  • Avoid one-liner, make it clean and clear.


Rationale

  1. The compiler knows what the codes is and turns it into the corresponding binary instruction. Codes are for human to read and maintain, so write it for human.
  2. We are not optimizing for the size of source codes on disk or time needed to type the codes.

#14 - Naming

  • Choose a name that is concise, descriptive, purposeful, and predictable.
  • Keep it sensibly short based on its context.
  • DO NOT name it based on their types.
  • Stay consistent with naming style
  • Avoid purposeless naming like base, common, utils, misc, etc.

To measure a good name, you should not need to explain the name itself. Good name should be not wasting spaces for extraneous, describes the application of the variable or constant, not the content (e.g. the result, not the function implementation), and quickly and easily inferred (idiomatic).

Example in Go:

// instead of this:
var usersMap map[string]*User
var companiesMap map[string]*Company
var productsMap  map[string]*Products

// use this:
var users map[string]*User
var companies map[string]*Company
var products  map[string]*Products


Rationale

  1. Keep the code sensibly short and simple.

#15 - Documentation

  • Always document public symbols or API


Rationale

  1. Make your customer (user) life easy to use your package.

#16 - Errors Handling

  • Embrace, not skip.
  • Code it defensively.


Rationale

  1. Always have parameters checking (defensive) for each inputs at the front line to prevent unexpected crashes and controlled processing.
  2. Errors are good indicators. Embrace and fix them, not working-around them.

#17 - Concurrency

  • Use delegation (threaded), not micro-management (shared memory) whenever possible
  • If it is simple, do it yourself
  • Never delegate without knowing the end-goal
  • Close the transmission from sender side, be it a message/signal payload or channel between sender and receiver

Concurrency is similar to team delegation. If the job is simple, don't delegate; do it. If you want to delegate, make sure you tell the end-goal to your teammate. Don't let him/her run wildly and ended up destroying things. Also, delegate, not micro-managing it (shared memory). Everyone hates micro-manager so avoid being one.


Rationale

  1. Simplify the process blocks for delegation so that you can avoid nasty concurrency problem like miscommunications, race conditions, dead-locks, etc.

#18 - Single Return for Crypto Sensitive Functions

  • Use arithmetic or down to assembly if available.
  • Never return early. Always write the function to have only 1 return.
  • Error handling should be part of the function sharing the same timing.

This is to prevent timing side-channel attack for sensitive codes, especially password hashes comparison. It allows the attacker to use a timing table to match the passwords back to the original characters via confident guessing.


Rationale

Keep things simple and boring, complying to the cryptography community best practices.

#19 - No Magic Numbers/Values

  • Use macro or constant to label the magic numbers
  • If it is truly magic number (e.g. fast inverse square root), comment on it

This is to avoid letting the next developer to wondering in the magic land or forcing them to read up documentations from scratch just to figure this magic out.


Rationale

There are only few truly magical numbers in the current industry. Those has a name too. Therefore, yours should have too.

#20 - Refactor Duplication on 3 Strikes

  • The first time - just do it.
  • The second time - if readability is not compromised, whine it but apply duplication. Else, refactor it.
  • The third time - refactor is a must.

This is to balance between costly refactoring vs. necessary duplication during each stages of the codes.


Rationale

There are time where you just need to prove things are working (first prototype), testing the development process (expand the code base for the first time), and truly a duplication issues in future development (building on existing working code base). Do duplication refactoring when the cost is worth the optimization.

#21 - Avoid Global States Whenever Possible

  • It causes confusion between modules/packages.
  • It makes a module/package works magically, forcing new developers to lost control.


Rationale

Program should only expose minimum necessary public interface. User does not need to know too much of stuff. Also, maintainers and developers hate magical codes where global state facilitates. We should always write the code in clarity and controllable.

Example:

  1. module A creates a global value X
  2. module B reads X and perform its function
  3. new developer starts wondering why module B is able to work without proper values OR start hunting down X, if the package is huge. This is a waste of resources.

#22 - Track Your Memory Usage

  • If you can't track it, others can't as well.
  • A normal human can track up to 7-12 variables at a time (for a function). If you need more than that, the function is complex. Break it down.
  • Track both static and dynamic types.


Rationale

  1. Acts as a natural linter for functional complexity.
  2. Makes it clear for any new developers about the memory consumption at source codes level instead of relying on linter.
  3. Avoid memory leaks or related unrecoverable bugs in certain languages.

#23 - Restrict use of Goto

  • if you need to use goto, only use it inside a function, and jump inside that function ONLY.
  • only do a goto jump according to the direction of the readability (if the flow is down, then jump down, not up).
  • only do a goto jump after all the memory declaration are done.


Rationale

  1. Abusive use of goto jump is the very source of evil and the first step to spaghetti codes.
  2. Only use goto jump for time-sensitive functions, like cryptography compare API.

#24 - Use Unsigned Integer for Monetary Values

  • Use unsigned integer type matching the CPU architecture (unsigned int 64-bit for 64-bit CPU)
  • Reduce the monetary value into the its minimal cent value (actual monetary value)
  • Only process the monetary display output when needed (involves number to string conversion and decimal/comma point injection)


Rationale

  • money is not quantified by the decimal point; it is rather by cents. We split money with point into "dollar" and "cent" is for easy evaluation sake.
  • money trades at very high speed (high-speed trading). Hence, use the unsigned integer type makes more sense than another other type (especially float data type)
  • money values changes dramatically. Hence, you need the data type as raw as possible to maintain accuracy.

That's all about coding styles in general. You may feel free to explore the language specific coding styles. Their mentioning overrides this generalized version.