ruk·si

Master Programming Guide

Updated at 2015-09-01 22:50

This is a programming language independent notes about writing code. While I've been reading programming standards and books, I've noticed that the best guidelines apply to most programming languages.

Code examples in this note are a mixture of different languages; PHP, Java, JavaScript and C++. This note focuses mainly, but not exclusively, on object-oriented languages. This note is related to note about developers.

There should be coding guidelines for every non-solo project. A coding guide consists of a project or organization specific guidelines how to structure your code, how to layout your code and list of all the major DOs and DON'Ts.

  • It unifies the primary way of communication, the code.
  • It cannot have too much detail.
  • It can be too restrictive, but is usually too lax.
  • It can be too long. If the guide is like a small novel, no one will read it.
  • It reduces code ownership because all team members write similar code.
  • It improves quality of the code And focusing on quality must be part of the software deveopment process in order to construct high quality software.
  • It should tell about the most important practices, gotchas and anti-patterns that the programming language and the environment have.

Establish coding conventions before you begin programming. It gets harder and harder to define coding convetions later in a project.

Guidelines are all or nothing. The whole development team must agree to the guidelines. It doesn't help if one developer uses 2 space indentation while all the others use 4.

Your personal style should not affect your professional work. Always follow the established style and only change the codebase style after a mutual agreement with the project team.

Project > Language > Frameworks > Libraries > You. When starting a new project, prefer using the coding guidelines defined by the language creators. If no or nonexistent coding rules are specified by the language creators, use the rules used by the libraries and frameworks you mainly rely on. Only after that apply your own standards.

Consider using static code analysis tools. They can scan your code for unwanted patterns. Running the static code analysis should be automatic like tied to running tests.

Guidelines are just that; guidelines. Use common sense and consider breaking the rules when the context requires it.

Architecture

It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures.

Focus on splitting the problems. Architecture should aim to split the problem to tiniest possible subproblems while minimizing duplication and complexity. When a software is in small pieces with low coupling, individual parts can be tested, debugged, improved and fixed faster. When your architecture starts to divert from this goal, consider refactoring.

Code that changes together should be grouped together Code should be factored so that changes don't ripple throughout the codebase.

Avoid writing code as much as possible. Use mature, open source and tested third party libraries. Consider using those libraries through wrapper objects so they can be changed more easily. Prefer writing simple but expandable solutions over over-engineered general implementations.

If you require a library that makes and handles HTTP requests, you should be
trout slapped senseless if you start to implement one on your work time.

Never preemptively optimize for performance. One of the most common waste of development time is writing optimized code. Solve the problem now, make it faster later. Aim for simplicity, not performance.

Keep your files small. If a single line passes 200 lines of code, consider refactoring. If a single file passes 500 lines of code, split it right away. If you have a non-binary file that cannot be split under 500 line chunks, your whole design is flawed.

Keep common things simple. Especially things you want to encourage. Like error handling, testing and logging.

Setup one command testing. It should be possible to run all tests by executing one command. If running tests is hard, programmers will run them less frequently, leading to writing less tests, leading to inefficient testing. The later you add testing culture, the harder and harder it gets. Construct testing environment around your project right after you have a working prototype.

Setup one command building. Building and compiling your project should be done with a single command. Create build scripts and distribute them to the development team. Saves a lot of development time.

Setup one command deployment. Deploying your project to production or staging should be possible with a single command. Configure one command deployment and one command undo action. Create scripts on the production server or use a deployment frameworks. Less margin for error and faster fixes in chaotic situation.

Code Layout

Source code should be written to be understood by people, not by machines.

Code layout rules should be simple, logical and consistent. Otherwise developers will have hard time remembering them and they aren't used. Code that behaves the same should look the same.

All code layout rules aim to promote the logical structure. Obvious logical structure makes code easier to scan and faster to read. Code layout rules are not about making code look pretty. Always think for yourself when writing code. Don't follow code layout rules that obscure logical structure in the specific context.

# bad, goes against how the code behaves
x = 3+4 * 2+7;

