104
Be pragmatic, be SOLID

4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

  • Upload
    proidea

  • View
    56

  • Download
    0

Embed Size (px)

Citation preview

Page 1: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Be pragmatic,be SOLID

Page 2: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Krzysztof Menżyk

practises TDDbelieves that software is a craft

loves domain modellingobsessed with brewing

plays squash

kmenzyk [email protected]

Page 3: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Do you consider yourselfa professional software developer?

Page 4: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

New client

Greenfield project

Starting from scratch

Page 5: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk
Page 6: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk
Page 7: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

What went wrong?

Page 8: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

The code started to rot

Page 9: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

The design is hard to change

Rigidity

Page 10: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

The design is easy to break

Fragility

Page 11: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Immobility

The design is hard to reuse

Page 12: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

It is easy to do the wrong thing, but hard to do the right thing

Viscosity

Page 13: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Your software is bound to change

Page 14: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Design stamina hypothesis

time

cumulativefunctionality

design payoff lineno design

good design

by Martin Fowler

Page 15: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk
Page 16: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

What is Object Oriented Design

then?

Page 17: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Design Principles andDesign Patterns

Robert C. Martin

Page 18: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Single Responsibility

Open Closed

Liskov Substitution

Interface Segregation

Dependency Inversion

Page 19: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

SingleResponsibilityPrinciple

A class should have only one reason to change

Page 20: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Gather together those things that change for the same reason

Separate those things that change for different reasons

