Log in | Back to darenet.org

Web Development

m (Indentation)
m (Code Complexity)
 
(23 intermediate revisions not shown)
Line 1: Line 1:
-
Here we'll attempt to explain the process we'll be using to develop the next generation of the DareNET web site. We will rely heavily on community interaction, whether through the forums or on IRC (#dev). IRC is perhaps the best place to find members of the development team and discuss ideas, latest code and make general comments.
+
{{Header|1 = <h2>'''[[Development Team|DareNET Development Wiki]]''' - {{FULLPAGENAME}}</h2>}}
 +
This document contains practices and guidelines which apply across languages. Contributors should follow these guidelines. These guidelines are not hard-and-fast but should be followed unless there is a compelling reason to deviate from them.
-
We'll maintain 3 versions of the site.
+
==Code Complexity==
 +
* Prefer to write simple code which is easy to understand. The simplest code is not necessarily the smallest, and some changes which make code larger (such as decomposing complex expressions and choosing more descriptive names) may also make it simpler.
 +
* Be willing to make size tradeoffs in favor of simplicity.
 +
* Prefer simple methods and functions which take a small number of parameters. Avoid methods and functions which are long and complex, or take an innumerable host of parameters. When possible, decompose monolithic, complex methods into several focused, simpler ones.
-
* '''stable''' - for production (the version used on the main site) where stability is more important than features.
+
Avoid putting many ideas on a single line of code.
-
* '''trunk''' - development version where features are important and stability is necessary.
+
-
* '''branches''' - for testing, and development members interested in the most advanced feature set and willing to refine them some.
+
-
<br>
+
-
== Coding Standards ==
+
-
=== Adding New Features ===
+
For example, avoid this kind of code:
-
No new features should be added to trunk, without having their own tests - which should be passed before committing them to the repository. Any additions to stable should undergo a team vote.
+
<pre>$category_map = array_combine(
 +
  $dates,
 +
  array_map(create_function('$z', 'return date("F Y", $z);'), $dates));</pre>
-
=== Indentation ===
+
Expressing this complex transformation more simply produces more readable code:
-
One tab will be used for indentation.
+
-
So, indentation should look like this:
+
<php>$category_map = array();
 +
foreach ($dates as $date) {
 +
  $category_map[$date] = date('F Y', $date);
 +
}</php>
-
<source lang="php" line start=1 >
+
And, obviously, don't do this sort of thing:
-
<?php
+
-
// base level
+
-
    // level 1
+
-
        // level 2
+
-
    // level 1
+
-
// base level
+
-
?>
+
-
</source>
+
-
Or:
+
<pre>if ($val = $some->complicatedConstruct() && !!~blarg_blarg_blarg() & $flags
 +
      ? HOPE_YOU_MEMORIZED == $all_the_lexical_binding_powers : <<<'Q'
 +
${hahaha}
 +
Q
 +
);</pre>
-
<source lang="php" line start=1 >
+
==Performance==
-
$booleanVariable = true;
+
* Prefer to write efficient code.
-
$stringVariable = "moose";
+
* Strongly prefer to drive optimization decisions with hard data. Avoid optimizing based on intuition or rumor if you can not support it with concrete measurements.
-
if ($booleanVariable)
+
* Prefer to optimize code which is slow and runs often. Optimizing code which is fast and runs rarely is usually a waste of time, and can even be harmful if it makes that code more difficult to understand or maintain. You can determine if code is fast or slow by measuring it.
-
{
+
* Reject performance discussions that aren't rooted in concrete data.
-
  echo "Boolean value is true";
+
-
  if ($stringVariable == "moose")
+
-
  {
+
-
    echo "We have encountered a moose";
+
-
  }
+
-
}</source>
+
-
===Function Calls===
+
==Naming Things==
-
Functions should be called without space between function's name and starting bracket. There should be one space between every parameter of a function call.
+
* Follow language-specific conventions.
 +
* Name things unambiguously.
 +
* Choose descriptive names.
 +
* Avoid nonstandard abbreviations (common abbreviations like ID, URI and HTTP are fine).
 +
* Spell words correctly.
 +
* Use correct grammar.
-
<source lang="php" line start=1 ><?php
+
For example, avoid these sorts of naming choices:
-
$var = foo($bar, $bar2, $bar3);
+
-
?></source>
+
-
As you can see above there should be one space on both sides of equals sign (=). To increase the readability of the code you can add spaces (or tabs) before the equals sign, but only in the case of a multiple function call presented below:
+
<pre>$PIE->GET_FLAVOR();      //  Unconventional.
 +
$thing->doStuff();        //  Ambiguous.
 +
$list->empty();          //  Ambiguous -- is it isEmpty() or makeEmpty()?
 +
$e = 3;                  //  Not descriptive.
 +
$this->updtHndlr();      //  Nonstandard abbreviation.
 +
$this->chackSpulls();    //  Misspelling, ungrammatical.</pre>
-
<source lang="php" line start=1 ><?php
+
Prefer these:
-
$varShort = foo($bar1);
+
-
$variableLong = foo($bar1);
+
-
?></source>
+
-
=== Commenting Code ===
+
<php>$pie->getFlavor();        //  Conventional.
 +
$pie->bake();            //  Unambiguous.
 +
$list->isEmpty();        //  Unambiguous.
 +
$list->makeEmpty();      //  Unambiguous.
 +
$edge_count = 3;          //  Descriptive.
 +
$this->updateHandler();  //  No nonstandard abbreviations.
 +
$this->getID();          //  Standard abbreviation.
 +
$this->checkSpelling();  //  Correct spelling and grammar.</php>
-
All comments should be written in English, and should in a clear way describe the commented block of code.
+
==Error Handling==
 +
* Strongly prefer to detect errors.
 +
* Strongly prefer to fail fast and loudly. The maximum cost of script termination is known, bounded, and fairly small. The maximum cost of continuing script execution when errors have occurred is unknown and unbounded. This also makes APIs much easier to use and problems far easier to debug.
-
Comments can include the following phpDocumentor tags:  
+
When you ignore errors, defer error handling, or degrade the severity of errors by treating them as warnings and then dismissing them, you risk dangerous behavior which may be difficult to troubleshoot:
-
* [http://manual.phpdoc.org/HTMLframesConverter/phpdoc.de/phpDocumentor/tutorial_tags.access.pkg.html @access]
+
<pre>exec('echo '.$data.' > file.bak');                // Bad!
-
* [http://manual.phpdoc.org/HTMLframesConverter/phpdoc.de/phpDocumentor/tutorial_tags.author.pkg.html @author]
+
do_something_dangerous();
-
* [http://manual.phpdoc.org/HTMLframesConverter/phpdoc.de/phpDocumentor/tutorial_tags.copyright.pkg.html @copyright]
+
-
* [http://manual.phpdoc.org/HTMLframesConverter/phpdoc.de/phpDocumentor/tutorial_tags.deprecated.pkg.html @deprecated]
+
-
* [http://manual.phpdoc.org/HTMLframesConverter/phpdoc.de/phpDocumentor/tutorial_tags.example.pkg.html @example]
+
-
* [http://manual.phpdoc.org/HTMLframesConverter/phpdoc.de/phpDocumentor/tutorial_tags.ignore.pkg.html @ignore]
+
-
* [http://manual.phpdoc.org/HTMLframesConverter/phpdoc.de/phpDocumentor/tutorial_tags.internal.pkg.html @internal]
+
-
* [http://manual.phpdoc.org/HTMLframesConverter/phpdoc.de/phpDocumentor/tutorial_tags.link.pkg.html @link]
+
-
* [http://manual.phpdoc.org/HTMLframesConverter/phpdoc.de/phpDocumentor/tutorial_tags.see.pkg.html @see]
+
-
* [http://manual.phpdoc.org/HTMLframesConverter/phpdoc.de/phpDocumentor/tutorial_tags.since.pkg.html @since]
+
-
* [http://manual.phpdoc.org/HTMLframesConverter/phpdoc.de/phpDocumentor/tutorial_tags.tutorial.pkg.html @tutorial]
+
-
* [http://manual.phpdoc.org/HTMLframesConverter/phpdoc.de/phpDocumentor/tutorial_tags.version.pkg.html @version]
+
-
* [http://manual.phpdoc.org/HTMLframesConverter/phpdoc.de/phpDocumentor/tutorial_tags.inlineinternal.pkg.html inline {@internal}}]
+
-
* [http://manual.phpdoc.org/HTMLframesConverter/phpdoc.de/phpDocumentor/tutorial_tags.inlineinheritdoc.pkg.html inline {@inheritdoc}}]
+
-
* [http://manual.phpdoc.org/HTMLframesConverter/phpdoc.de/phpDocumentor/tutorial_tags.inlinelink.pkg.html inline {@link}}]
+
-
PhpDoc tags are very much like JavaDoc tags in Java. Tags are only processed if they are the first thing in a DocBlock line, for example:
+
exec('echo '.$data.' > file.bak', $out, $err);    /Also bad!
-
<source lang="php" line start=1 >
+
if ($err) {
-
<?php
+
  debug_rlog("Unable to copy file!");
-
/**
+
-
* Tag example.
+
-
* @author this tag is parsed, but this @version is ignored
+
-
* @version 1.0 this tag is also parsed
+
-
*/
+
-
?></source>
+
-
 
+
-
There are 3 inline tags ({@internal}}, {@inheritdoc}} and {@link}}).
+
-
<source lang="php" line start=1 >
+
-
<?php
+
-
/**
+
-
  * Example of inline phpDoc tags.
+
-
*
+
-
* This function works hard with {@link foo()} to rule the world.
+
-
*/
+
-
function bar() {
+
}
}
-
function foo() {
+
do_something_dangerous();</pre>
-
}
+
-
?></source>
+
-
=== Including Files ===
+
Instead, fail loudly:
-
When including files with classes or libraries, use only and always the [http://php.net/require_once require_once] function.
+
<php>exec('echo '.$data.' > file.bak', $out, $err);    //  Better
-
 
+
if ($err) {
-
=== PHP Tags ===
+
  throw new Exception("Unable to copy file!");
-
 
+
-
Always use long tags (<?php ?>) Instead of short tags (<? ?>).
+
-
 
+
-
=== Functions ===
+
-
 
+
-
Write all functions in camel case.
+
-
<source lang="php" line start=1 >
+
-
<?php
+
-
function longFunctionName() {
+
}
}
-
?></source>
+
do_something_dangerous();</php>
-
 
+
-
=== Classes ===
+
-
 
+
-
Class names should be written in CamelCase, for example:
+
-
<source lang="php" line start=1 >
+
-
<?php
+
-
class ExampleClass {
+
-
}
+
-
?></source>
+
-
 
+
-
=== Variables ===
+
-
 
+
-
Variable names should be as descriptive as possible, but also as short as possible. Normal variables should start with a lowercase letter, and should be written in camelBack in case of multiple words. Variables containing objects should start with a capital letter, and in some way associate to the class the variable is an object of. Example:
+
-
<source lang="php" line start=1 >
+
-
<?php
+
-
$user      = 'John';
+
-
$users      = array('John', 'Hans', 'Arne');
+
-
$Dispatcher = new Dispatcher();
+
-
?></source>
+
-
 
+
-
=== Compatibility ===
+
-
 
+
-
Support for PHP 4 was discontinued over a year ago. We will assume the latest stable release of PHP 5 is running, and as such, will write code with that in mind.
+
-
 
+
-
=== Example Addresses ===
+
-
 
+
-
For all example URL and mail addresses use "example.com", "example.org" and "example.net", for example:
+
-
 
+
-
* Email: someone@example.com
+
-
* WWW: http://www.example.com
+
-
* FTP: ftp://ftp.example.com
+
-
 
+
-
=== File Names ===
+
-
 
+
-
File names should be created with lower case. If a file name consist of multiple words, they should be divided by an underscore character, for example:
+
-
 
+
-
<code>long_file_name.php</code>
+
-
 
+
-
=== Variable Types ===
+
-
 
+
-
Variable types for use in DocBlocks:
+
-
 
+
-
{| class="wikitable" width="60%" style="font-size: 85%; text-align: left;"
+
-
|-
+
-
| mixed
+
-
| A variable with undefined (or multiple) type.
+
-
|-
+
-
| integer
+
-
| Integer type variable (whole number).
+
-
|-
+
-
| float
+
-
| Float type (point number).
+
-
|-
+
-
| boolean
+
-
| Logical type (true or false).
+
-
|-
+
-
| string
+
-
| String type (any value in "" or ' ').
+
-
|-
+
-
| array
+
-
| Array type.
+
-
|-
+
-
| object
+
-
| Object type.
+
-
|-
+
-
| resource
+
-
| Resource type (returned by for example mysql_connect()).
+
-
|}
+
-
 
+
-
Remember that when you specify the type as mixed, you should indicate whether it is unknown, or what the possible types are.
+
-
 
+
-
=== Constants ===
+
-
 
+
-
Constants should be defined in capital letters:
+
-
<source lang="php" line start=1 >
+
-
<?php
+
-
define('CONSTANT', 1);
+
-
?></source>
+
-
 
+
-
If a constant name consists of multiple words, they should be separated by an underscore character, for example:
+
-
<source lang="php" line start=1 >
+
-
<?php
+
-
define('LONG_NAMED_CONSTANT', 2);
+
-
?></source>
+
-
 
+
-
== Method Definition ==
+
-
 
+
-
Example of a function definition:
+
-
<source lang="php" line start=1 >
+
-
<?php
+
-
function someFunction($arg1, $arg2 = '') {
+
-
  if (expr) {
+
-
    statement;
+
-
  }
+
-
  return $var;
+
-
}
+
-
?></source>
+
-
 
+
-
Parameters with a default value, should be placed last in function definition. Try to make your functions return something, at least true or false - so it can be determined whether the function call was successful.
+
-
<source lang="php" line start=1 >
+
-
<?php
+
-
function connection(&$dns, $persistent = false) {
+
-
  if (is_array($dns)) {
+
-
    $dnsInfo = &$dns;
+
-
  }
+
-
  else
+
-
  {
+
-
    $dnsInfo = BD::parseDNS($dns);
+
-
  }
+
-
  if (!($dnsInfo) || !($dnsInfo['phpType'])) {
+
-
    return $this->addError();
+
-
  }
+
-
  return true;
+
-
}
+
-
?></source>
+
-
 
+
-
NOTE: There are spaces between the equals (=) sign.
+
-
 
+
-
== Release Checklist ==
+
-
The following is a list of requirements that need to be satisfied when creating a release:
+
But the best approach is to use or write an API which simplifies condition handling and makes it easier to get right than wrong:
-
* Create a change log with clean, readable descriptions, referencing tickets wherever possible.
+
<php>execx('echo %s > file.bak', $data);              //  Good
-
* Changes must be reflected in all written material prior to release.
+
do_something_dangerous();
-
* The code must be tested.
+
-
* The code should always be made available in the following archive formats: .tar.gz
+
-
<nowiki>*</nowiki> ''When referring to code availability, we specifically mean accessibility for team members, not the public. The code source should not be distributed outside of the team. Additionally, the change log should be posted on the development site wiki for easy viewing.''
+
Filesystem::writeFile('file.bak', $data);        //  Best
 +
do_something_dangerous();</php>
-
== Version Scheme ==
+
==Documentation, Comments and Formatting==
 +
* Prefer to remove code by deleting it over removing it by commenting it out. It shall live forever in source control, and can be retrieved therefrom if it is ever again called upon.
 +
* In source code, use only ASCII printable characters plus space and linefeed. Do not use UTF-8 or other multibyte encodings.
-
We will be utilizing the following version scheme for the site:
+
== See Also ==
-
{| class="wikitable" width="60%" style="font-size: 85%; text-align: left;"
+
* [[Web Development/PHP Coding Standards|PHP Coding Standards]]
-
|-
+
* [[Web Development/Javascript Coding Standards|Javascript Coding Standards]]
-
| Major revision:
+
-
| #.0.0.0
+
-
|  Major code changes
+
-
|-
+
-
| Moderate revision:
+
-
| 0.#.0.0
+
-
| Minor code changes
+
-
|-
+
-
| Minor revision:
+
-
| 0.0.#.0
+
-
| Bug fixes - no major code changes
+
-
|-
+
-
| Build:
+
-
| 0.0.0.#
+
-
| Refers to the SVN revision number at the time of the build.
+
-
|}
+

Current revision as of 19:10, 28 July 2011

In This Guide:

DareNET Development Wiki - Web Development

This document contains practices and guidelines which apply across languages. Contributors should follow these guidelines. These guidelines are not hard-and-fast but should be followed unless there is a compelling reason to deviate from them.

Code Complexity

  • Prefer to write simple code which is easy to understand. The simplest code is not necessarily the smallest, and some changes which make code larger (such as decomposing complex expressions and choosing more descriptive names) may also make it simpler.
  • Be willing to make size tradeoffs in favor of simplicity.
  • Prefer simple methods and functions which take a small number of parameters. Avoid methods and functions which are long and complex, or take an innumerable host of parameters. When possible, decompose monolithic, complex methods into several focused, simpler ones.

Avoid putting many ideas on a single line of code.

For example, avoid this kind of code:

$category_map = array_combine(
  $dates,
  array_map(create_function('$z', 'return date("F Y", $z);'), $dates));

Expressing this complex transformation more simply produces more readable code:

$category_map = array();
foreach ($dates as $date) {
  $category_map[$date] = date('F Y', $date);
}

And, obviously, don't do this sort of thing:

if ($val = $some->complicatedConstruct() && !!~blarg_blarg_blarg() & $flags
      ? HOPE_YOU_MEMORIZED == $all_the_lexical_binding_powers : <<<'Q'
${hahaha}
Q
);

Performance

  • Prefer to write efficient code.
  • Strongly prefer to drive optimization decisions with hard data. Avoid optimizing based on intuition or rumor if you can not support it with concrete measurements.
  • Prefer to optimize code which is slow and runs often. Optimizing code which is fast and runs rarely is usually a waste of time, and can even be harmful if it makes that code more difficult to understand or maintain. You can determine if code is fast or slow by measuring it.
  • Reject performance discussions that aren't rooted in concrete data.

Naming Things

  • Follow language-specific conventions.
  • Name things unambiguously.
  • Choose descriptive names.
  • Avoid nonstandard abbreviations (common abbreviations like ID, URI and HTTP are fine).
  • Spell words correctly.
  • Use correct grammar.

For example, avoid these sorts of naming choices:

$PIE->GET_FLAVOR();       //  Unconventional.
$thing->doStuff();        //  Ambiguous.
$list->empty();           //  Ambiguous -- is it isEmpty() or makeEmpty()?
$e = 3;                   //  Not descriptive.
$this->updtHndlr();       //  Nonstandard abbreviation.
$this->chackSpulls();     //  Misspelling, ungrammatical.

Prefer these:

$pie->getFlavor();        //  Conventional.
$pie->bake();             //  Unambiguous.
$list->isEmpty();         //  Unambiguous.
$list->makeEmpty();       //  Unambiguous.
$edge_count = 3;          //  Descriptive.
$this->updateHandler();   //  No nonstandard abbreviations.
$this->getID();           //  Standard abbreviation.
$this->checkSpelling();   //  Correct spelling and grammar.

Error Handling

  • Strongly prefer to detect errors.
  • Strongly prefer to fail fast and loudly. The maximum cost of script termination is known, bounded, and fairly small. The maximum cost of continuing script execution when errors have occurred is unknown and unbounded. This also makes APIs much easier to use and problems far easier to debug.

When you ignore errors, defer error handling, or degrade the severity of errors by treating them as warnings and then dismissing them, you risk dangerous behavior which may be difficult to troubleshoot:

exec('echo '.$data.' > file.bak');                //  Bad!
do_something_dangerous();

exec('echo '.$data.' > file.bak', $out, $err);    //  Also bad!
if ($err) {
  debug_rlog("Unable to copy file!");
}
do_something_dangerous();

Instead, fail loudly:

exec('echo '.$data.' > file.bak', $out, $err);    //  Better
if ($err) {
  throw new Exception("Unable to copy file!");
}
do_something_dangerous();

But the best approach is to use or write an API which simplifies condition handling and makes it easier to get right than wrong:

execx('echo %s > file.bak', $data);               //  Good
do_something_dangerous();
 
Filesystem::writeFile('file.bak', $data);         //  Best
do_something_dangerous();

Documentation, Comments and Formatting

  • Prefer to remove code by deleting it over removing it by commenting it out. It shall live forever in source control, and can be retrieved therefrom if it is ever again called upon.
  • In source code, use only ASCII printable characters plus space and linefeed. Do not use UTF-8 or other multibyte encodings.

See Also