# good
x = (3+4) * (2+7);
x = 3 + (4*2) + 7;

Be consistent with your indention. Indentation is a strong indicator of structure. It doesn't matter much which indentation you use, your eyes will get used to it. Always prefer following programming language and library standards.

I personally prefer 4 spaces > 2 spaces > 8 spaces > same order using tabs.
But more often than not, I have to use 2 space indention e.g. with Node.js
and Ruby because that is the established standard.

Emphasize beginning and ending points of code blocks. Always include optional brackets as they show structure.

// bad
if (basicPrice === NULL)
    return;

// good
if (basicPrice === NULL) {
    return;
}

Limit lines to 80 characters. This restriction doesn't apply to markup languages like HTML/CSS or when mixing a programming language with a markup language like Jade/JavaScript.

  • Allows more files to be open side by side in an editor or IDE.
  • Easier to hot patch code on a remote server through console.
  • Online code hosting services support at least this much.
  • You are not excluding any development environments from the team.
  • Multitude of short lines are easier to read than fewer long lines.
  • Sets a hard limit for code nesting, which forces you to split problems into smaller code blocks.

Keep the code compact. Minimal vertical height is good so you can keep all relevant on a screen at once.

// bad
public class ReporterConfig {

    /** The class name of the reporter listener */
    private String m_className;

    /** The properties of the reporter listener */
    private List<Property> m_properties = new ArrayList<Property>();

    public void addProperty(Property property) {
        m_properties.add(property);
    }

}

// good
public class ReporterConfig {
    private String m_className;
    private List<Property> m_properties = new ArrayList<Property>();

    public void addProperty(Property property) {
        m_properties.add(property);
    }
}

Use blank lines to group logically related code together. But mind the vertical space your code takes, code blocks get hard to read when they do not fully fit on the screen. Blank lines should take around 10% of your code.

// bad
package formal.text.widgets;
import java.util.regex.*;
public class MyWidget extends ParentWidget {
    public static final String REGEX = "'''\d'''";
    private static final Pattern pattern = Pattern.compile("'''(\d)'''",
        Pattern.MULTILINE + Pattern.DOTALL
    );
    public MyWidget(ParentWidget parent, String content) throws Exception {
        super(parent);
        Matcher match = pattern.matcher(content);
        match.find();
        AddChildWIdgets(match.group(1));
    }
}

// good
package formal.text.widgets;

import java.util.regex.*;

public class MyWidget extends ParentWidget {
    public static final String REGEX = "'''\d'''";
    private static final Pattern pattern = Pattern.compile("'''(\d)'''",
        Pattern.MULTILINE + Pattern.DOTALL
    );

    public MyWidget(ParentWidget parent, String content) throws Exception {
        super(parent);
        Matcher match = pattern.matcher(content);
        match.find();
        AddChildWIdgets(match.group(1));
    }
}

Functions definitions and calls may go multiline. Allow function calls and definitions go multiline, but prefer them as single line. Specify one parameter per line in multiline definitions and align all parameters to the same position. Usually when function goes multiline, you should consider refactoring though.

// bad
void doStuff(parameterOne, parameterTwo, parameterThree, parameterFour, parameterFive)
{
    // ...
}

// good, but the formatting can vary depending on the project
void doStuff(parameterOne,
             parameterTwo,
             parameterThree,
             parameterFour,
             parameterFive)
{
    // ...
}

Max one statement per line. Don't use multiple statements per line even if the language supports it. Error message line numbers become vague, you easily miss statements and it obscures the logical structure.

// bad
var A := 'a'; var B := 'b'; var C := 'c';
int maxCount; Pointer A, B; Font typeFace;

// good
var A := 'a';
var B := 'b';
var C := 'c';
int maxCount;
Pointer A;
Pointer B;
Font typeFace;

Always include spaces around an assignment. Stop being silly.

// bad
$myName='Ruksi';

// good
$myName = 'Ruksi';

Naming