Page 21: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class Employee{ public static function hire($name, $forPosition, Money $withSalary) { // ... }

public function promote($toNewPosition, Money $withNewSalary) { // ... }

public function asJson() { // ... }

public function save() { // ... }

public function delete() { // ... }}

Page 22: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Try to describe what the class does

Page 23: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class Employee{ public static function hire($name, $forPosition, Money $withSalary) { // ... }

public function promote($toNewPosition, Money $withNewSalary) { // ... }

public function asJson() { // ... }

public function save() { // ... }

public function delete() { // ... }}

Page 24: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class Employee{ public static function hire($name, $forPosition, Money $withSalary) { // ... }

public function promote($toNewPosition, Money $withNewSalary) { // ... }

public function asJson() { // ... }

public function save() { // ... }

public function delete() { // ... }}

Page 25: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class Employee{ public static function hire($name, $forPosition, Money $withSalary) { // ... }

public function promote($toNewPosition, Money $withNewSalary) { // ... }

public function asJson() { // ... }

public function save() { // ... }

public function delete() { // ... }}

Page 26: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk
Page 27: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class Employee{ public static function hire($name, $forPosition, Money $withSalary) { // ... }

public function promote($toNewPosition, Money $withNewSalary) { // ... }

public function asJson() { // ... }

public function save() { // ... }

public function delete() { // ... }} violation

Page 28: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class Employee { public static function hire($name, $forPosition, Money $withSalary) { // ... }

public function promote($toNewPosition, Money $withNewSalary) { // ... }}

class EmployeeSerializer{ public function toJson(Employee $employee) { // ... }}

class EmployeeRepository { public function save(Employee $employee) { // ... }

public function delete(Employee $employee) { // ... }}

the right

way

Page 29: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

What about applying SRP to class methods?

Page 30: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

What about applying SRP to test methods?

Page 31: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

/** @test */public function test_employee(){ $employee = Employee::hire('John Doe', 'Junior Developer', $this->fiveHundredEuros);

$this->assertEquals($this->fiveHundredEuros, $employee->getSalary());

$employee->promote('Senior Developer', $this->sixHundredEuros);

$this->assertEquals($this->sixHundredEuros, $employee->getSalary());

$employee->promote('Technical Leader', $this->fiveHundredEuros);

$this->assertEquals($this->sixHundredEuros, $employee->getSalary());}

Page 32: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

/** @test */public function it_hires_with_salary(){ $employee = Employee::hire('John Doe', 'Junior Developer', $this->fiveHundredEuros);

$this->assertEquals($this->fiveHundredEuros, $employee->getSalary());}

/** @test */public function it_promotes_with_new_salary(){ $employee = Employee::hire('John Doe', 'Junior Developer', $this->fiveHundredEuros); $employee->promote('Senior Developer', $this->sixHundredEuros);

$this->assertEquals($this->sixHundredEuros, $employee->getSalary());}

/** @test */public function it_does_not_promote_if_new_salary_is_not_bumped(){ $employee = Employee::hire('John Doe', 'Senior Developer', $this->sixHundredEuros); $employee->promote('Technical Leader', $this->fiveHundredEuros);

$this->assertEquals($this->sixHundredEuros, $employee->getSalary());}

the right

way

Page 33: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

One test covers one behaviour

Page 34: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

OpenClosedPrinciple

Software entities should be open for extension, but closed for modification

Page 35: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Write once, change never!

Page 36: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Wait! What?

Page 37: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class Shortener{ public function shorten(Url $longUrl) { if (!$this->hasHttpScheme($longUrl)) { throw new InvalidUrl('Url has no "http" scheme'); }

// do stuff to shorten valid url

return $shortenedUrl; }

private function hasHttpScheme(Url $longUrl) { // ... }}

/** @test */public function it_does_not_shorten_url_without_http(){ $urlToFtp = // ...

$this->setExpectedException(InvalidUrl::class, 'Url has no "http" scheme');

$this->shortener->shorten($urlToFtp);}

Page 38: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class Shortener{ public function shorten(Url $longUrl) { if (!$this->hasHttpScheme($longUrl)) { throw new InvalidUrl('Url has no "http" scheme'); }

if (!$this->hasPlDomain($longUrl)) { throw new InvalidUrl('Url has no .pl domain'); }

// do stuff to shorten valid url

return $shortenedUrl; }

private function hasHttpScheme(Url $longUrl) { // ... }

private function hasPlDomain(Url $longUrl) { // ... }}

Page 39: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

/** @test */public function it_shortens_only_urls_with_pl_domains(){ $urlWithEuDomain = // ...

$this->setExpectedException(InvalidUrl::class, 'Url has no .pl domain');

$this->shortener->shorten($urlWithEuDomain);}

Page 40: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

/** @test */public function it_shortens_only_urls_with_pl_domains(){ $urlWithEuDomainButWithHttpScheme = // ...

$this->setExpectedException(InvalidUrl::class, 'Url has no .pl domain');

$this->shortener->shorten($urlWithEuDomainButWithHttpScheme);}

Page 41: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

/** @test */public function it_shortens_urls(){ $validUrl = // make sure the url satisfies all "ifs"

$shortenedUrl = $this->shortener->shorten($validUrl);

// assert}

Page 42: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Testing seems hard?

Page 43: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class Shortener{ public function shorten(Url $longUrl) { if (!$this->hasHttpScheme($longUrl)) { throw new InvalidUrl('Url has no "http" scheme'); }

if (!$this->hasPlDomain($longUrl)) { throw new InvalidUrl('Url has no .pl domain'); }

// do stuff to shorten valid url

return $shortenedUrl; }

private function hasHttpScheme(Url $longUrl) { // ... }

private function hasPlDomain(Url $longUrl) { // ... }} violation

Page 44: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Abstraction is the key

Page 45: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

interface Rule{ /** * @param Url $url * * @return bool */ public function isSatisfiedBy(Url $url);}

Page 46: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class Shortener{ public function addRule(Rule $rule) { // ... }

public function shorten(Url $longUrl) { if (!$this->satisfiesAllRules($longUrl)) { throw new InvalidUrl(); }

// do stuff to shorten valid url

return $shortenedUrl; }

private function satisfiesAllRules(Url $longUrl) { // ... }}

the right

way

Page 47: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class HasHttp implements Rule{ public function isSatisfiedBy(Url $url) { // ... }}

class HasPlDomain implements Rule{ public function isSatisfiedBy(Url $url) { // ... }}

Page 48: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

”There is a deep synergy between testability and good design”

– Michael Feathers

Page 49: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

LiskovSubstitutionPrinciple

Subtypes must be substitutable for their base types

Page 50: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class Tweets{ protected $tweets = [];

public function add(Tweet $tweet) { $this->tweets[$tweet->id()] = $tweet; }

public function get($tweetId) { if (!isset($this->tweets[$tweetId])) { throw new TweetDoesNotExist(); }

return $this->tweets[$tweetId]; }}

Page 51: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class BoundedTweets extends Tweets{ const MAX = 10;

public function add(Tweet $tweet) { if (count($this->tweets) > self::MAX) { throw new \OverflowException(); }

parent::add($tweet); }}

Page 52: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

function letsTweet(Tweets $tweets){ // ... // $tweets has already 10 tweets

$tweets->add(new Tweet('Ooooops'));}

Page 53: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

function letsTweet(Tweets $tweets){ // ...

try { $tweets->add(new Tweet('Ooooops')); } catch (\OverflowException $e) { // What to do? }}

violation

Page 54: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Design by contract

Page 55: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Design by contract(because public API is not enough)

Page 56: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

What does it expect?

What does it guarantee?

What does it maintain?

Page 57: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class Tweets{ public function add(Tweet $tweet) { // ... }

/** * @param $tweetId * * @return Tweet * * @throws TweetDoesNotExist If a tweet with the given id * has not been added yet */ public function get($tweetId) { // ... }}

Page 58: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

interface Tweets{ public function add(Tweet $tweet);

/** * @param $tweetId * * @return Tweet * * @throws TweetDoesNotExist If a tweet with the given id * has not been added yet */ public function get($tweetId);}

class InMemoryTweets implements Tweets{ // ...}

Page 59: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

public function retweet($tweetId){ try { $tweet = $this->tweets->get($tweetId); } catch (TweetDoesNotExist $e) { return; }

// ...}

Page 60: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class DoctrineORMTweets extends EntityRepository implements Tweets{ public function add(Tweet $tweet) { $this->_em->persist($tweet); $this->_em->flush(); }

public function get($tweetId) { return $this->find($tweetId); }}

Page 61: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class EntityRepository implements ObjectRepository, Selectable{ /** * Finds an entity by its primary key / identifier. * * @param mixed $id The identifier. * @param int $lockMode The lock mode. * @param int|null $lockVersion The lock version. * * @return object|null The entity instance * or NULL if the entity can not be found. */ public function find($id, $lockMode = LockMode::NONE, $lockVersion = null) { // ... }

// ...}

Page 62: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

function retweet($tweetId){ if ($this->tweets instanceof DoctrineORMTweets) { $tweet = $this->tweets->get($tweetId);

if (null === $tweet) { return; } } else { try { $tweet = $this->tweets->get($tweetId); } catch (TweetDoesNotExist $e) { return; } }

// ...} violation

Page 63: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Violations of LSP arelatent violations of OCP

Page 64: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class DoctrineORMTweets extends EntityRepository implements Tweets{ // ...

public function get($tweetId) { $tweet = $this->find($tweetId);

if (null === $tweet) { throw new TweetDoesNotExist(); }

return $tweet; }}

the right

way

Page 65: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

LSP violations are difficult to detect until it is too late

Page 66: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Ensure the expected behaviour of your base class is preserved in

derived classes

Page 67: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

DependencyInversionPrinciple

High-level modules should not depend on low-level modules, both should depend on abstractions

Abstractions should not depend on details. Details should depend on abstractions

Page 68: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class PayForOrder { public function __construct(PayPalApi $payPalApi) { $this->payPalApi = $payPalApi; }

public function function pay(Order $order) { // ...

$token = $this->payPalApi->createMethodToken($order->creditCard()); $this->payPalApi->createTransaction($token, $order->amount());

// ... }}

Page 69: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

PayForOrder

PayPalApi

Business Layer

Integration Layer

Page 70: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

High-level module

Low-level module

PayForOrder

PayPalApi

Page 71: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Abstraction is the key

Page 72: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

PaymentProvider

PayPalApi

PayForOrder

Page 73: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class PayForOrder{ public function __construct(PaymentProvider $paymentProvider) { $this->paymentProvider = $paymentProvider; }

public function function pay(Order $order) { // ...

$token = $this->paymentProvider->createMethodToken($order->creditCard()); $this->paymentProvider->createTransaction($token, $order->amount());

// ... }}

Page 74: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class PayForOrder{ public function __construct(PaymentProvider $paymentProvider) { $this->paymentProvider = $paymentProvider; }

public function function pay(Order $order) { // ...

$token = $this->paymentProvider->createMethodToken($order->creditCard()); $this->paymentProvider->createTransaction($token, $order->amount());

// ... }}

Abstractions should not depend on details. Details should depend on abstractions

Page 75: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Define the interface from the usage point of view

Page 76: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class PayForOrder{ public function __construct(PaymentProvider $paymentProvider) { $this->paymentProvider = $paymentProvider; }

public function function pay(Order $order) { // ...

$token = $this->paymentProvider->charge( $order->creditCard(), $order->amount() );

// ... }} the right

way

Page 77: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Concrete things change alot

Abstract things change muchless frequently

Page 78: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

PaymentProvider

PayPalProvider

PayForOrder

PayPalApi

3rd party

Page 79: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class PayPalProvider extends PayPalApi implements PaymentProvider{ public function charge(CreditCard $creditCard, Money $forAmount) { $token = $this->createMethodToken($creditCard); $this->createTransaction($token, $forAmount); }}

Page 80: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

PaymentProvider

PayPalProvider

PayForOrder

PayPalApi

3rd party

Page 81: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class PayPalProvider implements PaymentProvider{ public function __construct(PayPalApi $payPal) { $this->payPal = $payPal; }

public function charge(CreditCard $creditCard, Money $forAmount) { $token = $this->payPal->createMethodToken($creditCard); $this->payPal->createTransaction($token, $forAmount); }}

Page 82: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class TestPaymentProvider implements PaymentProvider { //... }

Page 83: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

InterfaceSegregationPrinciple

Clients should not be forced to depend on methods they do not use

Page 84: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Many client specific interfaces are better than one general purpose

interface

Page 85: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

interface EventDispatcherInterface{ public function dispatch($eventName, Event $event = null);

public function addListener($eventName, $listener, $priority = 0);

public function removeListener($eventName, $listener);

public function addSubscriber(EventSubscriberInterface $subscriber);

public function removeSubscriber(EventSubscriberInterface $subscriber);

public function getListeners($eventName = null);

public function hasListeners($eventName = null);}

Page 86: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class HttpKernel implements HttpKernelInterface, TerminableInterface{ public function terminate(Request $request, Response $response) { $this->dispatcher->dispatch( KernelEvents::TERMINATE, new PostResponseEvent($this, $request, $response) ); }

private function handleRaw(Request $request, $type = self::MASTER_REQUEST) { // ... $this->dispatcher->dispatch(KernelEvents::REQUEST, $event);

// ...

$this->dispatcher->dispatch(KernelEvents::CONTROLLER, $event);

// ... }

private function filterResponse(Response $response, Request $request, $type) { // ... $this->dispatcher->dispatch(KernelEvents::RESPONSE, $event); // ... }

// ...}

Page 87: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class ImmutableEventDispatcher implements EventDispatcherInterface{ public function dispatch($eventName, Event $event = null) { return $this->dispatcher->dispatch($eventName, $event); }

public function addListener($eventName, $listener, $priority = 0) { throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); }

public function removeListener($eventName, $listener) { throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); }

public function addSubscriber(EventSubscriberInterface $subscriber) { throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); }

public function removeSubscriber(EventSubscriberInterface $subscriber) { throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); }

// ...}

violation

Page 88: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

It serves too many different types of clients

Page 89: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Design interfaces from clients point of view

Page 90: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

interface EventDispatcherInterface{ public function dispatch($eventName, Event $event = null);}

interface EventListenersInterface{ public function addListener($eventName, $listener, $priority = 0); public function removeListener($eventName, $listener);}

interface EventSubscribersInterface{ public function addSubscriber(EventSubscriberInterface $subscriber); public function removeSubscriber(EventSubscriberInterface $subscriber);}

interface DebugEventListenersInterface{ public function getListeners($eventName = null); public function hasListeners($eventName = null);} the right

way

Page 91: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

class EventDispatcher implements EventDispatcherInterface, EventListenersInterface, EventSubscribersInterface{ // ...}

class DebugEventDispatcher extends EventDispatcher implements DebugEventListenersInterface{ // ...}

Page 92: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Design is all about dependencies

Page 93: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Think about the design!

Page 94: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Listen to your tests

Page 95: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

”Always leave the code a little better than you found it.”

Page 96: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

But...

Page 97: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Be pragmatic

Page 98: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

"By not considering the future of your code, you make your code

much more likely to be adaptable in the future."

Page 99: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

At the end of the day what matters most is a business value

Page 100: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Know the rules well, so you can break them effectively

Page 101: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk
Page 102: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Be pragmatic,be SOLID

kmenzyk [email protected]

Thanks!

Page 103: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Worth reading

http://www.objectmentor.com/resources/articles/Principles_and_Patterns.pdf

http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod

https://gilesey.wordpress.com/2013/09/01/single-responsibility-principle/

”Clean Code: A Handbook of Agile Software Craftsmanship” by Robert C. Martin

http://martinfowler.com/bliki/DesignStaminaHypothesis.html

Page 104: 4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk

Photo Creditshttps://flic.kr/p/5bTy6C

http://www.bonkersworld.net/building-software/

https://flic.kr/p/jzCox

https://flic.kr/p/n37EXH

https://flic.kr/p/9mcfh9

https://flic.kr/p/7XmGXp

http://my.csdn.net/uploads/201205/13/1336911356_6234.jpg

http://bit.ly/1cMgkPA

https://flic.kr/p/qQTMa

http://bit.ly/1EhyGEc

https://flic.kr/p/5PyErP

http://fc08.deviantart.net/fs49/i/2009/173/c/7/The_Best_Life_Style_by_Alteran_X.jpg

https://flic.kr/p/4Sw9pP

https://flic.kr/p/8RjbTS