Title: Writing Maintainable PHP
1Writing Maintainable PHP
- Laura Thomson, OmniTI
- PHP Quebec Conference
- 16th March 2007
2Overview
- Defining the problem
- Basics of maintainable code
- Scaling the code base
- Maintaining legacy code
3What is Maintainability?
4Maintainability
- 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?
5How do maintainability problems arise?
- Lack of foresight about
- Size of the project
- Time frame/future direction
- Developer ignorance (a big one)
6Sizing 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
7Developer 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 peoples horrible
code - Have not yet been forced to revisit their own old
code - How are they going to improve?
8Basics of maintainable code
- (What you should already know)
9Basics of maintainable code
- Common errors
- Coding standards
- Version control
- Developer education
10Common 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)
11Obfuscated 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 its virtually always
premature)
12Poor 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_CTGYPlease
provide a category name (or) select an existing
one')
13Abusing define()
- define('STR_NBSP', 'nbsp')
- define('STR_BR_TAG', '
') - define('STR_BEGIN_TD', '')
- define('STR_END_TD', '')
14Reimplementation of built ins
- function change_to_lowercase(item,key)
-
- global changes
- changeskey strtolower(item)
15Simplicity
- First, try the simplest thing that could possibly
work. - /
- 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 file2Bparsed.ext
-
- /
- if (argc
- die("\nPlease enter the file to be parsed\n")
-
- filename argv1
- if (!file_exists(filename) !is_readable(filen
ame)) - die("\nEnter a valid file\n")
16Simplicity - 2
- changes array()
- is_match false
- fh fopen(filename, "r")
- contents fread(fh, filesize(filename))
- fclose(fh)
- pattern "/()/"
- if (preg_match_all(pattern, contents,
matches)) - is_match true
- if (!empty(matches0))
- //change the matched elements to all
lowercase - array_walk(matches0, 'change_to_lowercase')
-
-
- if (!is_match)
- die("\nNo match found\n")
-
17Simplicity - 3
- fh fopen(filename, "w")
- if (!is_writable(filename))
- fclose(fh)
- die("\nFile is not writable\n")
-
- contents str_replace(matches0, changes,
contents) - success fwrite(fh, contents)
- if (success)
- print "\nSuccessfully matched and modified.\n"
-
- fclose(fh)
18Premature optimization
- Often obfuscates code, and often done without a
good rational reason to do so - function foo(bar)
19Coding standards
- Have and use a coding standard
- Dont 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
20How 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?)
21Example coding standard
- (Excerpts)
- Formatting e.g.
- Always use long form PHP tags
- Two space indents throughout, NO HARD TABS
-
- Naming
- Use camel caps for OO identifiers (classnames,
methods, member variables), like this
theVarCalledFoo -
22Standard - 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
23Standard - 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
-
24Version 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)
25The 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
26Developer education
- Dont underestimate the importance of training.
- How
- Provide code layout and design
- Provide sample code
- Explain whats required
- Give frequent feedback
27Scaling the code base
28Frameworks and Architectures use and abuse
- Frameworks are buzzy, and Rails doesnt 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.
29What do you gain from a framework?
- Standard code layout for that framework
- Often makes developing a prototype fast
30Downside
- Skills dont transfer from one framework to
another - Rapidly prototyped code not necessarily
appropriate for use in production
31Two kinds of frameworks
- MVC style (e.g. Cake)
- Component style (e.g. eZ)
- Both kinds of music (e.g. ZF)
32Database abstraction use and abuse
- Use PDO its a defacto standard
- Standardize on use of prepared statements
33Security
- 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
34Documentation
- 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 its 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
35Maintaining Legacy Code(or, The Ninth Circle of
Hell)
36Maintaining legacy code
- Hell is other peoples 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 didnt document it,
chances are you never will - If it needs a complete rewrite, chances are you
wont have time - You will have to to deal with this at some stage
if you havent already.
37Strategies
- 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
- Dont get too ambitious.
38Questions?