Naming rules aim for consistency, readability and searchability. Always follow naming conventions of the language and the frameworks you use.

  • Names should be consistent so you can guess names for searches like git grep.
  • Names should readable so you can read code easily and this reduces misunderstandings.

Variables should be named after their intent. What variable contains is usually obvious when reading the code.

// bad
x
value
number
people
nopit
temp
html = '<div></div>' // you can see that it is html

// good
numberOfPeopleInUsOlympicTeam
numTeamMembers
container = '<div></div>'

Don't abbreviate uncommon words. You may consider using shorter names if they are not shown on the public interface or variable is used only on a couple of rows after declaration.

// bad almost always
var wh = 10;

// good if private visibility, project wide standard that w = window
// or used only on a couple of lines after this declaration
var wHeight = 10;

// good always
var windowHeight = 10;

Avoid having similar names in the same scope. Autocomplete and mistyping can cause hard to debug problems.

// bad
clientRecs
clientReps

// good
recordsOfClients
clientRepositories

Avoid using numbers in names. There is usually a better way of naming if you think how each entity differentiate from the other numbered entities.

// bad
person1
person2
person3

// good
personThatExists
personsFriendThatExists
personToBeInvited

Avoid commonly misspelled words. Typing errors are common, but if you need to Google for variable names, you know your naming is suboptimal.

// bad
development
conscious
privilege

Avoid meaningless words in names. Context usually provides ways to name them better.

// bad
data
info
value
Handler
HandleCalculation()
ProcessInput()

Avoid misleading names. Especially variables with their type in the name.

// bad if not an array
accountArray

Variable name length should depend on the scope it is being used. You may shorten the name if the variable scope is short and reader can understand the contents from the context. Simple three line loop iterator can be name i where as you should not name global constant I or a function parameter i.

// bad
I.getInstance().initialize();

// good
var sum = 0;
var len = counts.length;
for (var i = 0; i < len; i++) {
    sum += counts[i];
}

Variable names should be less than 15 characters. Prefer short names but make them as long as it is required to keep their intent clear in the context they are used.

// bad
Address

// good
PostalAddress
MAC
URL

Boolean variables should be named after yes/no questions. Prefix name with is, has, are or something similar.

// bad
var errorHappened = false;

// good
var isError = true;

Use positive names for boolean variables. Negation on a negative boolean name is confusing.

// bad
if not notFound

// good
if found

If you want to use Hungarian notation, use it right. Don't only specify data type but identify category inside that data type. You should only allow a handful of prefixes per file and document them well.

// bad
sName // string
iMax // integer

// good
usName // unsafe string
ssName // safe string
rwMax // row, an integer
xlMin // horizontal coordinates relative to the layout, an integer

Functions should be named after what they do. Function should only do what the name tells, nothing more and nothing less. When named right, a long function name means that the function is too complex.

// Code that should compute report total sums and opens a file for writing.

// bad, does not do what it says
computeReportTotals()
myReportTotals()

// bad, does too much
computeReportTotalsAndOpenFile()

// good
computeReportTotal()
openFile()

Function names should be less than 15 characters and start with a verb. Function names should be as short as possible while still clearly stating what they do.

Most common function verbs should be defined on the project level. Using opposites is a good practice e.g. Add()/Remove() or Show()/Hide().

// Which one to use or are they different things?
setThing
addThing
createThing
constructThing
makeThing

// Which is preferred? Or are they different things?
deleteThing
removeThing
destroyThing
killThing

Class name should always reflect the responsibilities of the class. When class names get long, you know you should split the class. Manager, processor and super are all bad words in class names. They mean that the class is doing too much.

// bad
class ObjectManager {}; // Validates, Serializes and saves objects to database.

// good
class Validator {}; // Validates objects.
class Serializer {} // Serializes objects.
class DbDriver {};  // Saves objects to database.

Files should be named after what they contain. Follow the same letter case. In object-oriented languages, one file usually contain one class. Files that do not contain a single class should not be named like a class.

