Dutch PHP Conference 2013: Distilled

Post on 10-May-2015

2.576 views 3 download

Tags:

description

A couple of our team members attended DPC13, and this is a subset of some of the interesting talks we wanted to share with the rest of the team.

Transcript of Dutch PHP Conference 2013: Distilled

Dutch PHPConference:Distilled

Chris Saylor

Stephen Young

@cjsaylor

@young_steveo

Focus of this talkPHP by the NumbersEmergent DesignWhat's new in PHP 5.5Unbreakable Domain Models

PHP by the Numbers

Measuring ComplexityCyclomatic complexityN-path complexity

Cyclomatic complexityThe cyclomatic complexity of a method is the count of the number

of independent decision points in the method, plus one for themethod entry.

It's a fancy term for measuring the complexity of a method.Decision points in a method increase complexity.(e.g. if, else, foreach, etc.)Plugins will calculate it for you.(PHP Mess Detector, JSHint, Grunt!)

The lower, the better1—4 low complexity, easy to maintain5—7 moderate complexity8—10 high complexity, hard to test11+ ?

N-path complexityThe number of acyclic execution paths through a function; an

objective measure of complexity related to the ease with whichsoftware can be comprehensively tested

acyclic execution paths?

It's a lot like cyclomatic complexity.It measures how many straight lines you can draw through amethod.A method with a single IF statement has an N-path of 2.A method with 2 IF statements has an N-path of 4.3 IF statements would make the N-path 8.

Another way to look at itThe value of a method's N-path complexity is equal to the numberof unit tests needed to ensure that you have 100% code coverage.

A "quick estimate" for N-Path:

2̂(cyclomaticComplexity - 1)

You have probably seen thisRunning Grunt!

Running "jshint:source" (jshint) task

Linting app/webroot/js/views/doesEverythingView.js...

ERROR

[L31:C38] W074: This function's cyclomatic complexity is too high. (18)

Things to avoidViolating the Single Responsibility Principle

A Controller method with logic to perform CRUD operations.A Product Model with logic for formatting currency.

Seperation of Concerns

Too complex: A single method that executes four businessrules to perform a task.Better: Four methods that each execute a single business rule.

Plan AheadIt's common to be handed a user story that is simple to describe butcomplex to implement.

Take time to break the logic into the smallest possible units beforewriting code.

Emergent Design withPHPSpec

Topics covered1. PHPSpec overview2. emergent design3. simple design & smells4. designing composition with mocks

What is PHPSpec?

it started as a port for rspec

ProblemPHP !== Ruby

in ruby everything is an object

and all objects are openAlso, monkey patching code at runtime is a typical practice in the Ruby world.

blowling.score.should eq(0)

an early PHPSpec syntax example

Trying to emulate ruby in PHP looks ugly

$this->spec($bowling->getScore())->shouldEqual(0);

PHPSpec's new goalsfun to work withdevelopment toollet's not get in the wayenforce TDDdo it the PHP way

Test Driven Developmentyellow — Write the test first

red — Implement the class/method; test is failing

green — Test is passing

How PHPUnit handles the Yellow stepPHPUnit 3.7.14 by Sebastian Bergmann.

PHP Fatal error: Class 'Markdown' not found in /Users/stephenyoung/Documents/projects/Lab/phpunit/tests/MarkdownTest.php on line 8

Fatal error: Class 'Markdown' not found in /Users/stephenyoung/Documents/projects/Lab/phpunit/tests/MarkdownTest.php on line 8

How PHPSpec handles the Yellow step

it does this for missing methods too.

> spec\Customer ✘ it converts plain text to html paragraphs Class Markdown does not exist. Do you want me to create it for you? [Y/n]

MockingIt suffices to say that mocking is painful in PHPUnit.

PHPSpec has a very easy-to-use Mocking library.

Too much to go into here.

That's Enough about PHPSpecIt's a pretty awesome tool. Go check it out.

Emergent Design

What is software design?

Software designis

the art of describing how to to solve a problem.

First learn design, then learn emergentdesign

Alan Kay on Messaging

"The key in making great and growable systems ismuch more to design how its modules

communicate rather than what their internalproperties and behaviors should be."

$this->person->getCar()->getEngine()->ignite();

Focusing on messaging makes code moreflexible

$this->person->startCar();

Software designis

the art of describing how to to solve problems with roles,responsibilities and messages

Big Design Up FrontIt's hard to change later.We need to think about things before developing.We need to make sure we don't miss anything.This is just the way we do it.

Y A G N I

61%of all requested features are actually

delivered

27%of all requested features are actually used

5% to 10%are responsible for realising the

envisioned benefits

we should design for the high priority items and make it easy tochange later.

Agile Software designis

the art of describing how to to solve problems with roles,responsibilities and messages

in a change-friendly way

Easier said than done?

1. Test2. Code3. Refactor4. Repeat

Use simple design rules to refactor1. All tests run and pass

2. Remove duplication

3. Remove opacity

4. Remove complexity

What is the result of this method in yourcode?

It is testable.

It is modular.

It is expressive.

It is simple.

What is the alternative?Viscosity

Immobility, Rigidity, Fragility

Unreadable

