Skip to content

Coding Standards and Code Quality

garyc40 edited this page Jan 9, 2013 · 10 revisions

This document provides guidelines for coding standards and code quality. These guidelines should be adhered to as much as possible when you contribute code to WPEC. But if something doesn't make sense, feel free to question or challenge it.

First and foremost

We're striving to adhere to WordPress' coding standards as much as possible, so here are 3 must-read guidelines from WordPress Codex:

Some general guidelines

Functions

Size

Each function should only do one thing. If it's taking care of too many operations, it should be broken down into multiple smaller functions.

Example:

class Person
{
	public function can_drink_alcohol() {
		$year_of_birth = db_query( "SELECT year FROM people WHERE id=%d", $this->id );

		$age = date('Y') - $year_of_birth;

		return $age >= 21;
	}
}

should be broken down to:

class Person
{
	public function get_year_of_birth() {
		return db_query( "SELECT year FROM people WHERE id=%d", $this->id );
	}

	public function get_age() {
		return date('Y') - $this->get_year_of_birth();
	}

	public function can_drink_alcohol() {
		return $this->get_age() >= 21;
	}
}

Arguments

Avoid having too many arguments. It usually means you need to break down the function further, or let the function accept an associative array of arguments.

Arguments that accept default values should be at the end of the argument list.

Return values

It's a good habit to make sure each function returns something. Even functions such as "setters", or functions that interact with the database etc. should at least return a boolean value indicating whether the operation is successful or not.

Exceptions

Limit the use of exceptions. It makes the code overly complicated, and it creates fatal error which is undesirable in a production environment. Instead, extend or use WP_Error.

Separation of logic & template

Try your best to separate logic and template. If a function needs to output a huge HTML template, put the HTML code in a separate file and include it. If a function only needs to output a line or two in HTML, it might be ok to just leave that line in the function. However, don't "echo" it directly. Instead, create one function that returns the output string, then create another that echo the returned value.

OOP

Object Oriented Programming is a good idea. But use it wisely. Not everything is supposed to be a class. Of course there's no absolute rules that define whether something should be coded as a class. Some guidelines:

  • If a class doesn't maintain states (properties that are unique to each instances, and are mutable depending on the situation), it should be broken down into a bunch of functions.

  • If the name of the class ends with "er" or "or", beware. It might indicate that the class you're about to create is just a wrapper of a bunch of functions. E.g. Purchase_Log_Processor.

  • Don't make a class do too many things. If you're coding a class "Person", it's fine to let it "eat", "play", "work", "study". It's not fine to make it ask itself whether it's legal to drink (it's something defined by law, not by the person), or tally up the total amount of monthly expenses (which should be handled by a Money_Book class).

Example:

This class should be broken down: class Person { public function get_year_of_birth() { return db_query( "SELECT year FROM people WHERE id=%d", $this->id ); }

	public function get_age() {
		return date('Y') - $this->get_year_of_birth();
	}

	public function can_drink_alcohol() {
		return $this->get_age() >= 21;
	}

	public function get_last_month_expenses() {
		$purchases = $this->get_purchases();
		$total = 0;
		foreach ( $purchases as $purchase ) {
			$total += $purchase;
		}

		return $total;
	}
}

It should be broken down into: class Person { public function get_year_of_birth() { return db_query( "SELECT year FROM people WHERE id=%d", $this->id ); }

	public function get_age() {
		return date('Y') - $this->get_year_of_birth();
	}

	public function get_last_month_expenses() {
		$purchases = $this->get_purchases();
		$total = 0;
		foreach ( $purchases as $purchase ) {
			$total += $purchase;
		}

		return $total;
	}
}

function is_legal_for_drinking( $person ) {
	return $person->get_age() >= 21;
}

class Money_Book
{
	public function __construct( $person ) {
		$this->person = $person;
		$this->fetch_data();
	}

	public function get_last_month_expenses() {
		// ...
	}
}

Debugging

There are two ways to debug a PHP application.

IDE and Breakpoints

Debugging using breakpoints can be handy in some cases where you only need to track down a bug that occurs within only a few functions.

In order to use this, you need a full-fledged IDE like NetBeans or Eclipse. Docs on how to configure this below: http://netbeans.org/kb/docs/php/debugging.html http://yoopergeek.blogspot.com/2007/10/getting-breakpoints-to-work-in-eclipse.html

Printing out debug traces

Another way that would surprisingly work well in complicated PHP app is simply printing out debug traces, or log them into a file. print_r(), var_dump() and exit() would be your best friends.

If you want to have nicely formatted debug trace, install XDebug.

IBM has a comprehensive guide on PHP debugging.

Naming convention

All functions need to be prefixed with "wpsc" (in case of functions) or "WPSC" (in case of classes) to avoid collision with WP core and other plugins.

A distinction between "public" and "private" routines should also be made clear in the routine name. A function is "public" when it is meant to be available for 3rd party developers to use. It is "private" when it is meant to only be used by WPEC core (and other related plugins that we are in control of). We need this kind of distinction to discourage third party developer from relying too much on routines that are volatile.

A private function should be prefixed with an underscore "_".

Example: function wpsc_create_product() is a good candidate to be a public function. On the other hand, function _wpsc_ajax_change_purchase_log_status() should be private.

AJAX

Since 3.8.9, all AJAX requests follow a uniform standard. See wpsc-admin/ajax.php and ajax.js for examples. Documentation will be written on how to use this soon. In the mean time, read the code.

The point of this standard is to make sure all AJAX requests are handled the same way: nonce validation, properly passing error objects, JSON response.

Actions and Filters

Any time you want to add a new hook or filter to support third party developers, think twice, or thrice, then create an issue ticket for that. It's a bad idea to add everything third party devs requested to make their plugins work. We would end up with a bunch of legacy actions / filters that we need to maintain backward compatibility. Not something to look forward to.

That's not to say we should be too conservative. It's natural that over the years we'll have a huge accumulation of filters and actions, but it's important to make sure these filters and actions are "maintainable", meaning:

  • The filter or action should not be inside a "private" function that is likely to be changed.

  • If the filter is supposed to be used only by WPEC core, make it clear by adding prefixing it with "_" .

== JavaScript == Only three things:

Clone this wiki locally