// bad
// myclass.php / my_class.php
class MyClass
{
    // ...
}
// Template.php
<div><?php echo 'stuff'; ?></div>

// good
// MyClass.php
class MyClass
{
    // ...
}
// template.php
<div><?php echo 'stuff'; ?></div>

Comments

Use documentation standards to clarify your public interfaces. Focus on how they are used, not on the implementation.

JavaDoc, ScriptDoc, PHPDoc

Comment your intent. Implementation comments should tell why you are doing something, not what you are doing. The code itself should explain what you are doing.

// bad
// Check if status flag is 0.
if (account_status == NO_ACCOUNT) {
    // ...
}

// bad
// No account found.
if (account_status == NO_ACCOUNT) {
    // ...
}

// good
// Establishing new account if no account is found.
if (account_status == NO_ACCOUNT) {
    // ...
}

Prefer "good enough" coding by writing TODO-comments. Comment what should or could be improved.

// bad
// TODO: Fix this.

// good
// TODO: You could cache the location names. -Ruksi

Prefer defining or renaming variables over writing a comment. When adding a comment, check if you can fulfil the need for the comment by changing variable names and placement of code lines.

// bad
// Check that does the module from the global list depend on the
// subsystem we are part of.
if (smodule.getDependSybsystems().contains(subSysMod.getSubSystem())) {
    // ...
}

// good
ArrayList moduleDependees = smodule.getDependSybsystems();
String ourSubSystem = subSysMod.getSubSystem();
if (moduleDependees.contains(ourSubSystem)) {
    // ...
}

Use comments to clarify. Like explaining a regex string.

// U.S. phone number regular expression.
preg_match('/^
    ( \( )?     # optional opening parenthesis
    \d{3}       # the area code
    (?(2) \) )  # if there was opening parenthesis, close it
    [-\s.]?     # followed by - or . or space
    \d{3}       # first 3 digits
    [-\s.]?     # followed by - or . or space
    \d{4}       # last 4 digits
    $/x',
    $number
);

Use comments to warn. Warn about problems that might raise when changing a specific part of the code.

public function login() {
    // Warn: if you change how password hash is checked, change it also
    // in changePassword function!
    // ...
}

Place a blank line before every line comment. Then it is easier to spot comments. Directs programmers to right kind of commenting style, commenting a block of code. Use end of line comments to comment a single line.

// bad
funcCallOne();
funcCallFour(); // This comment applies only to this line.
// Following two are somehow related.
funcCallTwo();
funcCallThree();

// good
funcCallOne();
funcCallFour(); // This comment applies only to this line.

// Following two are somehow related.
funcCallTwo();
funcCallThree();

Commenting shouldn't affect the code layout. Comments shouldn't highlight logical structure but explain why those structures are being used.

// bad
funcCallOne();

// this is the important part here
    funcCallTwo();

    /**
     * this is also important, must do later though,
     * because it uses values we get from second call
     */
        funcCallThree();

// good
funcCallOne();

// this is the important part here
funcCallTwo();

/**
 * this is also important, must do later though,
 * because it uses values we get from second call
 */
funcCallThree();

Avoid flashy comments. Coding convetions must be maintainable. You can create one line "separator comment" e.g. with asterisks * but that should only show that the file contains two or more clearly separate sections of code e.g. multiple classes in a single file.

// bad
/***************************************************************************
* ClassName                                                                *
*                                                                          *
* Requirements: value1 must be positive float                              *
*               value2 must be positive integer                            *
*               function1 must be called after construction                *
*                                                                          *
* Usage: Lorem ipsum                                                       *
*                                                                          *
***************************************************************************/
class ClassName {
    // ...
}

// acceptable
/***************************************************************************
 * You may split the file with horizontal character line only if the file
 * contains multiple classes or otherwise distinct sections.
 */
class ClassName {
    // ...
}

Variables

Use const, final and readonly when possible. If you assume a value won't change, make sure it doesn't change.

Avoid variables with hidden meaning. There are always better solutions.

// bad
// When pageCount is negative, it means error has occurred.
int pageCount;

