solid principles

39
S.O.L.I.D Principles Bastian Feder [email protected] OSIDays 2011, Bangalore 21 st November 2011

Upload: bastian-feder

Post on 18-May-2015

1.421 views

Category:

Technology


0 download

DESCRIPTION

Early in year 2000 Robert C. Martin, aka "Uncle Bob", introduced his thoughts in an article about some of five basic principles on object oriented programming to the open world. What he probably did not expect was, that this 5 principles became the standard for object oriented programming. This Talk is about those principles: Single responsibility, Open/close, Liskov substitution, Interface segregation, and Dependency inversion, or shorter S.O.L.I.D. principles. It will give you an introduction about these principles, their meaning, and where they should be recognized and applied. Examples from my daily work will show you the practical aspects of those principles.

TRANSCRIPT

Page 1: Solid principles

S.O.L.I.DPrinciples

Bastian [email protected]

OSIDays 2011, Bangalore21st November 2011

Page 2: Solid principles

Me, myself & I

PHP since 2001

Testing and Quality coach @ Liip Inc.

Opensource addict

PHP manual translations

FluentDOM

phpDox

Page 3: Solid principles

News from Uncle Bob

Essential principles for software development & object oriented design (OOD).

Robert C. Martin summarized those principles, but did not invent them.

Page 4: Solid principles

Which are these principles?

Single responsibility principle

Open/Close principle

Liskov substitution principle

Interface segregation principle

Dependency inversion principle

Page 5: Solid principles

Geolocation Tracker

„As a hiker I want to track where I walked and how much I climbed.“

„As a developer I want to be able to store the geo information on different devices.“

„As a developer I want to store the geo information in a unified format.“

Page 6: Solid principles

Single responsibilityprinciple (SRP)

„A class should have one, and only one, reason to change.“

Page 7: Solid principles

How to doit wrong

Page 8: Solid principles

<?phpnamespace lapis\Tracker;use lapis\Tracker\Structs;

class Geolocation extends Tracker{ public function trackPosition(Position $position) { list($langitude, $longitude, $altitude) = $this->extractCoordinatesFromPosition($position); $altitude = $this->convertFeetToMeter($altitude); $this->persistPosition($langitude, $longitude, $altitude, new DateTime()); }

public function persistPosition( $langitude, $longitude, $altitude, \DateTime $time) { try{ $conn = $this->getDatabaseConnection('write'); $conn->execute($this->generateQuery($langitude, $longitude, $altitude, $time)); } catch (Exception $e) { $this->logError($e->getMessage()); } } /** […] */}

Page 9: Solid principles

How to doit right

Page 10: Solid principles

<?php

namespace lapis\Tracker;use lapis\Tracker\Structs\Position;

class Geolocation extends Tracker{ public function __construct(Parser $parser, PersistenceManager $pm) { /** […] */ }

public function trackPosition(Position $position, \DateTime $time = null) { try { $coordinates = $this->parser->parsePosition($position); $this->pm->persistPosition($coordinates, $time); } catch (PersistanceManagerException $e) { throw new TrackerException( 'Unable to persist your position.', TrackerException::PersistError, $e ); } }}

Page 11: Solid principles

Single responsibilityprinciple

Simple to understand, very hard to get right.

Separation of responsibilities / concerns

One responsibility per class

Page 12: Solid principles

Liskov substitutionprinciple (LSP)

„Derived classes must be substitutable for their base

classes.“

Page 13: Solid principles

Where dowe start

Page 14: Solid principles

<?phpnamespace lapis\Converter;

class Distance { const FACTOR = 0.3048; // 1 foot in meters

public function feetToMeters($distance) { $this->verifyDistance($distance); return $distance * self::FACTOR; }

public function metersToFeet($distance) { $this->verifyDistance($distance); return $distance / self::FACTOR; }

protected function verifyDistance($distance) { if ($distance < 0) { throw new \OutOfRangeException( 'Distance may not be lower than zero.', DistanceException::OutOfRange ); } }}

Page 15: Solid principles

How to doit wrong

Page 16: Solid principles

<?php

namespace lapis\Converter\Distance;use lapis\Converter;

class NegativeDistance extends Distance{ protected function verifyDistance($distance) { return TRUE; }}

Page 17: Solid principles

How to doit right

Page 18: Solid principles

<?phpnamespace lapis\Converter\Distance;use lapis\Converter;

