writing maintainable php

38
Writing Maintainable PHP Laura Thomson, OmniTI PHP Quebec Conference 16th March 2007

Upload: robert-guiscard

Post on 14-Oct-2014

413 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Writing Maintainable PHP

Writing Maintainable PHP

Laura Thomson, OmniTIPHP Quebec Conference

16th March 2007

Page 2: Writing Maintainable PHP

PHP Quebec 2007 2

Overview

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

Page 3: Writing Maintainable PHP

What is Maintainability?

Page 4: Writing Maintainable PHP

PHP Quebec 2007 4

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?

Page 5: Writing Maintainable PHP

PHP Quebec 2007 5

How do maintainability problems arise?

• Lack of foresight about:– Size of the project– Time frame/future direction

• Developer ignorance (a big one)

Page 6: Writing Maintainable PHP

PHP Quebec 2007 6

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

Page 7: Writing Maintainable PHP

PHP Quebec 2007 7

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?

Page 8: Writing Maintainable PHP

Basics of maintainable code

(What you should already know)

Page 9: Writing Maintainable PHP

PHP Quebec 2007 9

Basics of maintainable code

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

Page 10: Writing Maintainable PHP

PHP Quebec 2007 10

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)

Page 11: Writing Maintainable PHP

PHP Quebec 2007 11

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)

Page 12: Writing Maintainable PHP

PHP Quebec 2007 12

Poor naming

• Not just $foo, $barfunction edit_item_name(itemID) {

var sItemID = "edit-item-" + itemID;

var oItemID = document.getElementById(sItemID);

• Imagine trying to find this error in the codedefine('ERROR_TAG_CATEGORY', 'ERR_TAG_CTGY::Please

provide a category name (or) select an existing one');

Page 13: Writing Maintainable PHP

PHP Quebec 2007 13

Abusing define()

define('STR_NBSP', ' ');

define('STR_BR_TAG', '<BR/>');

define('STR_BEGIN_TD', '<TD>');

define('STR_END_TD', '</TD>');

Page 14: Writing Maintainable PHP

PHP Quebec 2007 14

Reimplementation of built ins

function change_to_lowercase($item,$key)

{

global $changes;

$changes[$key] = strtolower($item);

}

Page 15: Writing Maintainable PHP

PHP Quebec 2007 15

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");}

Page 16: Writing Maintainable PHP

PHP Quebec 2007 16

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");}

Page 17: Writing Maintainable PHP

PHP Quebec 2007 17

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);

Page 18: Writing Maintainable PHP

PHP Quebec 2007 18

Premature optimization

• Often obfuscates code, and often done without a good rational reason to do so

function foo(&$bar) {…

Page 19: Writing Maintainable PHP

PHP Quebec 2007 19

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

Page 20: Writing Maintainable PHP

PHP Quebec 2007 20

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?)

Page 21: Writing Maintainable PHP

PHP Quebec 2007 21

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

– …

Page 22: Writing Maintainable PHP

PHP Quebec 2007 22

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

– …

Page 23: Writing Maintainable PHP

PHP Quebec 2007 23

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

• …

Page 24: Writing Maintainable PHP

PHP Quebec 2007 24

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)

Page 25: Writing Maintainable PHP

PHP Quebec 2007 25

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

Page 26: Writing Maintainable PHP

PHP Quebec 2007 26

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

Page 27: Writing Maintainable PHP

Scaling the code base

Page 28: Writing Maintainable PHP

PHP Quebec 2007 28

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.

Page 29: Writing Maintainable PHP

PHP Quebec 2007 29

What do you gain from a framework?

• Standard code layout for that framework

• Often makes developing a prototype fast

Page 30: Writing Maintainable PHP

PHP Quebec 2007 30

Downside

• Skills don’t transfer from one framework to another

• Rapidly prototyped code not necessarily appropriate for use in production

Page 31: Writing Maintainable PHP

PHP Quebec 2007 31

Two kinds of frameworks

• MVC style (e.g. Cake)• Component style (e.g. eZ)

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

Page 32: Writing Maintainable PHP

PHP Quebec 2007 32

Database abstraction use and abuse

• Use PDO – it’s a defacto standard• Standardize on use of prepared

statements

Page 33: Writing Maintainable PHP

PHP Quebec 2007 33

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

Page 34: Writing Maintainable PHP

PHP Quebec 2007 34

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

Page 35: Writing Maintainable PHP

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

Page 36: Writing Maintainable PHP

PHP Quebec 2007 36

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.

Page 37: Writing Maintainable PHP

PHP Quebec 2007 37

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.

Page 38: Writing Maintainable PHP

PHP Quebec 2007 38

Questions?