Slide 1

Slide 1 text

PHP FOR GROWN-UPS

Slide 2

Slide 2 text

ANDREAS PHP DEVELOPER @ MIJNDOMEIN.NL

Slide 3

Slide 3 text

PHP HAS A BAD RAP (WHICH IT PARTLY DESERVES)

Slide 4

Slide 4 text

BUT YOU CAN STILL USE IT TO BUILD SOLID STUFF (IF YOU KNOW HOW)

Slide 5

Slide 5 text

SO LET’S TALK ABOUT THE HOW

Slide 6

Slide 6 text

QUALITIES OF GOOD CODE

Slide 7

Slide 7 text

EASY TO CHANGE EASY TO UNDERSTAND EASY TO (RE)USE ~ HARD TO BREAK

Slide 8

Slide 8 text

“Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live” - probably John Woods

Slide 9

Slide 9 text

SHY CODE

Slide 10

Slide 10 text

“Shy code - modules that don’t reveal anything unnecessary to other modules and that don’t rely on other modules’ implementations” - The Pragmatic Programmer

Slide 11

Slide 11 text

ENCAPSULATION “MODULES THAT DON’T REVEAL ANYTHING UNNECESSARY TO OTHER MODULES”

Slide 12

Slide 12 text

$totalPrice = 0; foreach ($order->getItems() as $item) { $amount = $item->getAmount(); $price = $item->getPrice(); $totalPrice += $amount * $price; } $totalPrice += $order->getShippingCosts();

Slide 13

Slide 13 text

$totalPrice = $order->getTotalPrice();

Slide 14

Slide 14 text

TELL, DON’T ASK

Slide 15

Slide 15 text

$order->applyDiscount($discountPercentage);

Slide 16

Slide 16 text

“[...] modules that don’t rely on other modules’ implementations”

Slide 17

Slide 17 text

interface EventDispatcher { public function dispatch(Event $event); }

Slide 18

Slide 18 text

public function __construct(EventDispatcher $eventDispatcher) { $this->eventDispatcher = $eventDispatcher }

Slide 19

Slide 19 text