Complex

Simple design enables smell detection

Simple Design1. All tests run and pass

2. Remove duplication

3. Remove opacity

4. Remove complexity

smells1. Test smells?

2. DRY smells?

3. Opacity smells?

4. Complexity smells?

Test smellsLack of testsSetup is too complexUnclear exerciseNo expectation

DRY SmellsCopy PastaLogic duplicationDuplicated constantsAlternative classes with different interfaces

Opacity smellsNaming not in the domainName does not express intentFeature envyMethod too longMethod does more than one thing

Complexity smellsUnnecessary elseUnnecessary ifUnnecessary switchToo many passed arguments

Use design patterns to refactor

What can happen in a method?return a valuethrow an exceptiondelegatemodify state not the final behavior

print something we should probably delegate that too

Design delegation with mocks

start by defining behavior

internally delegate to another method

FinallyDefine new roleExtract collaborators using mocksMove behavior definition to new collaborator test

What's new in PHP 5.5

PerformancePerformance boost compared to 5.3 -> 5.4 is not as great as 5.4 ->

5.5

APC replacementZend's OPCache is now packaged with PHP 5.5 and APC is now

depricated

array_column $keyValues = [ ['key1' => 'val1', 'key2' => 'val2'], ['key1' => 'val3', 'key2' => 'val4'] ]; var_dump(array_column($keyValues, 'key1')); // yields array('val1', 'val3')

Foreach with list $test = [ [1, 2], [3, 4] ]; foreach ($test as list($a, $b)) { echo "a: $a; b: $b"; } // displays: // a: 1; b: 2 // a: 3; b: 4

Finally a finally! try { doSomeWork(); return true; } finally { cleanUpSomeStuff(); echo "I am reachable!"; } echo "I am not reachable :( ";

Generators function lotsOfRecords() { while ($row = $this->db->getNext()) { yield $row['id'] => $row; } } foreach (lotsOfRecords() as $id => $row) { // do stuff }

Password hashing API echo password_hash('somepassword', \PASSWORD_BCRYPT); // $2y$12$QjSH496pcT5CEbzjD/vtVeH03tfHKFy36d4J0Ltp3lRtee9HDxY3K password_verify( 'somepassword', '$2y$12$QjSH496pcT5CEbzjD/vtVeH03tfHKFy36d4J0Ltp3lRtee9HDxY3K' ); // true

Unbreakable Domain Models

Use objects as consistencyboundaries

class Customer { public function __construct($email) { if( /* ugly regex here */) { throw new \InvalidArgumentException(); } $this->email = $email; } }

Single Responsibility Principle class Email { private $email; public function __construct($email) { if( /* ugly regex here */) { throw new \InvalidArgumentException(); } $this->email = $email; } public function __toString() { return $this->email; } }

Customer class is now tighter class Customer { /** @var Email */ private $email; public function __construct(Email $email) { $this->email = $email; } }

Encapsulate state andbehavior with Value Objects

A user story may be:

"A customer orders products and pays for them."

Procedural $order = new Order; $order->setCustomer($customer); $order->setProducts($products); $order->setStatus(Order::UNPAID); // ... $order->setPaidAmount(500); $order->setPaidCurrency(‘EUR’); $order->setStatus(Order::PAID);

Improve it with object forconsistency

$order = new Order; $order->setCustomer($customer); $order->setProducts($products); $order->setStatus( new PaymentStatus(PaymentStatus::UNPAID) ); $order->setPaidAmount(500); $order->setPaidCurrency(‘EUR’); $order->setStatus( new PaymentStatus(PaymentStatus::PAID) );

Improve it with moreconsistency

$order = new Order; $order->setCustomer($customer); $order->setProducts($products); $order->setStatus( new PaymentStatus(PaymentStatus::UNPAID) ); $order->setPaidMonetary( new Money(500, new Currency(‘EUR’)) ); $order->setStatus( new PaymentStatus(PaymentStatus::PAID) );

Even more $order = new Order($customer, $products); // set PaymentStatus in Order::__construct() $order->setPaidMonetary( new Money(500, new Currency(‘EUR’)) ); $order->setStatus( new PaymentStatus(PaymentStatus::PAID) );

Getting ridiculous now $order = new Order($customer, $products); $order->pay( new Money(500, new Currency(‘EUR’)) ); // set PaymentStatus in Order#pay()

Encapsulation throughspecification

"I want to give a discount to a customer that has at least 3 orders."

interface CustomerSpecification { /** @return bool */ public function isSatisfiedBy(Customer $customer); }

class CustomerIsPremium implements CustomerSpecification { private $orderRepository; public function __construct( OrderRepository $orderRepository ) {...} /** @return bool */ public function isSatisfiedBy(Customer $customer) { $count = $this->orderRepository->countFor($customer); return $count >= 3; } } $customerIsPremium = new CustomerIsPremium($orderRepository) if($customerIsPremium->isSatisfiedBy($customer)) { // send special offer }

CreditsPHP By the numbers - Anthony FerraraEmergent Design with phpspec - Marcello DuarteUnbreakable Domain Models - Mathias VerraesLet's have a look at PHP 5.5 - Julien Pauli