You are on page 1of 38

Writing Maintainable PHP

Laura Thomson, OmniTI


PHP Quebec Conference
16th March 2007
Overview

• Defining the problem


• Basics of maintainable code
• Scaling the code base
• Maintaining legacy code

PHP Quebec 2007 2


What is Maintainability?
Maintainability

• Can somebody else understand your


code enough to change and update it?
• Can you understand your own code
enough to change and update it?
• Can the code be extended and
adapted easily?

PHP Quebec 2007 4


How do maintainability
problems arise?
• Lack of foresight about:
– Size of the project
– Time frame/future direction

• Developer ignorance (a big one)

PHP Quebec 2007 5


Sizing the project

• For small problems write small code


and be willing to write throwaway
code
• For big problems design before you
start
• The issue arises when projects grow
organically
• Classic problem of being unable to
redevelop a prototype
PHP Quebec 2007 6
Developer ignorance

• Self taught and junior developers


• Lack of experience with working in teams
• Lack of experience with developing
significant code bases
• Lack of experience with other people’s
horrible code
• Have not yet been forced to revisit their
own old code
• How are they going to improve?
PHP Quebec 2007 7
Basics of maintainable code

(What you should already


know)
Basics of maintainable code

• Common errors
• Coding standards
• Version control
• Developer education

PHP Quebec 2007 9


Common errors

• Obfuscated code (the big one)


• Failure to comment appropriately
• Inline functions
• Side effects
• Failure to read and fit in with existing
code
• Ignoring security (or planning to
retrofit)
PHP Quebec 2007 10
Obfuscated code

• The worst of all common errors:


– Poor naming
– Seventeen layers of handoff
– Misuse of define()
– Reimplementation of built in functions
– Failure to do the simplest thing that could
possibly work
– Premature optimization (and it’s virtually
always premature)
PHP Quebec 2007 11
Poor naming

• Not just $foo, $bar


