Return to CrazyBri home
Coding Guidelines for CrazyBri Projects
Comments or suggestions? email us using the CrazyBri Feedback Form

Contents


Introduction

Standardization is Important

It helps if the standard annoys everyone in some way so everyone feels they are on the same playing field. The proposal here has evolved over many projects, many companies, and literally a total of many weeks spent arguing. It is no particular person's style and is certainly open to local amendments.

Good Points

When a project tries to adhere to common standards a few good things happen:
  • programmers can go into any code and figure out what's going on
  • new people can get up to speed quickly
  • people new to PHP are spared the need to develop a personal style and defend it to the death
  • people new to PHP are spared making the same mistakes over and over again
  • people make fewer mistakes in consistent environments
  • programmers have a common enemy :-)

Bad Points

Now the bad:
  • the standard is usually stupid because it's not what I do
  • standards reduce creativity
  • standards are unnecessary as long as people are consistent
  • standards enforce too much structure
  • people ignore standards anyway

Discussion

The experience of many projects leads to the conclusion that using coding standards makes the project go smoother. Are standards necessary for success? Of course not. But they help, and we need all the help we can get! Be honest, most arguments against a particular standard come from the ego. Few decisions in a reasonable standard really can be said to be technically deficient, just matters of taste. So be flexible, control the ego a bit, and remember any project is fundamentally a team effort.



Top

Interpretation

Conventions

The use of the word "shall" in this document requires that any project using this document must comply with the stated standard.

The use of the word "should" directs projects in tailoring a project-specific standard, in that the project must include, exclude, or tailor the requirement, as appropriate.

The use of the word "may" is similar to "should", in that it designates optional requirements.

Standards Enforcement

First, any serious concerns about the standard should be brought up and worked out within the group. Maybe the standard is not quite appropriate for your situation. It may have overlooked important issues or maybe someone in power vehemently disagrees with certain issues :-)

In any case, once finalized hopefully people will play the adult and understand that this standard is reasonable, and has been found reasonable by many other programmers, and therefore is worthy of being followed even with personal reservations.

Failing willing cooperation it can be made a requirement that this standard must be followed to pass a code inspection.

Failing that the only solution is a massive tickling party on the offending party.



Top

Accepting an Idea

  1. It's impossible.
  2. Maybe it's possible, but it's weak and uninteresting.
  3. It is true and I told you so.
  4. I thought of it first.
  5. How could it be otherwise.
If you come to objects with a negative preconception please keep an open mind. You may still conclude objects are bunk, but there's a road you must follow to accept something different. Allow yourself to travel it for a while.

1. Editor Settings

Tabs vs Spaces: We prefer the consistent use of spaces - please do not use tabs. Copying and pasting from shell windows to other shell windows causes simple diffs to become complex when you use tabs. Convert all tabs to 4 spaces.

Linefeeds: Ensure that your editor is saving files in the UNIX format. This means lines are terminated with a newline, not with a CR/LF combo as they are on Win32, or whatever the Mac uses. Any decent Win32 editor should be able to do this, but it might not always be the default. Know your editor. 

Top

Names



Make Names Fit

Names are the heart of programming. In the past people believed knowing someone's true name gave them magical power over that person. If you can think up the true name for something, you give yourself and the people coming after power over the code. Don't laugh! A name is the result of a long deep thought process about the ecology it lives in. Only a programmer who understands the system as a whole can create a name that "fits" with the system. If the name is appropriate everything fits together naturally, relationships are clear, meaning is derivable, and reasoning from common human expectations works as expected.

If you find all your names could be Thing and DoIt then you should probably revisit your design.

All names must be standard english words.

Abbreviated words like get_loc_dev instead of get_local_device may be perfectly acceptable and understandable to native english speakers, but confusing and illogical to someone who is trying to "translate" the idea or concept to their own language. Keep in mind if a word cannot be translated, it makes it ten times harder for someone who works better in another language to understand the code.

Top


Array Element

Array element names follow the same rules as a variable.

  • use '_' as the word separator.
  • don't use '-' as the word separator

Justification

  • if '-' is used as a word separator it will generate warnings used with magic quotes.

Example

$myarr['foo_bar'] = 'Hello';
print "$myarr[foo_bar] world"; // will output: Hello world

$myarr['foo-bar'] = 'Hello';
print "$myarr[foo-bar] world"; // warning message

Single or Double Quotes

    Avoid double quotes: Whenever possible, avoid using double quotes for strings that do not contain variables.
    ONE caveat- when writing a SQL query, enclose the query in double quotes,
    enclose VARIABLES used in the query within single quotes. when using ARRAY elements in SQL queries or other strings break them out of the double quotes and concatenate them.


    $sql="SELECT * FROM table WHERE id = '$_POST['id']' ORDER BY id";
    $sql='SELECT * FROM table WHERE id = '$_POST[id]' ORDER BY id';
    The above queries will generate errors in many installations.


    $sql="SELECT * FROM table WHERE id = ".$_POST['id']." ORDER BY id";

