WHAT DO THEY MEAN?
WHAT DO THEY MEAN?
Let's find out together!
¯\_(
ツ)_/¯
Slide 7
Slide 7 text
SINGLE RESPONSIBILITY
SINGLE RESPONSIBILITY
PRINCIPLE
PRINCIPLE
Slide 8
Slide 8 text
A class should have
only 1 responsibility
Slide 9
Slide 9 text
No content
Slide 10
Slide 10 text
A class should have
only 1 responsibility reason to change
Slide 11
Slide 11 text
No content
Slide 12
Slide 12 text
class PostalCodeHelper
{
/* ... */
public function getCity(string $zip) : string {
return $this->map[$zip] ?? 'Black Hole';
}
public function format(string $zip) : string {
$city = $this->mapCodeToCity($zip);
return sprintf(
'%1$s %2$s',
$zip,
$city
Slide 13
Slide 13 text
REASONS FOR CHANGING:
REASONS FOR CHANGING:
Mapping changes
Formatting changes
Importing changes
...
Slide 14
Slide 14 text
WHO WANTS TO MAINTAIN THIS?
WHO WANTS TO MAINTAIN THIS?
Slide 15
Slide 15 text
HOW TO FIX?
HOW TO FIX?
Extract Postal Code Mapper
Extract Postal Code Repository
Extract Postal Code Formatter
Extract Postal Code Importer
...
Slide 16
Slide 16 text
BUT ISN'T THIS MORE WORK?
BUT ISN'T THIS MORE WORK?
absolutely!
Slide 17
Slide 17 text
SO WHAT IS THE BENEFIT?
SO WHAT IS THE BENEFIT?
Clear & concise classes,
which are easier to grasp and therefore
easier to maintain.
Slide 18
Slide 18 text
HEURISTICS & CONVENTIONS
HEURISTICS & CONVENTIONS
Think before coding
Keep classes small
Extract whenever you detect a new responsibility
Don't be lazy
Slide 19
Slide 19 text
ANY QUESTIONS?
ANY QUESTIONS?
Slide 20
Slide 20 text
OPEN/CLOSED PRINCIPLE
OPEN/CLOSED PRINCIPLE
Slide 21
Slide 21 text
A CLASS/MODULE/PACKAGE SHOULD BE
A CLASS/MODULE/PACKAGE SHOULD BE
Open for extension
Closed for modification
POLYMORPHIC OPEN/CLOSED PRINCIPLE
POLYMORPHIC OPEN/CLOSED PRINCIPLE
Relies on abstractions
Abstracts are closed for modification
Implementation can change
Slide 25
Slide 25 text
class Circle
{
/* ... */
}
class Rectangle
{
/* ... */
}
Slide 26
Slide 26 text
$shapes = [
new Circle,
new Circle,
new Rectangle,
new Circle,
];
Slide 27
Slide 27 text
class ShapeDrawer
{
public function draw(array $shapes) : void
{
foreach ($shapes as $shape) {
if ($shape instanceof Circle) {
// ...
}
if ($shape instanceof Rectangle) {
// ...
}
}
}
}
Slide 28
Slide 28 text
VIOLATES OPEN/CLOSED PRINCIPLE
VIOLATES OPEN/CLOSED PRINCIPLE
New shape? => Modify ShapeDrawer
=> ShapeDrawer is not closed
Slide 29
Slide 29 text
HOW TO FIX?
HOW TO FIX?
Define an abstraction
Depend on abstraction (see later on)
Implement different behaviors (polymorphism)
Slide 30
Slide 30 text
interface Shape {
public function draw(): void;
}
class Circle implements Shape
{
/* ... */
}
class Rectangle implements Shape
{
/* ... */
}
Slide 31
Slide 31 text
class ShapeDrawer
{
public function draw(array $shapes) : void
{
foreach ($shapes as $shape) {
if (! $shape instanceof Shape) {
continue;
}
$shape->draw();
}
}
}
Slide 32
Slide 32 text
HEURISTICS & CONVENTIONS
HEURISTICS & CONVENTIONS
Work towards closed classes
Make functionality private
Mark classes & methods as final
No RTTI
Specify abstractions
BARBARA LISKOV
BARBARA LISKOV
American Computer Scientist
MIT
Turing Award winner
Fields:
Operating systems
Programming languages
Distributed systems
Abstractions & modularity
Slide 38
Slide 38 text
LSP
LSP
When B is a subtype of A,
Then objects of type A may be replaced
By objects of type B,
Without altering the desirable properties
Of the program
Slide 39
Slide 39 text
LSP
LSP
When B is a child of parent A,
Then objects of parent A may be replaced
By objects of child B,
Without altering the desirable properties
Of the program
Slide 40
Slide 40 text
CLASSIC
CLASSIC WRONG
WRONG EXAMPLE
EXAMPLE
Slide 41
Slide 41 text
class Rectangle {
// ...
public function setWidth(int $width) : void {
$this->width = $width;
}
// ...
}
Slide 42
Slide 42 text
No content
Slide 43
Slide 43 text
class Square extends Rectangle {
// ...
public function setWidth(int $width) : void {
$this->width = $width;
$this->height = $height;
}
// ...
}
Slide 44
Slide 44 text
WHO CAN EXPLAIN THE
WHO CAN EXPLAIN THE UNDESIRABLE
UNDESIRABLE
CHANGE?
CHANGE?
UNSURE ABOUT THE CORRECTNESS
UNSURE ABOUT THE CORRECTNESS
Slide 47
Slide 47 text
INFLUENCE OF LSP
INFLUENCE OF LSP
Standard requirements on method signature in OOP
languages
Slide 48
Slide 48 text
INFLUENCE OF LSP
INFLUENCE OF LSP
Contravariance of method arguments in subtype
Covariance of return types in subtype
Slide 49
Slide 49 text
No content
Slide 50
Slide 50 text
CAN ANYONE EXPLAIN VARIANCE?
CAN ANYONE EXPLAIN VARIANCE?
Slide 51
Slide 51 text
No content
Slide 52
Slide 52 text
Contravariance = Parameter type widening (less
specific)
Covariance = Return type narrowing (more specific)
Slide 53
Slide 53 text
SOME EXAMPLES IN PHP
SOME EXAMPLES IN PHP
Slide 54
Slide 54 text
QUIZ! - WILL THIS WORK? (1/4)
QUIZ! - WILL THIS WORK? (1/4)
class Foo
{
public function bar() {}
}
class Woo extends Foo
{
public function bar() : int {}
}
Slide 55
Slide 55 text
QUIZ! - WILL THIS WORK? (2/4)
QUIZ! - WILL THIS WORK? (2/4)
class Foo
{
public function bar() : Rectangle {}
}
class Woo extends Foo
{
public function bar() : Square {}
}
Slide 56
Slide 56 text
PHP IS "1-LEVEL" COVARIANT
PHP IS "1-LEVEL" COVARIANT
Only works from "mixed" to "something else"
Not from Supertype to Subtype
Slide 57
Slide 57 text
QUIZ! - WILL THIS WORK? (3/4)
QUIZ! - WILL THIS WORK? (3/4)
class Foo
{
public function bar(string $baz) : int {}
}
class Woo extends Foo
{
public function bar($baz) : int {}
}
Slide 58
Slide 58 text
QUIZ! - WILL THIS WORK? (4/4)
QUIZ! - WILL THIS WORK? (4/4)
class Foo
{
public function bar(Square $baz) : int {}
}
class Woo extends Foo
{
public function bar(Rectangle $baz) : int {}
}
Slide 59
Slide 59 text
PHP IS "1-LEVEL" CONTRAVARIANT
PHP IS "1-LEVEL" CONTRAVARIANT
Only works from "something" to "mixed" (omitting)
Not from Subtype to Supertype (scope widening)
(only in PHP >= 7.2)
Slide 60
Slide 60 text
CONCLUSION: PHP IS INVARIANT
CONCLUSION: PHP IS INVARIANT
Slide 61
Slide 61 text
HEURISTICS & CONVENTIONS
HEURISTICS & CONVENTIONS
LSP is about behavior. Think carefully when
replaceing with a subtype
PHP is Invariant
Typehints can be omitted in subtypes
Mixed return types can be specified in subtypes
No object should be forced to depend
on methods it doesn't use
Slide 67
Slide 67 text
Split large interfaces
into smaller, more specific role interfaces
Slide 68
Slide 68 text
Voorbeeldje
Slide 69
Slide 69 text
HEURISTICS & CONVENTIONS
HEURISTICS & CONVENTIONS
When you need to implement more than you'd like,
split the interface
Implementation
class Foo implements A, B, C
interface Bar extends A, C
Slide 70
Slide 70 text
INTERESTING READ
INTERESTING READ
Matthias Noback: When to add an interface to a class
Abstractions should not depend on details. Details
should depend on abstractions.
High-level modules should not depend on low-level
modules. Both should depend on abstractions.
Slide 74
Slide 74 text
final class InMemoryRegistry
{
}
Slide 75
Slide 75 text
interface ContextBuilder
{
public function setLocator(InMemoryRegistry $locator) : vo
}
Slide 76
Slide 76 text
ABSTRACTIONS SHOULD NOT DEPEND
ABSTRACTIONS SHOULD NOT DEPEND
ON DETAILS
ON DETAILS
Slide 77
Slide 77 text
interface ContextBuilderLocator
{
public function retrieve(string $key) : ContextBuilder;
}
final class InMemoryRegistry implements ContextBuilderLocator
{
}
Slide 78
Slide 78 text
interface ContextBuilder
{
public function setLocator(ContextBuilderLocator $locator)
}
Slide 79
Slide 79 text
HIGH-LEVEL MODULES SHOULD NOT
HIGH-LEVEL MODULES SHOULD NOT
DEPEND ON LOW-LEVEL MODULES
DEPEND ON LOW-LEVEL MODULES
Slide 80
Slide 80 text
High Level: domain logic; further away from
infrastructure
Low Level: framework logic; closer to infrastructure
CREATE ABSTRACTIONS ACCORDING THE
CREATE ABSTRACTIONS ACCORDING THE
OPEN/CLOSED PRINCIPLE
OPEN/CLOSED PRINCIPLE
interface ContactRepository
Slide 84
Slide 84 text
DEPEND ON THESE ABSTRACTIONS
DEPEND ON THESE ABSTRACTIONS
public function
__construct(ContactRepository $repo)
Slide 85
Slide 85 text
MAKE LOW LEVEL SPECIFIC IMPLEMENTATIONS &
MAKE LOW LEVEL SPECIFIC IMPLEMENTATIONS &
NAME ACCORDINGLY
NAME ACCORDINGLY
DbalContactRepository or
InMemoryContactRepository
Slide 86
Slide 86 text
IT CAN HELP TO "PHYSICALLY" SPLIT FILES BETWEEN
IT CAN HELP TO "PHYSICALLY" SPLIT FILES BETWEEN
HIGH & LOW LEVEL
HIGH & LOW LEVEL
Slide 87
Slide 87 text
ANY QUESTIONS?
ANY QUESTIONS?
Slide 88
Slide 88 text
WRAPPIN' IT UP
WRAPPIN' IT UP
Single Responsibility Principle
Open/Closed Principle
Liskov Substitution Principle
Interface Segregation Principle
Dependency Inversion Principle