class SymfonyEventDispatcher implements EventDispatcher { public function dispatch(Event $event) { // Symfony implementation here } }

Slide 20

Slide 20 text

public function __construct(EventDispatcher $eventDispatcher) { $this->eventDispatcher = $eventDispatcher }

Slide 21

Slide 21 text

FROM THE PERSPECTIVE OF THE CONSUMER THE INTERFACE IS THE REAL THING

Slide 22

Slide 22 text

“MATHEMATICS ABSTRACTION IS THE ART OF GIVING THE SAME NAME TO DIFFERENT THINGS.” ~ HENRI POINCARÉ’S PROGRAMMER COUSIN

Slide 23

Slide 23 text

/** * before: */ public function search($searchTerm, $productCategory, $make, $color) { switch ($productType) { case ‘car’: // search cars case ‘boat’: // search boat // etc. } }

Slide 24

Slide 24 text

/** * after: */ public function search(SearchQuery $query) { $worker = $this->getWorkerForQuery($query); /** @var SearchResults $results */ $results = $worker->process($query); return $results; }

Slide 25

Slide 25 text

”BUT... YOU JUST INTRODUCED COUPLING!”

Slide 26

Slide 26 text

“Figuring out if two people are married is easy. Figuring out if they should be is hard.” - Michael Feathers

Slide 27

Slide 27 text

LEVELS OF ABSTRACTION

Slide 28

Slide 28 text

LOW LEVEL OF ABSTRACTION $statement = $database->prepare( “INSERT INTO `fish`(‘name’, ‘species’, ‘gender’, ‘tankId’) ” . “VALUES(?, ?, ?, ?)” ); $statement->execute(array(‘Nemo’, $speciesId, ‘M’, $tankId));

Slide 29

Slide 29 text

HIGH LEVEL OF ABSTRACTION $command = new IntroduceFishCommand($fish, $tank); $this->commandBus->execute($command);

Slide 30

Slide 30 text

LAYERED ARCHITECTURE

Slide 31

Slide 31 text

DATABASE QUERIES IN CONTROLLER CODE BUSINESS LOGIC IN VIEWS VIEW LOGIC IN DOMAIN OBJECTS

Slide 32

Slide 32 text

MIXING LEVELS OF ABSTRACTION MAKES CODE HARDER TO UNDERSTAND

Slide 33

Slide 33 text

“THE RATIO OF TIME SPENT READING CODE VERSUS WRITING IS WELL OVER 10 TO 1” ~ UNCLE BOB

Slide 34

Slide 34 text

“THERE ARE ONLY TWO HARD THINGS IN COMPUTER SCIENCE: CACHE INVALIDATION AND NAMING THINGS” ~ PHIL KARLTON

Slide 35

Slide 35 text

// not: $light->setStatus(true); // but: $light->switchOn();

Slide 36

Slide 36 text

NAMES THAT LIE // neither of these is actually a locale $this->locale = $locale->locale; // does more than it says public function getItem() { // write to disk }

Slide 37

Slide 37 text

EXTRACT METHOD // before: if (is_numeric($amount) && $amount > 0) // after: if ($this->isValidAmount($amount))

Slide 38

Slide 38 text

VALUE OBJECTS $amount = new Amount($amount); // throws exception if amount is invalid

Slide 39

Slide 39 text

CODE SAYS WHAT COMMENTS SAY WHY

Slide 40

Slide 40 text

// set the patient’s clinic $patient->setClinic($clinic); // to register a patient, set the patient’s clinic $patient->setClinic($clinic);

Slide 41

Slide 41 text

GOOD NAMING AND GOOD ABSTRACTIONS BEAT GOOD COMMENTS

Slide 42

Slide 42 text

$clinic->registerPatient($patient);

Slide 43

Slide 43 text

PRINCIPLE OF LEAST ASTONISHMENT (MINIMIZE THE NUMBER OF WTFS PER MINUTE)

Slide 44

Slide 44 text

“I REUSE CODE IF, AND ONLY IF, I NEVER NEED TO LOOK AT THE SOURCE CODE” ~ UNCLE BOB

Slide 45

Slide 45 text

WELL-ABSTRACTED GOOD OUTWARD-FACING API DECOUPLED

Slide 46

Slide 46 text

NAMESPACES PREVENTING NAMING COLLISIONS SINCE PHP 5.3

Slide 47

Slide 47 text

COMPOSER

Slide 48

Slide 48 text

OPEN SOURCE VIA GITHUB/PACKAGIST PRIVATE REPOSITORIES IN COMPOSER.JSON TORAN PROXY

Slide 49

Slide 49 text

ADDED BONUS AUTOLOADING FOR INTERNAL CLASSES (THIS ALONE MAKES COMPOSER WORTH USING)

Slide 50

Slide 50 text

PHPDOC DOCBLOCKS IDE USERS LOVE THIS

Slide 51

Slide 51 text

”SIMPLICITY IS PREREQUISITE FOR RELIABILITY.” ~ EDSGER DIJKSTRA

Slide 52

Slide 52 text

”Rely only on reliable things” - The Pragmatic Programmer

Slide 53

Slide 53 text

NOT A RELIABLE THING: THE PHP TYPE SYSTEM

Slide 54

Slide 54 text

if (! $amount) { // do something } // $amount can actually be 0, “0”, “”, null or false for this to be true

Slide 55

Slide 55 text

if ($amount == 0) { // do something } // $amount can now still be 0, “0” or false for this to be true

Slide 56

Slide 56 text

if ($amount === 0) { // do something } // this will only evaluate to true when $amount is actually the number 0

Slide 57

Slide 57 text

“CRASH, DON’T TRASH” ~ THE PRAGMATIC PROGRAMMER

Slide 58

Slide 58 text

DO NOT PROGRAM BY COINCIDENCE

Slide 59

Slide 59 text

”TEST YOUR SOFTWARE, OR YOUR USERS WILL” ~ THE PRAGMATIC PROGRAMMER

Slide 60

Slide 60 text

PHPUNIT PHPSPEC CODECEPTION BEHAT

Slide 61

Slide 61 text

“WHEN YOU AREN’T AFRAID TO CHANGE YOUR CODE, YOU WILL CLEAN IT” ~ UNCLE BOB

Slide 62

Slide 62 text

LANGUAGE FEATURES TYPEHINTING VISIBILITY (PRIVATE BY DEFAULT) EXCEPTIONS

Slide 63

Slide 63 text

CLOSING NOTES

Slide 64

Slide 64 text

LEARNING ABOUT THIS STUFF IS EASY DOING IT RIGHT IS HARD

Slide 65

Slide 65 text

“TO A MAN WITH A HAMMER, EVERYTHING LOOKS LIKE A NAIL.” ~ ABRAHAM MASLOW

Slide 66

Slide 66 text

NONE OF THESE IDEAS ARE NEW (IN FACT, MOST ARE PRETTY OLD)

Slide 67

Slide 67 text

“THE MORE I LEARN, THE MORE I REALIZE HOW MUCH I DON’T KNOW” ~ ALBERT EINSTEIN

Slide 68

Slide 68 text

BOOKS Growing Object-Oriented Software, Guided By Tests The Pragmatic Programmer Domain-Driven Design Patterns of Enterprise Application Architecture Clean Code

Slide 69

Slide 69 text

VIDEOS Models and Service Layers; Hemoglobin and Hobgoblins (https://www.youtube.com/watch?v=3uV3ngl1Z8g) Unbreakable Domain Models (https://www.youtube.com/watch?v=ZJ63ltuwMaE) The Framework As An Implementation Detail (https://www.youtube.com/watch?v=0L_9NutiJlc)

Slide 70

Slide 70 text

PODCASTS Elephant in the Room (http://elephantintheroom.io)

Slide 71

Slide 71 text

QUESTIONS?

Slide 72

Slide 72 text

PLUG TIME WERKENBIJMIJNDOMEIN.NL

Slide 73

Slide 73 text

BONUS STAGE SOLID PRINCIPLES

Slide 74

Slide 74 text

“A CLASS SHOULD HAVE ONE, AND ONLY ONE, REASON TO CHANGE.” ~ SOLID PRINCIPLE #1 (SINGLE RESPONSIBILITY PRINCIPLE)

Slide 75

Slide 75 text

“A CLASS SHOULD BE OPEN FOR EXTENSION, BUT CLOSED FOR MODIFICATION” ~ SOLID PRINCIPLE #2 (OPEN-CLOSED PRINCIPLE)

Slide 76

Slide 76 text

”CHANGE WHAT A CLASS DOES, BUT NOT WHAT IT IS” ~ KONSTANTIN KUDRYASHOV

Slide 77

Slide 77 text

“SUBCLASSES MUST BE SUBSTITUTABLE FOR THEIR BASE CLASSES” ~ SOLID PRINCIPLE #3 (LISKOV SUBSTITUTION PRINCIPLE)

Slide 78

Slide 78 text

”NEVER FORCE CLASSES TO IMPLEMENT METHODS THAT THEY DO NOT USE” ~ SOLID PRINCIPLE #4 (INTERFACE SEGREGATION PRINCIPLE)

Slide 79

Slide 79 text

interface DoesAllTheThings { public function save(Soul $soul); public function addOneAndOne(One $one, One $one); public function shave(Yak $yak); }

Slide 80

Slide 80 text

class DefaultCalculator implements Calculator { public function addOneAndOne(One $one, One $one) { return new Two; } }

Slide 81

Slide 81 text

class DoesAllTheThings implements SoulSaver, Calculator, YakShaver { // can still do all the things }

Slide 82

Slide 82 text

“DEPEND ON ABSTRACTIONS, NOT ON CONCRETIONS” ~ SOLID PRINCIPLE #5 (DEPENDENCY INVERSION PRINCIPLE)