Justification

  • Some PHP configurations will output warnings if arrays are used without quotes except when used within magic quotes

Example

$myarr['foo_bar'] = 'Hello';
$element_name = 'foo_bar';
print "$myarr[foo_bar] world"; // will output: Hello world
print "$myarr[$element_name] world"; // will output: Hello world
print "$myarr['$element_name'] world"; // parse error
print "$myarr["$element_name"] world"; // parse error


Top



Global Variables

  • Global variables should be used as little as possible.
  • Functions should NEVER set a variable to global scope.

Justification

  • global variables can be security risks. if your code will not work with register_globals=off, you need to learn to code better.


Top


Define Names / Global Constants

  • Global constants should be all caps with '_' separators.
  • Constants should be kept to a minimum where possible. Better to use plain variables

Justification

It's tradition for global constants to named this way. You must be careful to not conflict with other predefined globals.
However, global constants can quickly become a headache unless they are explicitly defined all in one place Other programmers have been known to go nust looking through 15 or 20 different files looking for the place a global constant is defined.
Any global constants must be defined in a single universal file, preferrably suffixed with a "_constants.php" suffix.

Example


define("A_GLOBAL_CONSTANT", "Hello world!");


Top


Function Names

  • For PHP functions use the C GNU convention of all lower case letters with '_' as the word delimiter.

Justification

  • It makes functions very different from any class related names.

Example

function some_bloody_function()
{
    $variable = $code;
}


Top

2. Naming Conventions

We will not be using any form of hungarian notation in our naming conventions. Many of us believe that hungarian naming is one of the primary code obfuscation techniques currently in use. This means prefixing a variable with some identifier such as noted above in our requirement to use plain english names. Hungarian notation looks like this:
$g_constant = array();
$f_variable= "foo";
$a_name = "bar";
What, exactly do $g_ , $a_ and $f_ stand for?? who knows... ? use standard english, not abbreviations.

Variable Names: Variable names should be in all lowercase, with words separated by an underscore, example:

$current_user is right, but $currentuser and $currentUser are not.

Names should be descriptive, but concise. We don't want huge sentences as our variable names, but typing an extra couple of characters is always better than wondering what exactly a certain variable is for.

Loop Indices: The only situation where a one-character variable name is allowed is when it's the index for some looping construct. In this case, the index of the outer loop should always be $i. If there's a loop inside that loop, its index should be $j, followed by $k, and so on. If the loop is being indexed by some already-existing variable with a meaningful name, this guideline does not apply, example:

for ($i = 0; $i < $outer_size; $i++)
{
for ($j = 0; $j < $inner_size; $j++)
{
foo($i, $j);
}
}

Function Names: Functions should also be named descriptively. We're not programming in C here, we don't want to write functions called things like "stristr()". Again, all lower-case names with words separated by a single underscore character. Function names should preferably have a verb in them somewhere. Good function names are print_login_status(), get_user_data(), etc.

Function Arguments: Arguments are subject to the same guidelines as variable names. We don't want a bunch of functions like: do_stuff($a, $b, $c). In most cases, we'd like to be able to tell how to use a function by just looking at its declaration.

Summary: The basic philosophy here is to not hurt code clarity for the sake of laziness. This has to be balanced by a little bit of common sense, though; print_login_status_for_a_given_user() goes too far, for example -- that function would be better named print_user_login_status() , or just print_login_status().



Top


Error Return Check Policy

  • Check every system call for an error return, unless you know you wish to ignore errors.
  • Include the system error text for every system error message.
  • ALL functions must return a value that can be checked outside of the function


Top


Braces {} Policy

Of the three major brace placement strategies only ONE is acceptable,

  • GOOD: Place brace under and inline with keywords:
  •    if ($condition)       while ($condition)
       {                     {
          ...                   ...
       }                     }
    

    BAD: Traditional Unix policy of placing the initial brace on the same line as the keyword and the trailing brace inline on its own line with the keyword:

       if ($condition) {     while ($condition) {
          ...                   ...
       }                     }
    

Justification

  • There are more reasons than psychological for preferring the first style. If you use an editor (such as vi) that supports brace matching, the first is a much better style. Why? Let's say you have a large block of code and want to know where the block ends. You move to the first brace hit a key and the editor finds the matching brace. Example:
         if ($very_long_condition && $second_very_long_condition)
         {
            if(more_conditions == $variables)
         {
                while($loop = true)
                {
                    $action = "a lot of code (100 lines or so)";
                }
                $Action = true;
         }
            
         }//you can also comment the end of a bracket to note what loop it is SUPPOSED to close.
         else if (...)
         {
        ...
         }
    
    
    To move from block to block you just need to use cursor down and your brace matching key. No need to move to the end of the line to match a brace then jerk back and forth.