function edit_item_name(itemID) {
var sItemID = "edit-item-" + itemID;
var oItemID = document.getElementById(sItemID);

• Imagine trying to find this error in the code


define('ERROR_TAG_CATEGORY', 'ERR_TAG_CTGY::Please
provide a category name (or) select an existing
one');

PHP Quebec 2007 12


Abusing define()

define('STR_NBSP', ' ');
define('STR_BR_TAG', '<BR/>');
define('STR_BEGIN_TD', '<TD>');
define('STR_END_TD', '</TD>');

PHP Quebec 2007 13


Reimplementation of built ins

function change_to_lowercase($item,$key)
{
global $changes;
$changes[$key] = strtolower($item);
}

PHP Quebec 2007 14


Simplicity
• First, try the simplest thing that could possibly work.

<?php

/**
* Description: Changes the case of text within tags <>
* Make sure the $argc and $argv variables are enabled.
* Invoke this script on CLI as follows:
* php <thisfilename.ext> file2Bparsed.ext
*
**/

if ($argc <= 1 || !isset($argv[1])) {


die("\nPlease enter the file to be parsed\n");
}

$filename = $argv[1];
if (!file_exists($filename) || !is_readable($filename)) {
die("\nEnter a valid file\n");
}

PHP Quebec 2007 15


Simplicity - 2
$changes = array();
$is_match = false;
$fh = fopen($filename, "r");
$contents = fread($fh, filesize($filename));
fclose($fh);

$pattern = "/(<(\w+)>|<\/(\w+)>)/";

if (preg_match_all($pattern, $contents, $matches)) {


$is_match = true;
if (!empty($matches[0])) {
//change the matched elements to all lowercase
array_walk($matches[0], 'change_to_lowercase');
}
}

if (!$is_match) {
die("\nNo match found\n");
}

PHP Quebec 2007 16


Simplicity - 3
$fh = fopen($filename, "w");
if (!is_writable($filename)) {
fclose($fh);
die("\nFile is not writable\n");
}

$contents = str_replace($matches[0], $changes,


$contents);
$success = fwrite($fh, $contents);
if ($success) {
print "\nSuccessfully matched and modified.\n";
}
fclose($fh);

PHP Quebec 2007 17


Premature optimization

• Often obfuscates code, and often


done without a good rational reason to
do so

function foo(&$bar) {…

PHP Quebec 2007 18


Coding standards

• Have and use a coding standard


• Don’t need to write one from scratch:
PHP standards exist for PEAR and for
the Zend Framework. These can be
used adhoc or serve as a basis for
your own
• Greenfields vs legacy: virtually
impossible

PHP Quebec 2007 19


How not to write a coding
standard
• Make the rules awkward and difficult
to remember
• Apps Hungarian – the most abused
coding style ever
• Force millions of tiny files
(performance hit)
• Force complete OO (why not just use
Java?)
PHP Quebec 2007 20
Example coding standard

• (Excerpts)
• Formatting e.g.
– Always use long form PHP tags <?php ?>
– Two space indents throughout, NO HARD TABS
– …
• Naming
– Use camel caps for OO identifiers (classnames,
methods, member variables), like this:
$theVarCalledFoo
– …
PHP Quebec 2007 21
Standard - 2

• Comments
– Every file should have a header block
containing at a minimum…
– Single line comments are encouraged on
non-obvious code. These can also be
used to add "TODO", "DEBUG", and
"FIXME" items
–…

PHP Quebec 2007 22


Standard - 3
Semantics

• Declare functions and classes in library files that do not have any execution
side effects besides possibly instantiating variables or defining constants.

• All code should run clean with error reporting turned up to E_ALL

• Try to avoid use of the ternary operator for readability

• Avoid magic numbers, declare a constant

• Avoid embedding PHP logic in HTML and vice versa

• Use parentheses to reinforce unclear or complicated precedence.

• Avoid use of global keyword

• …

PHP Quebec 2007 23


Version control

• For any project that will take more


than a week, more than one code file,
or more than one developer .
• And most of the others as well.
• Frequent commits of conceptual
changesets
• Detailed commit messages (trac,
while it has shortcomings, is your
friend)
PHP Quebec 2007 24
The code under the rug

• If nobody ever notices how awful your code is, but


notices if it is late what happens?
• If the next guy only says “aaarrrgh” when you are
working somewhere else, does it make a sound?
• You need somebody other than the original author
doing QA anyway
• Peer review can be confronting, but valuable
• Somebody overseeing commits can pick up a lot of
evil … and act as a deterrent

PHP Quebec 2007 25


Developer education

• Don’t underestimate the importance


of training.
• How:
– Provide code layout and design
– Provide sample code
– Explain what’s required
– Give frequent feedback

PHP Quebec 2007 26


Scaling the code base
Frameworks and Architectures:
use and abuse
• Frameworks are buzzy, and Rails doesn’t help.
• Having an architecture like MVC can be a really good thing,
but:
– Everybody has a different idea about how this ought to be
implemented
– Some of the ideas are really twisted
– Some make it hard to do very basic things simply
– Code bloats
– Which framework?
– No dominant paradigm yet, ergo little help with maintainability
Have a clear, simple, architecture that is easy to
add to, easy to explain to new developers, and
easy to remember now or in two or five years’
time.

PHP Quebec 2007 28


What do you gain from a
framework?
• Standard code layout for that
framework
• Often makes developing a prototype
fast

PHP Quebec 2007 29


Downside

• Skills don’t transfer from one


framework to another
• Rapidly prototyped code not
necessarily appropriate for use in
production

PHP Quebec 2007 30


Two kinds of frameworks

• MVC style (e.g. Cake)


• Component style (e.g. eZ)

• Both kinds of music (e.g. ZF)

PHP Quebec 2007 31


Database abstraction use and
abuse
• Use PDO – it’s a defacto standard
• Standardize on use of prepared
statements

PHP Quebec 2007 32


Security

• Needs to be part of the initial build


• Trying to retrofit it is very hard, but
also what usually happens, and new
exploits need to be accounted for
• Build into your architecture stages of
input and output processing to
encourage filtering and escaping in
single locations

PHP Quebec 2007 33


Documentation

• For projects beyond a certain size, you start


to need significant documentation
• If your plan says this code will grow large,
document as you go, from the start. If it’s
not done at the time, it will never be done.
• (Sometimes we can all be caught short)
• Aim for consistent production of lightweight
documentation:
– Takes less time to produce (and therefore has
some chance of actually happening)
– Takes less time to read

PHP Quebec 2007 34


Maintaining Legacy Code
(or, “The Ninth Circle of Hell”)
Maintaining legacy code

• “Hell is other people’s code.”


- Anonymous, late twentieth century

- Sad true facts:


- You may never read all the legacy code
- There will be parts of it that are broken or never
used
- If the original author didn’t document it, chances
are you never will
- If it needs a complete rewrite, chances are you
won’t have time
- You will have to to deal with this at some stage if
you haven’t already.

PHP Quebec 2007 36


Strategies

• Worth spending some time to audit:


– What you have in the way of documentation
– The basic architecture of the code
– Coding conventions if any
– What is used
– What is obviously broken or fragile and why
• Refactor as you go, to a lightweight plan
• Don’t get too ambitious.

PHP Quebec 2007 37


Questions?

PHP Quebec 2007 38

You might also like