dutch php conference 2013: distilled

87
Dutch PHP Conference: Distilled Chris Saylor Stephen Young @cjsaylor @young_steveo

Upload: zumba-fitness-technology-team

Post on 10-May-2015

2.577 views

Category:

Technology


3 download

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

Page 1: Dutch PHP Conference 2013: Distilled

Dutch PHPConference:Distilled

Chris Saylor

Stephen Young

@cjsaylor

@young_steveo

Page 2: Dutch PHP Conference 2013: Distilled

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

Page 3: Dutch PHP Conference 2013: Distilled

PHP by the Numbers

Page 4: Dutch PHP Conference 2013: Distilled

Measuring ComplexityCyclomatic complexityN-path complexity

Page 5: Dutch PHP Conference 2013: Distilled

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.

Page 6: Dutch PHP Conference 2013: Distilled
Page 7: Dutch PHP Conference 2013: Distilled

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

Page 8: Dutch PHP Conference 2013: Distilled

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

Page 9: Dutch PHP Conference 2013: Distilled
Page 10: Dutch PHP Conference 2013: Distilled

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

Page 11: Dutch PHP Conference 2013: Distilled

acyclic execution paths?

Page 12: Dutch PHP Conference 2013: Distilled

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.

Page 13: Dutch PHP Conference 2013: Distilled

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)

Page 14: Dutch PHP Conference 2013: Distilled

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)

Page 15: Dutch PHP Conference 2013: Distilled

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.

Page 16: Dutch PHP Conference 2013: Distilled

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.

Page 17: Dutch PHP Conference 2013: Distilled
Page 18: Dutch PHP Conference 2013: Distilled
Page 19: Dutch PHP Conference 2013: Distilled

Emergent Design withPHPSpec

Page 20: Dutch PHP Conference 2013: Distilled

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

Page 21: Dutch PHP Conference 2013: Distilled

What is PHPSpec?

Page 22: Dutch PHP Conference 2013: Distilled

it started as a port for rspec

Page 23: Dutch PHP Conference 2013: Distilled

ProblemPHP !== Ruby

Page 24: Dutch PHP Conference 2013: Distilled

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)

Page 25: Dutch PHP Conference 2013: Distilled

an early PHPSpec syntax example

Trying to emulate ruby in PHP looks ugly

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

Page 26: Dutch PHP Conference 2013: Distilled

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

Page 27: Dutch PHP Conference 2013: Distilled

Test Driven Developmentyellow — Write the test first

red — Implement the class/method; test is failing

green — Test is passing

Page 28: Dutch PHP Conference 2013: Distilled

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

Page 29: Dutch PHP Conference 2013: Distilled

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]

Page 30: Dutch PHP Conference 2013: Distilled

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.

Page 31: Dutch PHP Conference 2013: Distilled

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

Page 32: Dutch PHP Conference 2013: Distilled

Emergent Design

Page 33: Dutch PHP Conference 2013: Distilled

What is software design?

Page 34: Dutch PHP Conference 2013: Distilled

Software designis

the art of describing how to to solve a problem.

Page 35: Dutch PHP Conference 2013: Distilled

First learn design, then learn emergentdesign

Page 36: Dutch PHP Conference 2013: Distilled

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."

Page 37: Dutch PHP Conference 2013: Distilled
Page 38: Dutch PHP Conference 2013: Distilled

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

Page 39: Dutch PHP Conference 2013: Distilled

Focusing on messaging makes code moreflexible

Page 40: Dutch PHP Conference 2013: Distilled

$this->person->startCar();

Page 41: Dutch PHP Conference 2013: Distilled

Software designis

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

Page 42: Dutch PHP Conference 2013: Distilled

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.

Page 43: Dutch PHP Conference 2013: Distilled

Y A G N I

Page 44: Dutch PHP Conference 2013: Distilled

61%of all requested features are actually

delivered

Page 45: Dutch PHP Conference 2013: Distilled

27%of all requested features are actually used

Page 46: Dutch PHP Conference 2013: Distilled

5% to 10%are responsible for realising the

envisioned benefits

Page 47: Dutch PHP Conference 2013: Distilled

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

Page 48: Dutch PHP Conference 2013: Distilled

Agile Software designis

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

in a change-friendly way

Page 49: Dutch PHP Conference 2013: Distilled

Easier said than done?

Page 50: Dutch PHP Conference 2013: Distilled

1. Test2. Code3. Refactor4. Repeat

Page 51: Dutch PHP Conference 2013: Distilled

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

2. Remove duplication

3. Remove opacity

4. Remove complexity

Page 52: Dutch PHP Conference 2013: Distilled

What is the result of this method in yourcode?

It is testable.

It is modular.

It is expressive.

It is simple.

Page 53: Dutch PHP Conference 2013: Distilled

What is the alternative?Viscosity

Immobility, Rigidity, Fragility

Unreadable

Complex

Page 54: Dutch PHP Conference 2013: Distilled

Simple design enables smell detection

Page 55: Dutch PHP Conference 2013: Distilled

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?

Page 56: Dutch PHP Conference 2013: Distilled

Test smellsLack of testsSetup is too complexUnclear exerciseNo expectation

Page 57: Dutch PHP Conference 2013: Distilled

DRY SmellsCopy PastaLogic duplicationDuplicated constantsAlternative classes with different interfaces

Page 58: Dutch PHP Conference 2013: Distilled

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

Page 59: Dutch PHP Conference 2013: Distilled

Complexity smellsUnnecessary elseUnnecessary ifUnnecessary switchToo many passed arguments

Page 60: Dutch PHP Conference 2013: Distilled

Use design patterns to refactor

Page 61: Dutch PHP Conference 2013: Distilled

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

print something we should probably delegate that too

Page 62: Dutch PHP Conference 2013: Distilled

Design delegation with mocks

Page 63: Dutch PHP Conference 2013: Distilled

start by defining behavior

Page 64: Dutch PHP Conference 2013: Distilled

internally delegate to another method

Page 65: Dutch PHP Conference 2013: Distilled

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

Page 66: Dutch PHP Conference 2013: Distilled

What's new in PHP 5.5

Page 67: Dutch PHP Conference 2013: Distilled

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

5.5

Page 68: Dutch PHP Conference 2013: Distilled

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

depricated

Page 69: Dutch PHP Conference 2013: Distilled

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

Page 70: Dutch PHP Conference 2013: Distilled

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

Page 71: Dutch PHP Conference 2013: Distilled

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

Page 72: Dutch PHP Conference 2013: Distilled

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

Page 73: Dutch PHP Conference 2013: Distilled

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

Page 74: Dutch PHP Conference 2013: Distilled

Unbreakable Domain Models

Page 75: Dutch PHP Conference 2013: Distilled

Use objects as consistencyboundaries

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

Page 76: Dutch PHP Conference 2013: Distilled

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

Page 77: Dutch PHP Conference 2013: Distilled

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

Page 78: Dutch PHP Conference 2013: Distilled

Encapsulate state andbehavior with Value Objects

Page 79: Dutch PHP Conference 2013: Distilled

A user story may be:

"A customer orders products and pays for them."

Page 80: Dutch PHP Conference 2013: Distilled

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

Page 81: Dutch PHP Conference 2013: Distilled

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

Page 82: Dutch PHP Conference 2013: Distilled

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

Page 83: Dutch PHP Conference 2013: Distilled

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

Page 84: Dutch PHP Conference 2013: Distilled

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

Page 85: Dutch PHP Conference 2013: Distilled

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

Page 86: Dutch PHP Conference 2013: Distilled

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 }

Page 87: Dutch PHP Conference 2013: Distilled

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