Top


Indentation/Tabs/Space Policy

  • Indent using 4 spaces for each level.
  • Do not use tabs, use spaces. Most editors can substitute spaces for tabs.
  • Indent as much as needed, but no more. There are no arbitrary rules as to the maximum indenting level. If the indenting level is more than 4 or 5 levels you may think about factoring out code.

Justification

  • When people using different tab settings the code is impossible to read or print, which is why spaces are preferable to tabs.
  • Most PHP applications use 4 spaces.
  • Most editors use 4 spaces by defalt.
  • As much as people would like to limit the maximum indentation levels it never seems to work in general. We'll trust that programmers will choose wisely how deep to nest code.

Example


   function func()
   {
      if (something bad)
      {
         if (another thing bad)
         {
            while (more input)
            {
            }
         }
      }
   }


Top


Parens () with Key Words and Functions Policy

  • Do not put parens next to keywords. Put a space between.
  • Do put parens next to function names.
  • Do not use parens in return statements when it's not necessary.

Justification

  • Keywords are not functions. By putting parens next to keywords keywords and function names are made to look alike.
  • (it isnt always rigidly enforced, however.. )

Example


    if (condition)
    {
    }

    while (condition)
    {
    }

    strcmp($s, $s1);

    return 1;



Top


Make Functions Reentrant

Functions should not keep static variables that prevent a function from being reentrant. That is, variables that are used outside a function must be declared outside the function, variables used inside a function should not be identical to variables on the outside, UNLESS the variables are declared outside, and passed INTO the function, and returned.



Top


If Then Else Formatting

Layout

Should follow the following format.
   if (condition)                 // Comment
   {
   }
   else if (condition)            // Comment
   {
   }
   else                           // Comment
   {
   }
If you have else if statements then it is REQUIRED to always have an else block for finding unhandled cases. Maybe put a log message in the else even if there is no corrective action taken.

Condition Format

It is good practice to put the constant on the left hand side of an equality/inequality comparison. For example:

if ( 6 == $errorNum ) ...

One reason is that if you leave out one of the = signs, the parser will find the error for you. A second reason is that it puts the value you are looking for right up front where you can find it instead of buried at the end of your expression. It takes a little time to get used to this format, but then it really gets useful.



Top


switch Formatting

  • Falling through a case statement into the next case statement shall be permitted as long as a comment is included.
  • The default case should always be present and trigger an error if it should not be reached, yet is reached.
  • If you need to create variables put all the code in a block.

Example


   switch (...)
   {
      case 1:
         ...
      // FALL THROUGH

      case 2:
      {
         $v = get_week_number();
         ...
      }
      break;

      default:
      {
          trigger_error_message('error message');
      }
   }



Top


Use of continue,break and ?:

Continue and Break

Continue and break are really disguised gotos so they are covered here.

Continue and break like goto should be used sparingly as they are magic in code. With a simple spell the reader is beamed to god knows where for some usually undocumented reason.

The two main problems with continue are:

  • It may bypass the test condition
  • It may bypass the increment/decrement expression

Consider the following example where both problems occur:


while (TRUE)
{
   ...
   // A lot of code
   ...
   if (/* some condition */) 
   {
      continue;
   }
   ...
   // A lot of code
   ...
   if ( $i++ > STOP_VALUE) break;
}
Note: "A lot of code" is necessary in order that the problem cannot be caught easily by the programmer.

From the above example, a further rule may be given: Mixing continue with break in the same loop is a sure way to disaster.

?:

The trouble is people usually try and stuff too much code in between the ? and :. Here are a couple of clarity rules to follow:
  • Put the condition in parens so as to set it off from other code
  • If possible, the actions for the test should be simple functions.
  • DO NOT use long conditions for this shorthand if/else format.

Example

good:
(condition) ? funct1() : func2();

BAD
(condition) ? long statement : another long statement;

if you have long conditional statements use if/else formatting with braces.



Top


One Statement Per Line

There should be only one statement per line unless the statements are very closely related.



Top


Short Methods

  • Methods should limit themselves to a single page of code.

Justification

  • The idea is that the each method represents a technique for achieving a single objective.
  • Most arguments of inefficiency turn out to be false in the long run.
  • True function calls are slower than not, but there needs to a thought out decision (see premature optimization).



Top


Document Null Statements

Always document a null body for a for or while statement so that it is clear that the null body is intentional and not missing code.

   while ($dest++ = $src++)
      ;         // VOID



Top


Do Not Default If Test to Non-Zero

Do not default the test for non-zero, i.e.

   if (FAIL != f())