// good
// throwing an error or returning two variables (error, pageCount)
// where error is null if no error occurred.

Keep variable life-time as short as possible. Declare and define each variable close to where it is first used. Then there is less space between variable definition and use, so you do not lose the context so easily.

// bad
function () {
  var name = getName();
  if (!arguments.length) {
    return false;
  }
  // ... 50 lines of code ...
  doSomething();
  if (name === 'test') {
    return false;
  }
  return true;
}

// good
function () {
  if (!arguments.length) {
    return false;
  }
  // ... 50 lines of code ...
  doSomething();
  var name = getName();
  if (name === 'test') {
    return false;
  }
  return true;
}

Simplify complex conditions with booleans. Name resulting conditions according to what you are testing in the condition.

// bad
if (((string.length > 2) && (string.length < 100)) &&
    (writer.status == WRITER_LOADED) && (formatter !== NULL)
) {
    // ...
}

// good
var isValidInput = ((string.length > 2) && (string.length < 100));
var isValidEnvironment = ((writer.status == 1) && (formatter !== NULL));
if (isValidInput && isValidEnvironment) {
    // ...
}

Use variables to make code more readable. Code is read ten time more often than the code is written. Don't aim to write code fast, aim so the code can be read fast.

// bad
FieldByName('profit').AsFloat
    := ((100 - qPrice.FieldByName('salePrice').AsFloat)
    / 100
    * qPrice.FieldByName('price').AsFloat
    - FieldByName('price').AsFloat)
    /(1 + qProduct.FieldByName('vatPercent').AsFloat / 100);
FieldByName('profitPercent').AsFloat
    := (qProduct.FieldByName('price').AsFloat
    - FieldByName('price').AsFloat)
    / qProduct.FieldByName('price').AsFloat
    * 100;

// good
SaleMultiplier := (100 - qPrice.FieldByName('salePrice').AsFloat) / 100;
SellPrice := qPrice.FieldByName('price').AsFloat;
BuyPrice := FieldByName('price').AsFloat;
VatDivisor := (1 + qProduct.FieldByName('vatPercent').AsFloat / 100);

profitField := Dataset.FieldByName('profit').AsFloat;
profitField := (SaleMultiplier*SellPrice - BuyPrice) / VatDivisor;

profitPercentField := Dataset.FieldByName('profitPercent').AsFloat
profitPercentField := ((SellPrice - BuyPrice) / SellPrice) * 100;

Use enumerated types for readability and reliability. If you find yourself passing multiple boolean values, consider enums.

// bad
if color == 1
if color == "red"

// good
if color == COLOR_RED

Conditionals

Conditional body should always fit on the screen. Optimal length is less than 10 lines. Consider using function calls.

Use switch-statements. If you have an if-statement with more than two else ifs, change it to a switch-statement or consider making separate functions.

Most probable switch-case should come first. Error handling and default values should be on the last case.

Each switch-statement case should have only a two or three lines of code. Consider calling functions.

Loops

Loop body should always fit on the screen. Going past 10 lines should be rare. Consider shortening the loop with function calls.

Understand cases where different loops are meant for:

  • Use while when you don't know repeat count beforehand.
  • Use for when you know the count beforehand; cache that count to a variable.
  • Use foreach and map when you want to operate on each member of a container.

Each loop should only do one thing. Make each loop do only one thing and comment why you wrote the loop.

Consider using safety counters. Break away from possibly infinite loops. Especially if your loop includes something recursive.

var container = new Container();
var safety = 10000;
while (container.hasNext()) {
    safety = safety - 1;
    var next = container.getNext();
    // do something with next...
    if (safety < 0) {
        break;
    }
}

Avoid nesting loops. Never nest more than three loops. Nested loops are hard to read and long running nested loops are one of the few real performance killers.

Functions

Aim for short and simple functions that do one thing. Testing and debugging code that does lots of things is difficult. Optimal function length is less than 10 lines but should rarely be longer than what fits on your screen at once. Absolutely avoid God functions going over 100 lines.

