Coding Standards
Some consistent code writing style that I’m used to.
Mecha mostly contains CSS, HTML, JavaScript, JSON, PHP, and YAML files. Mecha is open-source where anyone can contribute to the code. The purpose of these coding standards is to make the source code appear as if it was written by one person.
The core application will probably be much more restrictive so there’s not much you can contribute to it. However, Mecha can be enriched by extensions and layouts which you are free to develop without my intervention. You will probably have a popular extension and/or layout in the future and it is not impossible that I will also contribute to your code. And when I write the codes, they will most likely look like these.
CSS
TL;DR
- Braces with control statement.
- Space after property colon.
- Space after comma.
- Space before control statement.
aaa {
bbb: ccc;
ddd: eee;
}
@aaa (bbb: ccc) {
ddd {
eee: fff;
}
}
Color
Always use HEX color code to declare a solid color, and RGBA color code to declare a color with opacity. Always use lower-case letter, and use the shortest color code version:
button {
background-color: #b4d455;
border-color: rgba(255, 255, 0, 0.5);
color: #def;
}
Declaration
Sort declarations alphabetically, unless you want to override the previous declaration:
button {
border: 1px solid #000;
border-top-width: 0;
margin-left: 1px;
margin-right: 1px;
}
Fraction Value
Always include zero prefix in fractions:
button {
margin: 1.25em;
padding: 0.25em 0.5em;
}
Indentation
Use two <Space>
s to represent single indent:
@media print {
.hidden-print {
display: none;
}
}
Key-Value Pairs
Add a <Space>
after colon:
@media (max-width: 1024px) {
body {
font-size: 80%;
}
}
Pseudo Class
Pseudo classes don’t have to be in alphabetical order. In common, they will be ordered like this:
button {}
button:focus {}
button:hover {}
button:active {}
But you can also order them like this to make sure that focus state will remain as-is when hovered:
button {}
button:hover {}
button:focus {}
button:active {}
Be sure to put disabled states at the end, so it will be easier to override other states:
input {}
input:hover {}
input:focus {}
input:active {}
input:valid {}
input:invalid {}
input:read-only {}
input:disabled {}
Selector
Add a line-break after comma, sort selectors alphabetically:
h1,
h2,
h3,
h4,
h5,
h6 {}
Use single quote for attribute selector value, and for non-empty string value. Use double quote for empty string value (except for @charset
rule value that must be using double quote):
@charset "utf-8";
@import url('./style.css');
[rel='nofollow']::before {
background-image: url('./image.jpg');
content: "";
}
Semi-Colon
Ensure semi-colon at the end of declaration:
body {
margin-bottom: 1px;
margin-top: 1px;
}
Zero Value
Remove unit in zero values except 0%
and 0deg
:
body {
margin: 0 0 1px 1px;
margin-top: 0%;
}
HTML
Attribute and Name
Use lower-case letter, sort attributes alphabetically:
<input class="input" id="input-0" name="input-0" type="text">
Attribute’s Value
Always use double quote, even on empty value:
<img alt="" src="./image.jpg">
Exception for attribute that contains JSON or JavaScript commands:
<div class="gallery" data-state='{"caption":true,"overlay":true}'></div>
Sort class and inline style values:
<div class="bar baz foo" style="bar: 1; baz: 4; foo: 0;"></div>
Boolean Attribute
Always remove values:
<button disabled type="submit">
Indentation
Use two <Space>
s to represent single indent:
<ul>
<li></li>
<li></li>
</ul>
Void Element
Do not add /
before >
in void elements:
<img alt="" src="/photo.jpg">
<hr>
JSON
Indentation
Use two <Space>
s to represent single indent:
{
"foo": "bar",
"baz": [1, 2, 3]
}
JavaScript
TL;DR
- Braces with control statement.
- Space after object property colon.
- Space after comma.
- Space after function keyword.
- Space before control statement.
function aaa() {}
if (bbb) {
ccc();
} else {
ddd();
}
switch (eee) {
case fff:
case ggg:
hhh();
break;
}
try {
iii();
} catch (jjj) {
kkk();
}
while (lll) {
mmm();
}
const nnn = function () {};
Comparison
Use Yoda notation in equal/not-equal comparison to quickly detect typos:
if (-1 !== pairs.indexOf(pair)) {}
Fraction Value
Always include zero prefix in fractions:
const opacity = 0.5;
Function
Use parseFloat()
and parseInt()
sparingly, simply prefix your variable with a +
sign if you know that the value will always be a valid number:
const value = input.value;
// :(
console.log(parseFloat(value));
// :)
console.log(+value);
Increment/Decrement
Prefers pre-increment/decrement over post-increment/decrement; always cache the data length before iteration using for
loop:
// :(
for (let i = 0, j = data.length; i < j; i++) {}
// :)
for (let i = 0, j = data.length; i < j; ++i) {}
Indentation
Use four <Space>
s to represent single indent:
function foo(bar = 'baz') {
return bar ?? 'qux';
}
Operator
Always add a <Space>
around operators:
let value = a + b * (1 / (c - 2));
let value = a + 'asdf' + b;
value += 'asdf';
value += 'asdf';
String
Use single quote for non-empty string or for string that contains "
character, so you don’t have to escape. Use double quote for empty string or for string that contains '
character, so you don’t have to escape:
'asdf'
"asdf's"
""
'"asdf"'
'"asdf\'s"'
"'asdf'"
"'asdf\"s'"
Only use backtick-style string for templating. E.g. to write a block of CSS and HTML snippet in a JavaScript file.
Variable
Join multiple variables, unless its indentation looks ugly such as when used with const
, or when making undefined variables. Sort them aplhabetically where possible:
let bar = 1,
baz = 2,
x, y, z;
const bar = 1;
const baz = 2;
PHP
TL;DR
- Braces with control statement.
- Space after comma.
- Space after property colon.
- Space after function and use keyword.
- Space before control statement.
function aaa() {}
if ($bbb) {
ccc();
} else {
ddd();
}
switch ($eee) {
case $fff:
case $ggg:
hhh();
break;
}
try {
iii();
} catch (Throwable $jjj) {
kkk();
}
while ($lll) {
mmm();
}
$nnn = static function () use ($mmm) {};
Class
Order constants, methods and properties alphabetically, including the visibility state:
class Foo implements A, B, C {
private function _internal() {}
public function get() {}
public function let() {}
public function set() {}
public function __construct() {}
public static function __callStatic() {}
}
Comparison
Use Yoda notation in equal/not-equal comparison to quickly detect typos:
if (false !== strpos($foo, $bar)) {}
Fraction Value
Always include zero prefix in fractions:
$opacity = 0.5;
Function
Use is_dir()
or is_file()
instead of file_exists()
:
// :(
if (file_exists($path)) {}
// :)
if (is_file($path)) {}
If you just want to check whether a path does exist, use stream_resolve_include_path()
instead of file_exists()
:
// :(
if (file_exists($path)) {}
// :\
if (is_dir($path) || is_file($path)) {}
// :)
if (stream_resolve_include_path($path)) {}
Use strtr()
instead of str_replace()
:
// :(
echo str_replace('a', 'b', $value);
echo str_replace('a', "", $value);
echo str_replace(['a', 'b'], ['c', 'd'], $value);
echo str_replace(['aa', 'bb'], ["", ""], $value);
// :)
echo strtr($value, 'a', 'b');
echo strtr($value, ['a' => ""]);
echo strtr($value, 'ab', 'cd');
echo strtr($value, [
'aa' => "",
'bb' => ""
]);
If you know that a path exists, use stream_resolve_include_path()
to normalize the path instead of realpath()
:
$path = stream_resolve_include_path($path);
If you just want to escape/un-escape HTML, use htmlspecialchars()
and htmlspecialchars_decode()
instead of htmlentities()
:
// :(
echo '<input value="' . htmlentities($value) . '">';
// :)
echo '<input value="' . htmlspecialchars($value) . '">';
Prefers static anonymous function if $this
context is not used:
$map = static function (array $array, callable $fn) {
foreach ($array as &$v) {
$v = $fn($v);
}
unset($v);
return $array;
};
Do not use count()
to detect empty array, and strlen()
to detect empty string. These should be enough:
if (!$array) {}
if ("" === $string) {}
Increment/Decrement
Prefers pre-increment/decrement over post-increment/decrement; always cache the data length before iteration using for
loop:
// :(
for ($i = 0, $j = count($data); $i < $j; $i++) {}
// :)
for ($i = 0, $j = count($data); $i < $j; ++$i) {}
Indentation
Use four <Space>
s to represent single indent:
function foo(string $bar = 'baz') {
return $bar ?? 'qux';
}
Language Construct
Use isset()
sparingly:
// :(
echo '<' . $m[1] . (isset($m[2]) ? $m[2] : "") . '>';
// :)
echo '<' . $m[1] . ($m[2] ?? "") . '>';
Do not use empty()
to detect empty string. Use empty()
as a shortcut for !(isset($var) && $var)
:
$name = $_POST['name'] ?? "";
// :(
// If `$name` contains `0` string, this will return `true`
if (empty($name)) {}
// :)
// Use `trim()` as a guard, since even a single space is not considered empty
if ("" !== trim($name)) {}
// :)
// You don’t have to use `empty()` to detect empty array. This should be enough!
if (!$array) {}
Use empty()
and isset()
only to detect undefined variable as a whole.
Markup
Always think of PHP statements as other kind of HTML markup. They should get the same indentation treatment as the surrounding HTML markup.
<!-- :( -->
<h1>
<a href="<?= $link; ?>"><?= $title; ?></a>
</h1>
<!-- :) -->
<h1>
<a href="<?= $link; ?>">
<?= $title; ?>
</a>
</h1>
<!-- :( -->
<?php foreach ($pages as $page): ?>
<article>
<h2><?= $page->title; ?></h2>
<div><?= $page->content; ?></div>
</article>
<?php endforeach; ?>
<!-- :) -->
<?php foreach ($pages as $page): ?>
<article>
<h2>
<?= $page->title; ?>
</h2>
<div>
<?= $page->content; ?>
</div>
</article>
<?php endforeach; ?>
Operator
Always add a <Space>
around operators:
$value = $a + $b * (1 / ($c - 2));
$value = $a . 'asdf' . $b;
$value .= 'asdf';
$value .= 'asdf';
Output
Use echo
or not at all. Always add a semi-colon at the end of declaration, even if you are using the <?=
syntax:
<h1>
<?php
$title = do_task(1);
$title .= do_task(2);
$title .= do_task(3);
echo $title;
?>
</h1>
<h1>
<?= $title; ?>
</h1>
String
Use single quote for non-empty string or for string that contains "
character, so you don’t have to escape. Use double quote for empty string or for string that contains '
character, so you don’t have to escape:
'asdf'
"asdf's"
""
'"asdf"'
'"asdf\'s"'
"'asdf'"
"'asdf\"s'"
Only use HEREDOC-style string for templating. E.g. to write a block of CSS and HTML snippet in a PHP region.
Always store HEREDOC string in a variable to overcome our first home-made PHP minifier bug.
// :(
echo implode("\n", ['<b></b>', <<<HTML
<div></div>
HTML
]);
// :)
$content = <<<HTML
<div></div>
HTML;
echo implode("\n", ['<b></b>', $content]);
Variable
Combine all variables with the same predefined value into one line. Sort them alphabetically:
$current = $next = $prev = "";
SQL
Function
Always use lower case letters:
SELECT count(*) AS "count" FROM "page" WHERE "x" = 'draft';
SELECT coalesce(max("id"), 0) + 1 AS "next_id" FROM "page";
SELECT raise(ABORT, 'Route already exists.');
Indentation
Use two <Space>
s to represent single indent:
SELECT
*
FROM
"page"
WHERE
"id" = 1
AND
"parent" IS NULL
;
Key-Value Pairs
Always add a <Space>
around operators and separators:
SELECT "content", "title" FROM "page" WHERE "name" = 'lorem-ipsum';
Variable
Always use double quotes to wrap variables:
SELECT "select" FROM "from" WHERE "where" = 'foo-bar';
Value
Always wrap literal text values in single quotes to ensure that they will not be interpreted as variables:
SELECT "foo" FROM "foo" WHERE "foo" = 'foo';
YAML
Fraction Value
Always include zero prefix in fractions:
opacity: 0.5
Indentation
Use two <Space>
s to represent single indent:
foo:
bar: 1
baz: 2
qux: 3
Do not indent sequence list:
# :(
foo:
- bar
- baz
- qux
# :)
foo:
- bar
- baz
- qux
Key-Value Pairs
Enclose values containing special characters in quotation marks:
foo: Bar Baz
qux: 'foo@bar.baz'
String
Use single quote for non-empty string or for string that contains "
character, so you don’t have to escape. Use double quote for empty string or for string that contains '
character, so you don’t have to escape:
foo:
bar: 'http://example.com'
baz: ""
To be continued… 🧠
Coding Standards
Some consistent code writing style that I’m used to.
Editor Settings
Various settings for code editors that might be used to develop Mecha.
Naming Conventions
Naming conventions and their reasons.