is better than

   if (f())
even though FAIL may have the value 0 which PHP considers to be false. An explicit test will help you out later when somebody decides that a failure return should be -1 instead of 0. Explicit comparison should be used even if the comparison value will never change; e.g., if (!($bufsize % strlen($str))) should be written instead as if (0 == ($bufsize % strlen($str))) to reflect the numeric (not boolean) nature of the test. A frequent trouble spot is using strcmp to test for string equality, where the result should never ever be defaulted.

The non-zero test is often defaulted for predicates and other functions or expressions which meet the following restrictions:

  • Returns 0 for false, nothing else.
  • Is named so that the meaning of (say) a true return is absolutely obvious. Call a predicate IsValid(), not CheckValid().



Top


The Bull of Boolean Types

Do not check a boolean value for equality with 1 (TRUE, YES, etc.); instead test for inequality with 0 (FALSE, NO, etc.). Most functions are guaranteed to return 0 if false, but only non-zero if true. Thus,


  

if (TRUE == func()) { ...

must be written

   

if (FALSE != func()) { ...



Top


Usually Avoid Embedded Assignments

There is a time and a place for embedded assignment statements. In some constructs there is no better way to accomplish the results without making the code bulkier and less readable.


   while ($a != ($c = getchar()))
   {
      process the character
   }

The ++ and -- operators count as assignment statements. So, for many purposes, do functions with side effects. Using embedded assignment statements to improve run-time performance is also possible. However, one should consider the tradeoff between increased speed and decreased maintainability that results when embedded assignments are used in artificial places. For example,


   $a = $b + $c;
   $d = $a + $r;

should not be replaced by

   $d = ($a = $b + $c) + $r;
even though the latter may save one cycle. In the long run the time difference between the two will decrease as the optimizer gains maturity, while the difference in ease of maintenance will increase as the human memory of what's going on in the latter piece of code begins to fade.



Top


Reusing Your Hard Work and the Hard Work of Others

Reuse across projects is almost impossible without a common framework in place. Objects conform to the services available to them. Different projects have different service environments making object reuse difficult.

Developing a common framework takes a lot of up front design effort. When this effort is not made, for whatever reasons, there are several techniques one can use to encourage reuse:

Don't be Afraid of Small Libraries

One common enemy of reuse is people not making libraries out of their code. A reusable class may be hiding in a program directory and will never have the thrill of being shared because the programmer won't factor the class or classes into a library.

One reason for this is because people don't like making small libraries. There's something about small libraries that doesn't feel right. Get over it. The computer doesn't care how many libraries you have.

If you have code that can be reused and can't be placed in an existing library then make a new library. Libraries don't stay small for long if people are really thinking about reuse.



Top


Comments on Comments



Top

Comments Should Tell a Story

Consider your comments a story describing the system. Expect your comments to be extracted by a robot and formed into a man page. Class comments are one part of the story, method signature comments are another part of the story, method arguments another part, and method implementation yet another part. All these parts should weave together and inform someone else at another point of time just exactly what you did and why.

Top

Document Decisions

Comments should document decisions. At every point where you had a choice of what to do place a comment describing which choice you made and why. Archeologists will find this the most useful information.

Comment Layout

Each part of the project has a specific comment layout.

Top

Make Gotchas Explicit

Explicitly comment variables changed out of the normal control flow or other code likely to break during maintenance. Embedded keywords are used to point out issues and potential problems. Consider a robot will parse your comments looking for keywords, stripping them out, and making a report so people can make a special effort where needed.

Gotcha Keywords

  • :TODO: topic
    Means there's more to do here, don't forget.

  • :BUG: [bugid] topic
    means there's a Known bug here, explain it and optionally give a bug ID.

  • :KLUDGE:
    When you've done something ugly say so and explain how you would do it differently next time if you had more time.

  • :TRICKY:
    Tells somebody that the following code is very tricky so don't go changing it without thinking.

  • :WARNING:
    Beware of something.

  • :PARSER:
    Sometimes you need to work around a parser problem. Document it. The problem may go away eventually.

  • :ATTRIBUTE: value
    The general form of an attribute embedded in a comment. You can make up your own attributes and they'll be extracted.

Gotcha Formatting

  • Make the gotcha keyword the first symbol in the comment.
  • Comments may consist of multiple lines, but the first line should be a self-containing, meaningful summary.
  • The writer's name and the date of the remark should be part of the comment. This information is in the source repository, but it can take a quite a while to find out when and by whom it was added. Often gotchas stick around longer than they should. Embedding date information allows other programmer to make this decision. Embedding who information lets us know who to ask.

Example

   // :TODO: tmh 960810: possible performance problem
   // We should really use a hash table here but for now we'll
   // use a linear search.

   // :KLUDGE: tmh 960810: possible unsafe type cast
   // We need a cast here to recover the derived type. It should
   // probably use a virtual method or template.


Top


Use if (0) to Comment Out Code Blocks

Sometimes large blocks of code need to be commented out for testing. The easiest way to do this is with an if (0) block:
   function example()
   {
      great looking code

      if (0) {
      lots of code
      }

      more code
    }

You can't use /**/ style comments because comments can't contain comments and surely a large block of your code will contain a comment, won't it?
(if you comment out a large section of code that ALREADY has a */ comment block, your code will break)
sure you can use it for debugging, but IDEALLY, NO such comments will be present in ANY CVS commit. if you have to comment out a large block, remove the entire block before committing to CVS.. (CVS takes care of versioning changes) Single line comments should use double-slashes (//). Hashes (#) may ideally be used for comment TITLES and for large blocks of "never to change" comments such as the file identification header



Top


Directory Documentation

Every directory should have a README file that covers:
  • the purpose of the directory and what it contains
  • a one line comment on each file. A comment can usually be extracted from the NAME attribute of the file header.
  • cover build and install directions
  • direct people to related resources:
    • directories of source
    • online documentation
    • paper documentation
    • design documentation
  • anything else that might help someone
Consider a new person coming in 6 months after every original person on a project has gone. That lone scared explorer should be able to piece together a picture of the whole project by traversing a source directory tree and reading README files, Makefiles, and source file headers.



Top


Server configuration

This section contains some guidelines for PHP/Apache configuration.


Top


$_SERVER, ,etc.

Always use SPECIFIC declarations of a variable.
If you expect $myvar from POST data, specify it as $_POST['myvar'];
Never just ASSUME you are getting $myvar from post data (somebody could just pass it in the URL as a $_GET)
The only exception is when declaring a variable global, in which case, instead of:

$_GLOBALS['myvar'];


use:

global $myvar;




Top


PHP File Extensions

There is lots of different extension variants on PHP files (.html, .php, .php3, .php4, .phtml, .inc, .class...).
  • Always use the extension .php.
  • Always use the extension .php for your class and function libraries.

Justification

  • The use of .php makes it possible to enable caching on other files than .php.
  • The use of .inc or .class can be a security problem. On most servers these extensions aren't set to be run by a parser. If these are accessed they will be displayed in clear text.




Top

Miscellaneous

This section contains some miscellaneous do's and don'ts.

  • Don't use floating-point variables where discrete values are needed. Using a float for a loop counter is a great way to shoot yourself in the foot. Always test floating-point numbers as <= or >=, never use an exact comparison (== or !=).

  • Do not rely on automatic beautifiers. The main person who benefits from good program style is the programmer him/herself, and especially in the early design of handwritten algorithms or pseudo-code. Automatic beautifiers can only be applied to complete, syntactically correct programs and hence are not available when the need for attention to white space and indentation is greatest. Programmers can do a better job of making clear the complete visual layout of a function or file, with the normal attention to detail of a careful programmer (in other words, some of the visual layout is dictated by intent rather than syntax and beautifiers cannot read minds). Sloppy programmers should learn to be careful programmers instead of relying on a beautifier to make their code readable. Finally, since beautifiers are non-trivial programs that must parse the source, a sophisticated beautifier is not worth the benefits gained by such a program. Beautifiers are best for gross formatting of machine-generated code.

  • Accidental omission of the second ``='' of the logical compare is a problem. The following is confusing and prone to error.
            if ($abool= $bbool) { ... }
         
    Does the programmer really mean assignment here? Often yes, but usually no. The solution is to just not do it, an inverse Nike philosophy. Instead use explicit tests and avoid assignment with an implicit test. The recommended form is to do the assignment before doing the test:
    
           $abool= $bbool;
           if ($abool) { ... }
        


Top


Layering

Layering is the primary technique for reducing complexity in a system. A system should be divided into layers. Layers should communicate between adjacent layers using well defined interfaces. When a layer uses a non-adjacent layer then a layering violation has occurred.

A layering violation simply means we have dependency between layers that is not controlled by a well defined interface. When one of the layers changes code could break. We don't want code to break so we want layers to work only with other adjacent layers.

Sometimes we need to jump layers for performance reasons. This is fine, but we should know we are doing it and document appropriately.



Top


Code Reviews

If you can make a formal code review work then my hat is off to you. Code reviews can be very useful. Unfortunately they often degrade into nit picking sessions and endless arguments about silly things. They also tend to take a lot of people's time for a questionable payback.

My god he's questioning code reviews, he's not an engineer!

Not really, it's the form of code reviews and how they fit into normally late chaotic projects is what is being questioned.

First, code reviews are way too late to do much of anything useful. What needs reviewing are requirements and design. This is where you will get more bang for the buck.

Get all relevant people in a room. Lock them in. Go over the class design and requirements until the former is good and the latter is being met. Having all the relevant people in the room makes this process a deep fruitful one as questions can be immediately answered and issues immediately explored. Usually only a couple of such meetings are necessary.

If the above process is done well coding will take care of itself. If you find problems in the code review the best you can usually do is a rewrite after someone has sunk a ton of time and effort into making the code "work."

You will still want to do a code review, just do it offline. Have a couple people you trust read the code in question and simply make comments to the programmer. Then the programmer and reviewers can discuss issues and work them out. Email and quick pointed discussions work well. This approach meets the goals and doesn't take the time of 6 people to do it.



Top


Create a Source Code Control System Early and Not Often

A common build system and source code control system should be put in place as early as possible in a project's lifecycle, preferably before anyone starts coding. Source code control is the structural glue binding a project together. If programmers can't easily use each other's products then you'll never be able to make a good reproducible build and people will piss away a lot of time. It's also hell converting rogue build environments to a standard system. But it seems the right of passage for every project to build their own custom environment that never quite works right.

Some issues to keep in mind:

  • Make simple things simple. It should be dead simple and well documented on how to:
    • how to change files
    • how to add new modules into the system
    • how to delete modules and files
    • how to check in changes
    • what are the available libraries and include files
    • how to get the build environment including all compilers and other tools

    Make a web page or document or whatever. New programmers shouldn't have to go around begging for build secrets from the old timers.

  • On checkins log comments should be useful. These comments should be collected every night and sent to interested parties.


Top


Create a Bug Tracking System Early and Not Often

The earlier people get used to using a bug tracking system the better. If you are 3/4 through a project and then install a bug tracking system it won't be used. You need to install a bug tracking system early so people will use it.

Programmers generally resist bug tracking, yet when used correctly it can really help a project:

  • Problems aren't dropped on the floor.
  • Problems are automatically routed to responsible individuals.
  • The lifecycle of a problem is tracked so people can argue back and forth with good information.
  • Managers can make the big schedule and staffing decisions based on the number of and types of bugs in the system.
  • Configuration management has a hope of matching patches back to the problems they fix.
  • QA and technical support have a communication medium with developers.
Not sexy things, just good solid project improvements.

Source code control should be linked to the bug tracking system. During the part of a project where source is frozen before a release only checkins accompanied by a valid bug ID should be accepted. And when code is changed to fix a bug the bug ID should be included in the checkin comments.

We do have/will have an effective bugtracker system IN PLACE, and one is being modified for in-game bug reports to be sent out to bugtracker, so we will have ALL bugs documented and numbered.

Top


Honor Responsibilities

Responsibility for software modules is scoped. Modules are either the responsibility of a particular person or are common. Honor this division of responsibility. Don't go changing things that aren't your responsibility to change. Only mistakes and hard feelings will result.

Face it, if you don't own a piece of code you can't possibly be in a position to change it. There's too much context. Assumptions seemingly reasonable to you may be totally wrong. If you need a change simply ask the responsible person to change it. Or ask them if it is OK to make such-n-such a change. If they say OK then go ahead, otherwise holster your editor.

Every rule has exceptions. If it's 3 in the morning and you need to make a change to make a deliverable then you have to do it. If someone is on vacation and no one has been assigned their module then you have to do it. If you make changes in other people's code try and use the same style they have adopted.

Programmers need to mark with comments code that is particularly sensitive to change. If code in one area requires changes to code in an another area then say so. If changing data formats will cause conflicts with persistent stores or remote message sending then say so. If you are trying to minimize memory usage or achieve some other end then say so. Not everyone is as brilliant as you.

The worst sin is to flit through the system changing bits of code to match your coding style. If someone isn't coding to the standards then ask them or ask your manager to ask them to code to the standards. Use common courtesy.

Code with common responsibility should be treated with care. Resist making radical changes as the conflicts will be hard to resolve. Put comments in the file on how the file should be extended so everyone will follow the same rules. Try and use a common structure in all common files so people don't have to guess on where to find things and how to make changes. Checkin changes as soon as possible so conflicts don't build up.

As an aside, module responsibilities must also be assigned for bug tracking purposes.

Top


PHP Code Tags

PHP Tags are used for delimit PHP from html in a file. There are serval ways to do this. <?php ?>, and <?=$name?>.
  • Use <?php ?>

Justification

  • <?php ?> is always avaliable in any system and setup.

Example

<?php print "Hello world"; ?> // Will print "Hello world"

<? print "Hello world"; ?> // Will print "Hello world" <% print "Hello world"; %> // Will print "Hello world" <?=$street?> // Will print the value of the variable $street

Top


No Magic Numbers

Magic numbers: Don't use them. Use named constants for any literal value other than obvious special cases. Basically, it's OK to check if an array has 0 elements by using the literal 0. It's not OK to assign some special meaning to a number and then use it everywhere as a literal. This hurts readability AND maintainability. Included in this guideline is that we should be using the constants TRUE and FALSE in place of the literals 1 and 0 -- even though they have the same values, it's more obvious what the actual logic is when you use the named constants.

A magic number is a bare-naked number used in source code. It's magic because no-one has a clue what it means including the author inside 3 months. For example:

if      (22 == $foo) { start_thermo_nuclear_war(); }
else if (19 == $foo) { refund_lotso_money(); }
else if (16 == $foo) { infinite_loop(); }
else                 { cry_cause_im_lost(); }
In the above example what do 22 and 19 mean? If there was a number change or the numbers were just plain wrong how would you know?

Heavy use of magic numbers marks a programmer as an amateur more than anything else. Such a programmer has never worked in a team environment or has had to maintain code or they would never do such a thing.

Instead of magic numbers use a real name that means something. You should use define(). For example:

define("PRESIDENT_WENT_CRAZY", "22");
define("WE_GOOFED", "19");
define("THEY_DIDNT_PAY", "16");

if      (PRESIDENT_WENT_CRAZY == $foo) { start_thermo_nuclear_war(); }
else if (WE_GOOFED            == $foo) { refund_lotso_money(); }
else if (THEY_DIDNT_PAY       == $foo) { infinite_loop(); }
else                                   { happy_days_i_know_why_im_here(); }
Now isn't that better?

Top


3. Code Layout

Standard header for new files: Here a template of the header that must be included at the start of all CrazyBri Projects files:


 
##############################################################################################
#                                                                                            #
#                                FILENAME.php                                                #
# *                            -------------------                                           #
# *   begin                : Friday, April 23, 2004                                          #
# *   copyright            : (C) 2004-2005  [Project Name here] Development Team             #
# *   email                : support@project-domain.com                                      #
# *   VERSION:             : $id$                                           
#                                                                                            #
##############################################################################################
#    This program is free software; you can redistribute it and/or modify it under the       #
#    terms of the GNU General Public License as published by the Free Software Foundation;   #
#    either version 2 of the License, or (at your option) any later version.                 #
#                                                                                            #
#    This program is distributed in the hope that it will be useful, but                     #
#    WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS   #
#    FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.          #
#                                                                                            #
#    You should have received a copy of the GNU General Public License along with this       #
#    program; if not, write to:                                                              #
#                                                                                            #
#                        Free Software Foundation, Inc.,                                     #
#                        59 Temple Place, Suite 330,                                         #
#                        Boston, MA 02111-1307 USA                                           #
##############################################################################################


HTML OUTPUT

NEVER output HTML directly from the php files!


This is what Smarty Template engine is for. We use it, all code shall conform to this requirement. All HTML output should be done in Smarty. The use of "echo" in a php file is forbidden except for purposes of debugging. Learn Smarty templates, IF you dont know how to output something, as a team mate.
On a related note: Smarty Templates should NEVER contain anything but display logic. This means, under no circumstances should ant smarty template break out of the template to process php code.

Top

Always include the braces: This is another case of being too lazy to type 2 extra characters causing problems with code clarity. Even if the body of some construct is only one line long, do not drop the braces. Just don't, examples:

// These are all wrong.

if (condition) do_stuff();

if (condition)
do_stuff();

while (condition)
do_stuff();

for ($i = 0; $i < size; $i++)
do_stuff($i);

// These are all right.

if (condition)
{
do_stuff();
}

while (condition)
{
do_stuff();
}

for ($i = 0; $i < size; $i++)
{
do_stuff();
}

Where to put the braces: This one is a bit of a holy war, but we're going to use a style that can be summed up in one sentence: Braces always go on their own line. The closing brace should also always be at the same column as the corresponding opening brace, examples:

if (condition) 
{
while (condition2)
{
...
}
}
else
{
...
}

for ($i = 0; $i < $size; $i++)
{
...
}

while (condition)
{
...
}

function do_stuff()
{
...
}

Use spaces between tokens: This is another simple, easy step that helps keep code readable without much effort. Whenever you write an assignment, expression, etc.. Always leave one space between the tokens. Basically, write code as if it was English. Put spaces between variable names and operators. Don't put spaces just after an opening bracket or before a closing bracket. Don't put spaces just before a comma or a semicolon. This is best shown with a few examples, examples:

// Each pair shows the wrong way followed by the right way.

$i=0;
$i = 0;

if($i<7) ...
if ($i < 7) ...

if ( ($i < 7)&&($j > 8) ) ...
if (($i < 7) && ($j > 8)) ...

do_stuff( $i, "foo", $b );
do_stuff($i, "foo", $b);

for($i=0; $i<$size; $i++) ...
for($i = 0; $i < $size; $i++) ...

$i=($j < $size)?0:1;
$i = ($j < $size) ? 0 : 1;

Operator precedence: Do you know the exact precedence of all the operators in PHP? Neither do I. (My Dear Aunt Sally is the norm, but there are exceptions) Don't guess. Always make it obvious by using brackets to force the precedence of an equation so you know what it does, examples:

// what's the result? who knows.

$bool = ($i < 7 && $j > 8 || $k == 4);

// now you can be certain what I'm doing here.

$bool = (($i < 7) && (($j < 8) || ($k == 4)))

Top

4. General Guidelines

Quoting strings: There are two different ways to quote strings in PHP - either with single quotes or with double quotes. The main difference is that the parser does variable interpolation in double-quoted strings, but not in single quoted strings. Because of this, you should always use single quotes unless you specifically need variable interpolation to be done on that string. This way, we can save the parser the trouble of parsing a bunch of strings where no interpolation needs to be done.

Also, if you are using a string variable as part of a function call, you do not need to enclose that variable in quotes. Again, this will just make unnecessary work for the parser. Note, however, that nearly all of the escape sequences that exist for double-quoted strings will not work with single-quoted strings. Be careful, and feel free to break this guideline if it's making your code harder to read, examples:

// wrong

$str = "This is a really long string with no variables
for the parser to find.";

do_stuff("$str");

// right

$str = 'This is a really long string with no variables
for the parser to find.';

do_stuff($str);

Associative array keys: In PHP, it's legal to use a literal string as a key to an associative array without quoting that string. We don't want to do this -- the string should always be quoted to avoid confusion. Note that this is only when we're using a literal, not when we're using a variable, examples:

// wrong

$foo = $assoc_array[blah];

// right

$foo = $assoc_array['blah'];

Comments: We intend for future versions to have a much higher level of commenting than we currently have (very little). Each function should be preceded by a comment that tells a programmer everything they need to know to use that function. The meaning of every parameter, the expected input, and the output are required as a minimal comment. The function's behaviour in error conditions (and what those error conditions are) should also be present. Nobody should have to look at the actual source of a function in order to be able to call it with confidence in their own code.

In addition, commenting any tricky, obscure, or otherwise not-immediately-obvious code is clearly something we should be doing. Especially important to document are any assumptions your code makes, or preconditions for its proper operation. Any one of the developers should be able to look at any part of the application and figure out what's going on in a reasonable amount of time.

Shortcut operators: The only shortcut operators that cause readability problems are the shortcut increment ($i++) and decrement ($j--) operators. These operators should not be used as part of an expression. They can, however, be used on their own line. Using them in expressions is just not worth the headaches when debugging, examples:

// wrong

$array[++$i] = $j;
$array[$i++] = $k;

// right

$i++;
$array[$i] = $j;

$array[$i] = $k;
$i++;

Inline conditionals: Inline conditionals should never be used if it can be avoided - only use them to do assignments, and not for function calls or anything complex at all. They can be harmful to readability if used incorrectly, so don't fall in love with saving typing by using them, examples:

// Bad place to use them

(($i < $size) && ($j > $size)) ? do_stuff($foo) : do_stuff($bar);

// OK place to use them

$min = ($i < $j) ? $i : $j;

Don't use uninitialized variables: For future versions, we intend to use the highest level of run-time error reporting. This will mean that the use of an uninitialized variable will be reported as an error. This will come up most often when checking which HTML form variables were passed. These errors can be avoided by using the built-in isset() function to check whether a variable has been set, examples:

// Old way

if ($forum) ...

// New way

if (isset($forum)) ...

Top

5. Specific guidelines

Optimal loops: Always calculate the length of a loop OUTSIDE/in advance of the loop itself:

// Wrong way

for ($i=0; $i<sizeof($x); $i++)

// Right way

$size = sizeof($x);
for ($i=0; $i<$size; $i++)

Avoid is_array: Whenever possible, avoid using is_array when you could use isset() or empty() instead.

Use the fastest string replacement functions: For searching for substrings, the fastest code is using strpos(), followed by preg_match() and lastly ereg(). Similarly, str_replace() is faster than preg_replace(), which is faster than ereg_replace().

Unset large arrays: While PHP handles memory management well, any time you create an array over 10 elements, unset the array after use.

Minimize global variables: We don't want functions with 10+ variables to call it, but we do want to reduce the number of global-scope variables when possible. All functions that need access to the db should pass $dblink and/or $dbtables as the first two parameters.

Echo v. Print: No, its not faster. We don't care - please avoid using print(), sprintf(), and similar print family members when possible.

Top

6. Development environment settings

Error reporting level: Please code with your php.ini error reporting level set to error_reporting  =  E_ALL. Ensure that all code you submit is warning free.

Top