Skip to content
This repository has been archived by the owner on Aug 30, 2022. It is now read-only.

Latest commit

 

History

History
285 lines (218 loc) · 6.86 KB

README.md

File metadata and controls

285 lines (218 loc) · 6.86 KB

General coding standards

This document contains the preferred coding style regardless of language. The examples below will be in PHP, but the accompanying rules work for Javascript or Ruby as well.

Whitespace

At its most basic, we generally prefer to not cram everything together. Use whitespace around parentheses, variables, and operators. Example:

class Garp_FiddleStick {
    public function __construct($foo, $bar = null) {
        if ($foo >= 10000) {
            doSomething();
        }
        $this->_property = $foo;

        if ($bar) {
            $this->_id = 1000 + $bar;
        }
    }

    public function loopDeLoop() {
        for ($i = 0; $i < count($this->_data); ++$i) {
            dump($this->_data[$i]);
        }
    }
}

Indentation

We use spaces for indentation.

  • 2 spaces for Javascript
  • 4 spaces for the rest

Set your editor to replace your tabs with spaces before you're saving it in a Garp project. An example for why we use spaces instead of tabs is for instance this docblock:

/**
 * @param array $data      Content of new record
 * @param bool  $overwrite Whether to overwrite existing records.
 */

Will be all screwed up if aligned using tabs. Different contexts render tabs differently, so do not rely on them.

Same goes for aligning things like variable declarations:

$blue   = 'Leonardo';
$red    = 'Rafael';
$orange = 'Michaelangelo';
$purple = 'Donatello';

Just use spaces. (a good Vim plugin to help with this is Tabular)

Line-length

Try to keep your lines readable. We stick to a line limit of 100 characters, but we do not enforce it - in case of urls and such.

Use Husky for hooks whenever possible.

In Vim you can enforce this/make this more visible using:

set textwidth=100
set colorcolumn=+1

In Atom you can make this visible by setting Preferred Line Length to 100 under Settings > Editor.

Private methods

Prefix private or protected methods and properties with an underscore:

protected $_data = array();

protected function _doSomething() {
}

Also, generally we prefer protected over private.

Function arguments

Try not to use more than three (3) arguments in a function or method definition:

// BAD
function fetchFiltered($page, $limit, $color, $brand, $group, $something, $else, $etc) {
    // ...
}

Convert to a parameter object (or array):

// GOOD
function fetchFiltered(array $params) {
    $page = $params['page'];
    // et cetera
}

See also "Introduce Parameter Object".

Argument line distribution

When calling function and spreading arguments over multiple lines, you should place all arguments on a separate line, not some. Especially not when the first argument is a closure or array and the second a wee scalar value.

// NOT LIKE THIS:
doTheThing(function ($foo) {
  return $this->manipulateTheVar($foo);
}, $poo);

// LIKE THIS:
doTheThing(
  function ($foo) {
    return $this->manipulateTheVar($foo);
  },
  $poo
);

Arrays

Try to write array/object/dictionary properties on new lines:

$abc = [
    'pork' => 'butts',
    'beef' => 'cake',
    'fruit' => 'loop'
];

Switch

If you have to use a switch, align the case and break statements:

switch ($breakfast) {
    case 'cereal':
        // ...
    break;
    case 'bacon':
        // ...
    break;
    default:
        // ...
    break;
}

Also, remember that cool kids use Replace Conditional With Polymorphism.

Curlies

Even though it's allowed to omit curly braces for one-liners, we generally prefer to always use them.

if (!array_key_exists('Leonardo', $ninjaTurtles)) array_push($ninjaTurtles, 'Leonardo');

The reasoning for this is that it's easier to add lines in the future:

if (!array_key_exists('Leonardo', $ninjaTurtles)) {
    array_push($ninjaTurtles, 'Leonardo');
    debug('Leonardo missing');
}

Names

We prefer CamelCase for identifiers, but in Ruby you are allowed to use the underscored notation.

Don't abbreviate

In general, prefer longer variable and method names over short variable names. This is not algebra, we're not trying to find x.

Usually there's a proper semantic name for whatever value you're working with.

Comments

Comments are added with the best of intentions, obviously. But take a moment to consider whether you can make the code self-explanatory before adding a comment. Maybe your variable names are ambiguous? Maybe your function parameters can be made a little bit more clear?

If you absolutely must, write a clear comment, use proper capitalisation and punctuation. We're not bloody animals.

Functional programming

No hard and fast rules here, but try to stick to the following:

  • Prefer maps/filters/reductions over looping
  • Prefer immutable data

Object Calisthenics

At GRRR, we practice Object Calisthenics. Generally, the most important bits are:

Only one level of indentation per method

Most commonly violated in loops:

public function listTurtles() {
    foreach ($turtles as $turtle) {
        if ($turtle->hasWeapons()) {
            foreach ($turtle->getWeapons() as $weapon) {
                echo "{$turtle->name} uses weapon: {$weapon->name}";
            }
        }
    }
}

Can be fixed using something like:

public function listTurtles() {
    $output = '';
    foreach ($turtles as $turtle) {
        $output .= $this->getOutput($turtle);
    }
    echo $output;
}

public function getOutputForTurtle($turtle) {
    if (!$turtle->hasWeapons()) {
        return;
    }
    $output = '';
    foreach ($turtle->getWeapons() as $weapon) {
        $output .= "{$turtle->name} uses weapon: {$weapon->name}";
    }
    return $output;
}

Don't use the ELSE keyword

Don't use this:

function getBreakfast() {
    if ($this->guest->isVegetarian()) {
        $bowl = new CerealBowl();
        $bowl->add($nuts);
        $bowl->add($berries);
        $bowl->add($milk);
        $breakfast = $bowl;
    } else {
        $breakfast = new Bacon();
    }
    return $breakfast;
}

Use an early return:

function getBreakfast() {
    if (!$this->guest->isVegetarian()) {
        return new Bacon();
    }
    $bowl = new CerealBowl();
    $bowl->add($nuts);
    $bowl->add($berries);
    $bowl->add($milk);
    return $bowl;
}

Conditional assignment

By extension, use a ternary operator when assigning a variable to one or another value:

const foo = yepNope ? 42 : 84;

It's immediately clear this is a single statement, being the assignment, whereas an if / else statement requires you to inspect the contents of the different blocks to see what's going on.