You are on page 1of 60

php | tek - Chicago, May 16-18, 2007

Writing Maintainable PHP Code

Organizing for Change

Jeff Moore

Jeff Moore

First programming job in 1987Jeff Moore 9 years working on the same ERP system PHP Since 2000

9 years working on the same ERP systemJeff Moore First programming job in 1987 PHP Since 2000

PHP Since 2000Jeff Moore First programming job in 1987 9 years working on the same ERP system

What is Maintainable Code?

Maintainable Code is

Quick to changeMaintainable Code is Safe to change

Safe to changeMaintainable Code is Quick to change

Maintainability is About Change

“The system doesn’t handle this case”Maintainability is About Change “This is too hard to do” A new law goes into effect

“This is too hard to do”is About Change “The system doesn’t handle this case” A new law goes into effect “Good

A new law goes into effectChange “The system doesn’t handle this case” “This is too hard to do” “Good news, we’ve

“Good news, we’ve been bought out”is About Change “The system doesn’t handle this case” “This is too hard to do” A

How Do You React To Change?

How Do You React To Change? Excitement! Great idea We can do that

Excitement!

Great ideaHow Do You React To Change? Excitement! We can do that

We can do thatHow Do You React To Change? Excitement! Great idea

How Do You React To Change? Excitement! Great idea We can do that

How Do You React To Change?

How Do You React To Change? Fear That won’t work because We’ll do that someday

Fear

That won’t work becauseHow Do You React To Change? Fear We’ll do that someday

We’ll do that somedayHow Do You React To Change? Fear That won’t work because

Much of Programming is Maintenance

Successful small systems grow into large systemsMuch of Programming is Maintenance Systems last longer than you expect

Systems last longer than you expectMuch of Programming is Maintenance Successful small systems grow into large systems

Organizing For Change

How Do You Organize Your Stuff?

Put tools and materials for a specific task in one placeHow Do You Organize Your Stuff? Eliminate distractions Have different places for different tasks

Eliminate distractionsOrganize Your Stuff? Put tools and materials for a specific task in one place Have different

Have different places for different tasksHow Do You Organize Your Stuff? Put tools and materials for a specific task in one

Mise en Place

Everything in placeMise en Place Clean up as you go Don’t leave a mess

Clean up as you goMise en Place Everything in place Don’t leave a mess

Don’t leave a messMise en Place Everything in place Clean up as you go

Refactoring

Improving the design of existing soft ware without changing its behaviorRefactoring Cleaning up code as we go Book by Martin Fowler

Cleaning up code as we goRefactoring Improving the design of existing soft ware without changing its behavior Book by Martin Fowler

Book by Martin FowlerRefactoring Improving the design of existing soft ware without changing its behavior Cleaning up code as

Code Smells

Code Smells Signs that you need to refactor

Signs that you need to refactor

Smell: Duplicate Code

When the same code exists in more than one place changes have to be made in more than one placeSmell: Duplicate Code Its easy to miss a change It takes time to analyze variation

Its easy to miss a changesame code exists in more than one place changes have to be made in more than

It takes time to analyze variationWhen the same code exists in more than one place changes have to be made in

Smell: Shotgun Surgery

Smell: Shotgun Surgery When a single change requires visiting many places in the code

When a single change requires visiting many places in the code

The Rule Of Threes

First time just do itThe Rule Of Threes Second time, wince and ignore it Third time, eliminate the duplication

Second time, wince and ignore itThe Rule Of Threes First time just do it Third time, eliminate the duplication

Third time, eliminate the duplicationThe Rule Of Threes First time just do it Second time, wince and ignore it

Put Things that are Alike Together

Grouping PHP Code

ApplicationGrouping PHP Code Package File Namespace Class Function Braces Whitespace

PackageGrouping PHP Code Application File Namespace Class Function Braces Whitespace

FileGrouping PHP Code Application Package Namespace Class Function Braces Whitespace

NamespaceGrouping PHP Code Application Package File Class Function Braces Whitespace

ClassGrouping PHP Code Application Package File Namespace Function Braces Whitespace

FunctionGrouping PHP Code Application Package File Namespace Class Braces Whitespace

BracesGrouping PHP Code Application Package File Namespace Class Function Whitespace

WhitespaceGrouping PHP Code Application Package File Namespace Class Function Braces

Cohesion How closely is the code in a group related?

Cohesion

How closely is the code in a group related?

Poor Cohesion

function import($valueList, $append = FALSE) { if ($append) { $this->vars += $valueList; } else { $this->vars = $valueList;

}

}

$obj->import($values, TRUE);

Smell: Boolean Parameters

Indicates lack of cohesionSmell: Boolean Parameters Hard to understand in calling context

Hard to understand in calling contextSmell: Boolean Parameters Indicates lack of cohesion

Better

define(‘REPLACE’, 0); define(‘APPEND’, 1);

function import($valueList, $mode = REPLACE) { if ($mode == APPEND) { $this->vars += $valueList; } else { $this->vars = $valueList;

}

}