class MaxDistance extends Distance { public function feetToMeters($distance) { $distance = parent::feetToMeters($distance); $this->verifyDistance($distance, 15000); return $distance; }

protected function verifyDistance($distance, $max = 0) { if ($distance < 0) { $message = 'Distance may not be lower than the zero.'; } if ($max > 0 && $distance >= $max) { $message = 'Distance may not be greater than the maximum of ' . $max . '.'; } If (isset($message) { throw new \OutOfRangeException($message, DistanceException::OutOfRange); } }}

Page 19: Solid principles

Liskov substitutionprinciple

Design by contract

User must not distinguish between super- & subclasses

Derived class must be more strict on output, but may handle the input less strict.

Increases maintainability, robustness & resusability

Page 20: Solid principles

Dependency inversionprinciple (DIP)

„Depend on abstractions, not on concretions.“

Page 21: Solid principles

How to doit wrong

Page 22: Solid principles

<?phpnamespace lapis\Tracker;use lapis\Tracker\Structs\Position;

class PersistenceManager { public function __construct(Tracker $tracker) { /** […] */ }

public function trackPosition(Position $position) { try { $this->tracker->trackPosition($position); $this->log('Position stored successfully'); } catch (TrackerException $e) { $this->log($e->getMessage()); } }

protected function log($message) { $fh = fopen ('log.txt' , 'a'); fwrite($fh, $message); fclose($fh); } /** […] */}

Page 23: Solid principles

How to doit right

Page 24: Solid principles

<?php

namespace lapis\Tracker;use lapis\Logger, lapis\Tracker\Services;

class PersistenceManager{ public function __construct(PersistService $ps, Logger $logger) { /** […] */ }

public function persistPosition($coordinates, \DateTime $time = null) { try { $this->ps->setCoordinates($coordinates); $this->ps->setTimeStamp($time); $this->ps->persist(); $this->logger->log('Position stored successfully');

} catch (PersistServiceException $e) { $this->logger->exception($e); } }}

Page 25: Solid principles

Dependency inversionprinciple

Fundamental principle for OOD

Encapsulate low level modules in abstractions

Depend on abstractions / interfaces rather than implementations

Page 26: Solid principles

Interface segregationprinciple (ISP)

„Make fine grained interfaces that are client specific.“

Page 27: Solid principles

Where dowe start

Page 28: Solid principles

<?php

namespace lapis\Tracker;use lapis\Logger, lapis\Tracker\Services;

class PersistenceManager{ public function __construct(PersistService $ps, Logger $logger) { /** […] */ }

public function persistPosition($coordinates, \DateTime $time = null) { try { $this->ps->setCoordinates($coordinates); $this->ps->setTimeStamp($time); $this->ps->persist(); $this->logger->log('Position stored successfully');

} catch (PersistServiceException $e) { $this->logger->exception($e); } }}

Page 29: Solid principles

How to doit right

Page 30: Solid principles

<?php

namespace lapis\Tracker;use lapis\Logger, lapis\Tracker\Services;

class PersistenceManager implements PersistenceManagerPosition{ public function __construct(PersistService $ps, Logger $logger) { /** […] */ }

public function persistPosition($coordinates, \DateTime $time = null) { /** […] */ }

public function persistHeight($height, \DateTime $time = null) { /** […] */ }

public function persistLocation($height, \DateTime $time = null) { /** […] */ }}

interface PersistenceManagerPosition{ public function persistPosition($coordinates, \DateTime $time = null);}

Page 31: Solid principles

<?php

namespace lapis\Tracker;use lapis\Tracker\Structs\Position;

class Geolocation extends Tracker{ public function __construct(Parser $parser, PersistenceManagerPosition $pm) { /** […] */ }

public function trackPosition(Position $position, \DateTime $time = null) { try{ $coordinates = $this->parser->parsePosition($position); $this->pm->persistPosition($coordinates, $time); } catch (PersistanceManagerException $e) { throw new TrackerException( 'Unable to persist your position.', TrackerException::PersistError, $e ); } }}

Page 32: Solid principles

Interface segregationprinciple

Avoid „fat“ interfaces, stick to what's really needed

Ask yourself „What do I want to archieve?“

Be strict!

Page 33: Solid principles

Open/Close principle (OCP)

„You should be able to extend a classes behavior, without modifying

it.“

Page 34: Solid principles

Open/Close principle (OCP)

„It is the heard of object oriented design“

Combines the other 4 principles

Page 35: Solid principles

Where we started

Page 36: Solid principles

Where we got

Page 37: Solid principles

Questions@lapistano

[email protected]

Page 38: Solid principles

PHP5.3 Powerworkshop

New features of PHP5.3

Best Pratices using OOP

PHPUnit

PHPDocumentor

Page 39: Solid principles

License

This set of slides and the source code included in the download package is licensed under the

Creative Commons Attribution-Noncommercial-Share Alike 2.0 Generic License

http://creativecommons.org/licenses/by-nc-sa/2.0/deed.en