Functions are used to avoid code duplication and reduce complexity. Even a single line function can be good if it simplifies the resulting code.

public int DeviceUnitsToPoints(int deviceUnits)
{
    return deviceUnits * (POINTS_PER_INCH / DeviceUnitsPerInch())
}

Prefer guard statements. Return when you know the answer and further clean-up is not needed. It makes your functions easier to read.

// bad
if (isValid) {
    if (isOpen) {
        if (dataIsUtf8) {
            // ... the operation
        }
        else {
            cleanUp();
        }
    }
    else {
        cleanUp();
        throw new Error('File is not open!');
    }
}
else {
    cleanUp();
}

// good
if (!isValid) {
    cleanUp();
    return;
}
if (!isOpen) {
    cleanUp();
    throw new Error('File is not open!');
}
if (!dataIsUtf8) {
    cleanUp();
    return;
}
// ... the operation

Group similar functions together. Define them near each other.

// good
public function addPerson() {}
public function editPerson() {}
public function removePerson() {}

Define public and high level functions first. For understanding a codebase, top-down approach is more efficient as it provides context why the code exists. In a case where function A that calls function B, A should come before B.

// good
var renderAll = function() {
  _.each(this.collection, this.renderOne);
}
var renderOne = function(model) {
  // ...
}

Avoid recursive functions. Prefer simpler while loops. Especially avoid recursion that calls multiple functions. Recursion can be hard to understand.

Ordering of function parameters matters. Ordering of function parameters should be consistent with other similar functions. If no order has been set, place first the value that changes the function the most. Place optional parameters always last.

Function must use each parameter it requires. If you don't use a parameter in the function, remove the parameter.

Document your public functions. Document all assumptions about the parameters, valid parameter types and range. Document all the possible return values. When a function returns a value, describe it in the name e.g. CurrentColor().

Function never have more than 3 parameters. If a function has 4 or more parameters, split the function or pass in a validated collection with the parameters as members.

// bad
public function updateBook(
    $book_id,
    $author,
    $publish_date_time,
    $genre,
    $length,
    $price,
    $seller = NULL
) {
    // ...
}

// good
// $book contains all parameters as members, some might exist, some might not,
// but will throw errors.
public function updateBook($book) {
    // ...
}

Avoid passing boolean flags to public functions. Then the function automatically does two different things. Consider splitting public interface to two separate functions and optionally use more generic version internally.

// bad
render($isSuite);

// good
if ($isSuite) {
    renderForSuite();
}
else {
    renderForSingleTest();
}

Classes

Classes should do as little as possible. Do not count the lines of code, count number of responsibilities the class has. Even two methods can be too much if the class has multiple responsibilities. When a class has more than 7 member data variables, consider splitting it up.

// bad, clearly clashing responsibilities if both implemented in one class
getLastElement
getMajorVersionNumber.

Keep the public interface clean. Hide all the implementation details. Define all member data and functions as private and raise the visibility level only when needed.

// bad, shows the internal implementation
float x;

// good
float GetX();
void SetX(float x);

Only pass simple data and simple objects between classes. When you are passing complex objects from a class to class, you create tight coupling between those classes and the passed object.

Use data containers. Data containers are behaviorless classes that have a responsibility to group information together. Depends on language you are writing but most of the time, initializing new objects is not expensive. You can easily expand the class with a little of data specific behavior e.g. validation, logging, printing.

public class PostalAddress {
    private String street;
    private String city;
    private String state;
    private String zip;

    public PostalAddress(String street, String city, String state, String zip) {
        this.street = street;
        this.city = city;
        this.state = state;
        this.zip = zip;
    }

    public String getStreet() {
        return this.street;
    }

    public String getCity() {
        return this.city;
    }

    public String getState() {
        return this.state;
    }

    public String getZip() {
        return this.zip;
    }
}