$obj->import($values, APPEND);

Smell: Type Code Parameters

Smell: Type Code Parameters Can indicate lack of cohesion

Can indicate lack of cohesion

Best

function append($valueList) { $this->vars += $valueList;

}

function replace($valueList) { $this->vars = $valueList;

}

$obj->append($values);

Good Cohesion

Communicational Lines operate on the same dataGood Cohesion Sequential Output from one line is input to the next Functional All lines contribute

SequentialGood Cohesion Communicational Lines operate on the same data Output from one line is input to

Communicational Lines operate on the same data Sequential Output from one line is input to the

Output from one line is input to the nextGood Cohesion Communicational Lines operate on the same data Sequential Functional All lines contribute to the

Functional All lines contribute to the same taskGood Cohesion Communicational Lines operate on the same data Sequential Output from one line is input

on the same data Sequential Output from one line is input to the next Functional All

Smell: Divergent Change

When the came code changes for different reasonsSmell: Divergent Change Indicates poor cohesion

Indicates poor cohesionSmell: Divergent Change When the came code changes for different reasons

Keep Things That Are Different Apart

Unwanted Interactions

A change in one place causes an unwanted effect in anotherUnwanted Interactions Requires time researching and doing due diligence before making a change Risk may prevent

Requires time researching and doing due diligence before making a changeUnwanted Interactions A change in one place causes an unwanted effect in another Risk may prevent

Risk may prevent change entirelyin one place causes an unwanted effect in another Requires time researching and doing due diligence

Dependencies

Defining dependencies in terms of change:Dependencies Soft ware element A depends upon B if “You can postulate some change to B

Soft ware element A depends upon B if “You can postulate some change to B that would require both A and B to be changed together in order to preser ve overall correctness.” - Meiler Page-JonesDependencies Defining dependencies in terms of change:

Coupling The degree to which a soft ware group is related to other parts of

Coupling

The degree to which a soft ware group is related to other parts of the program

Tools for Limiting Coupling in PHP

Variable Scopes

Application (Global)Variable Scopes $_GLOBALS[‘var’]; Class (Object) $this->var; self::$var; Function (Local) $var;

$_GLOBALS[‘var’];Variable Scopes Application (Global) Class (Object) $this->var; self::$var; Function (Local) $var;

Class (Object)Variable Scopes Application (Global) $_GLOBALS[‘var’]; $this->var; self::$var; Function (Local) $var;

$this->var;Variable Scopes Application (Global) $_GLOBALS[‘var’]; Class (Object) self::$var; Function (Local) $var;

self::$var;Variable Scopes Application (Global) $_GLOBALS[‘var’]; Class (Object) $this->var; Function (Local) $var;

Function (Local)Variable Scopes Application (Global) $_GLOBALS[‘var’]; Class (Object) $this->var; self::$var; $var;

$var;Variable Scopes Application (Global) $_GLOBALS[‘var’]; Class (Object) $this->var; self::$var; Function (Local)

Visibility

PrivateVisibility Protected Public

ProtectedVisibility Private Public

PublicVisibility Private Protected

Encapsulation

Limiting interactionsEncapsulation Information hiding Strong encapsulation groups have names May have a variable scope May specify element

Information hidingEncapsulation Limiting interactions Strong encapsulation groups have names May have a variable scope May specify element

Strong encapsulation groups have namesEncapsulation Limiting interactions Information hiding May have a variable scope May specify element visibility

May have a variable scopeLimiting interactions Information hiding Strong encapsulation groups have names May specify element visibility

May specify element visibilityEncapsulation Limiting interactions Information hiding Strong encapsulation groups have names May have a variable scope

What Happens When We Don’t Encapsulate?

.ini Options

146 .ini options in my PHP.ini Options Invisible parameters to every function and class Equivalent to global variables

Invisible parameters to every function and class.ini Options 146 .ini options in my PHP Equivalent to global variables

Equivalent to global variables.ini Options 146 .ini options in my PHP Invisible parameters to every function and class

.ini Strategies

Set them up front Easy.ini Strategies Documents your choices Set and restore Portable Easy to miss something

.ini Strategies Set them up front Easy Documents your choices Set and restore Portable Easy to

Documents your choices.ini Strategies Set them up front Easy Set and restore Portable Easy to miss something

Set and restore Portable Easy to miss something.ini Strategies Set them up front Easy Documents your choices

.ini Strategies Set them up front Easy Documents your choices Set and restore Portable Easy to
.ini Strategies Set them up front Easy Documents your choices Set and restore Portable Easy to

Global Keyword is Evil

global $var;Global Keyword is Evil Destroys the distinction bet ween global and local variables Global variables should

Destroys the distinction bet ween global and local variablesGlobal Keyword is Evil global $var; Global variables should be hard to use $_GLOBALS[‘var’]

Global variables should be hard to useGlobal Keyword is Evil global $var; Destroys the distinction bet ween global and local variables $_GLOBALS[‘var’]

$_GLOBALS[‘var’]is Evil global $var; Destroys the distinction bet ween global and local variables Global variables should

Main Line Code

More opportunities for interactionMain Line Code Avoid main line code

Avoid main line codeMain Line Code More opportunities for interaction

Keep Things That Are Different Apart

Separation of Concerns

Put things that change for different reasons in different placesSeparation of Concerns Templating MVC

TemplatingSeparation of Concerns Put things that change for different reasons in different places MVC

MVCSeparation of Concerns Put things that change for different reasons in different places Templating

Anticipating Changes

Separation of concerns requires anticipating the likely changesAnticipating Changes MVC allows the view to change independently of the other layers MVC also requires

MVC allows the view to change independently of the other layersof concerns requires anticipating the likely changes MVC also requires some changes to be made in

MVC also requires some changes to be made in 3 places instead of 1requires anticipating the likely changes MVC allows the view to change independently of the other layers

Balance tradeoffsthe view to change independently of the other layers MVC also requires some changes to be

Testing and Maintainability

Testing and Maintainability

Unmaintainable code is hard to testTesting and Maintainability Maintainable code is easier to test To write maintainable code, write testable code

Maintainable code is easier to testTesting and Maintainability Unmaintainable code is hard to test To write maintainable code, write testable code

To write maintainable code, write testable codeTesting and Maintainability Unmaintainable code is hard to test Maintainable code is easier to test

What Makes Code Hard to Test?

Cyclomatic Complexity

The number of decision points in the code plus oneCyclomatic Complexity Count each if, while, each case in a switch A.k.a Conditional Complexity Soft ware

Count each if, while, each case in a switchThe number of decision points in the code plus one A.k.a Conditional Complexity Soft ware metric

A.k.a Conditional Complexitypoints in the code plus one Count each if, while, each case in a switch Soft

Soft ware metric for measuring maintainability?number of decision points in the code plus one Count each if, while, each case in

Conditional Complexity

if ($condition) { $x = getA(); } else { $x = getB();

}

3
3

foreach ($x => $message) { echo $message;

}

Smell: Long Method

Long methods are hard to maintainSmell: Long Method How long is too long? Conditional complexity > 10 is too long

How long is too long?Smell: Long Method Long methods are hard to maintain Conditional complexity > 10 is too long

Conditional complexity > 10 is too longSmell: Long Method Long methods are hard to maintain How long is too long?

Conditional Complexity and Testing

Estimate of the number of test cases you will need to writeConditional Complexity and Testing The maximum number of paths through the code to achieve branch coverage

The maximum number of paths through the code to achieve branch coverageConditional Complexity and Testing Estimate of the number of test cases you will need to write

Coverage

Line CoverageCoverage Has every line in the program been executed? Branch Coverage Has both the true and

Has every line in the program been executed?Coverage Line Coverage Branch Coverage Has both the true and false branch of every decision in

Branch CoverageLine Coverage Has every line in the program been executed? Has both the true and false

Has both the true and false branch of every decision in the program been taken?Coverage Line Coverage Has every line in the program been executed? Branch Coverage

Why Are Fewer Conditionals Easier to Maintain?

Avoid Conditional Code?

Smell: Switch Statements

switch ($shape) { ‘circle’:

3
3

$area = PI * $radius * $radius; break; ‘rectangle’:

$area = $width * $height; break;

}

With Polymorphism

1
1

class Circle { function area() { return PI * $this->radius ** 2;With Polymorphism 1 } } class Rectangle { function area() { return $this->width * $this->height; }

}

}

class Rectangle { function area() { return $this->width * $this->height;With Polymorphism 1 class Circle { function area() { return PI * $this->radius ** 2; }

}

}

1
1

Testing Makes Code Safe to Change

Having a full test suite reduces fear of changeTesting Makes Code Safe to Change Tests increase confidence in the correctness of the change Tests

Tests increase confidence in the correctness of the changeTesting Makes Code Safe to Change Having a full test suite reduces fear of change Tests

Tests increase the speed of changeSafe to Change Having a full test suite reduces fear of change Tests increase confidence in

Consistency

Coding Standards

Standardize the stuff that doesn’t matterCoding Standards Reveals the patterns in the code that do matter Use the PEAR coding standard

Reveals the patterns in the code that do matterCoding Standards Standardize the stuff that doesn’t matter Use the PEAR coding standard

Use the PEAR coding standardCoding Standards Standardize the stuff that doesn’t matter Reveals the patterns in the code that do

Refactored Normalize Form

Refactoring book becoming a standardRefactored Normalize Form Refactoring code smells away leads to consistent code Refactor to standard patterns Reveals

Refactoring code smells away leads to consistent codeNormalize Form Refactoring book becoming a standard Refactor to standard patterns Reveals new patterns in code

Refactor to standard patternsbook becoming a standard Refactoring code smells away leads to consistent code Reveals new patterns in

Reveals new patterns in code that matterRefactoring book becoming a standard Refactoring code smells away leads to consistent code Refactor to standard

Go Write Good Code

Questions?