Learn the basic principles of inheritance:

  • If two classes share common data but have different behavior, include the same data container object in the both of them.
  • If two classes share common behavior but use different data, derive both classes from a base class with common methods.
  • If two classes share common data and behavior, derive both classes from a base class with common variables and methods.
  • Inherit when you want the base class to control the interface.
  • Contain when you want to control the interface.

Error Handling

Dead programs tell no lies.

Error handling is a project wide decision. You should announce your main error handling mechanisms to the whole development team at the early stages of development.

Team > Language > Framework > Library > You. Prefer following the error handling style defined by the programming language creators or your major libraries. Consider wrapping libraries that have different error handling mechanisms to keep the behavior unified.

Understand your choices. If you end up having to decide the error handling mechanism for yourself, learn what different error handling mechanisms are at your disposal. The most common error handling styles are:

  • Error Returns: are the best if the error can happen in normal usage. We do not want to crash automatically if the error happens. I personally prefer error returns as the resulting code has less nesting than try-catch-blocks.
  • Exceptions: should be used if the error should not happen, but might. We want to get notified immediately if one happens, so it can be fixed. It is a good practice to use exceptions for conditions that cannot be addressed or are troublesome to address by other coding practices e.g. errors in a third party library.
  • Asserts: are not really error handling but used to specify assumptions that the programmer had about the program. If those assumptions are incorrect, system should notify about it and crash.
Opening file that should exist on every Unix installation.
-> Throw exception if it does not exist.

Opening file that you just created successfully.
-> Throw exception if it does not exist.

Opening user inputted file.
-> Return an error response if it does not exist.

Lower level functions should return error responses. Higher you get, more likely you are better of using just logging.

Prefer crashing over undefined behavior. Use at least asserts to make sure that you assumptions are correct.

Keep error check as short as possible. Provide helpers and establish common conventions. If error checks are tiresome to write, they will be written less frequently.

// bad
return HTTP::response.new(code='404')

// good
if (rc < 0) return rc;
return 404 // webserver that sends not found

The container may try to fix the errors itself. If the routine or class can potentially fix the error itself, do not throw the exception any further until you have tried to fix it.

Never use exceptions as a control flow. I've seen exceptions been used as 21st century GOTO statements. It wasn't pretty.

Include human readable information about the error. Applies to all exceptions, error responses and asserts. Include in all information that led to the exception. Developers must know understand what caused the error.

Avoid using NULL, FALSE, integer or string as an error response. If a library you are using is returning a NULL on error, wrap that to throw an exception or return an Error object. Unify all error responses as soon as possible by wrapping them into a single type.

// Returns product VAT percent as an integer.
getVatPercent(productId);

// But what should it respond with if the database connection is not available?

// If it returns NULL, it means that there is no set VAT percent
// as NULL means absence of value.

// If it returns FALSE or string, does not answer to the question, but might
// be valid answer in some other function context e.g. hasVatPercent or
// getProductName.

// If it returns 0, or -1, might be valid VAT percent in some context.

// You should either throw an error or return an object of class/type Error.
// If the language supports multiple return values, using
// an error as the second return (Error object or NULL), is the most optimal.

Debugging

Bugs are the programmer's own fault most of the time. Always blame yourself first, not co-worker, database, library or external library. Typos are usual cause.

It is a lot easier to avoid bugs than to fix them. Use formal inspection, prototyping, execution testing, code inspections and set compilers on strict mode.

Bugs grow and reproduce when they age. The earlier you find a bug, the easier it is to repair. The sooner you fix the bug, the less side effects if will have. If there is a bug that was hidden for a while, there probably are multiple lurking around.

Reproduce, learn, find cause, fix. To fix a bug, first learn to reproduce the bug so you can test it. Then learn how the program works, find and fix the cause, do not just patch the symptoms. Do not fix a bug by guessing, you are only making it worse in the long run. Use divide and conquer to find cause of bugs.

1. Identify module that causes the bug with logs, break points or printing.
2. Place a print middle way to the first function that handles the buggy value.
3. Go to middle of next function if still valid, but go quarter back
   to the start of the function if values is already bugged.
4. I think you get the idea. Basic binary search.

Sources