SlideShare uma empresa Scribd logo
1 de 104
Baixar para ler offline
Be pragmatic,
be SOLID
Krzysztof Menżyk
practises TDD
believes that software is a craft
loves domain modelling
obsessed with brewing
plays squash
 kmenzyk
 krzysztof@menzyk.net
Do you consider yourself
a professional software developer?
New client
Greenfield project
Starting from scratch
What went wrong?
The code started to rot
The design is hard to change
Rigidity
The design is easy to break
Fragility
Immobility
The design is hard to reuse
It is easy to do the wrong thing,
but hard to do the right thing
Viscosity
Your software is bound to change
Design stamina hypothesis
time
cumulative
functionality
design payoff line
no design
good design
by Martin Fowler
What is
Object Oriented Design
then?
Design Principles and
Design Patterns
Robert C. Martin
Single Responsibility
Open Closed
Liskov Substitution
Interface Segregation
Dependency Inversion
Single
Responsibility
Principle
A class should have
only one reason to change
Gather together those things that
change for the same reason
Separate those things that change
for different reasons
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()
{
// ...
}
}
Try to describe what the class does
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()
{
// ...
}
}
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()
{
// ...
}
}
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()
{
// ...
}
}
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
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
What about applying SRP
to class methods?
What about applying SRP
to test methods?
/** @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());
}
/** @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
One test covers one behaviour
Open
Closed
Principle
Software entities should be open for
extension, but closed for modification
Write once, change never!
Wait! What?
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);
}
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)
{
// ...
}
}
/** @test */
public function it_shortens_only_urls_with_pl_domains()
{
$urlWithEuDomain = // ...
$this->setExpectedException(InvalidUrl::class, 'Url has no .pl domain');
$this->shortener->shorten($urlWithEuDomain);
}
/** @test */
public function it_shortens_only_urls_with_pl_domains()
{
$urlWithEuDomainButWithHttpScheme = // ...
$this->setExpectedException(InvalidUrl::class, 'Url has no .pl domain');
$this->shortener->shorten($urlWithEuDomainButWithHttpScheme);
}
/** @test */
public function it_shortens_urls()
{
$validUrl = // make sure the url satisfies all "ifs"
$shortenedUrl = $this->shortener->shorten($validUrl);
// assert
}
Testing seems hard?
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
Abstraction is the key
interface Rule
{
/**
* @param Url $url
*
* @return bool
*/
public function isSatisfiedBy(Url $url);
}
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
class HasHttp implements Rule
{
public function isSatisfiedBy(Url $url)
{
// ...
}
}
class HasPlDomain implements Rule
{
public function isSatisfiedBy(Url $url)
{
// ...
}
}
”There is a deep synergy between
testability and good design”
– Michael Feathers
Liskov
Substitution
Principle
Subtypes must be substitutable
for their base types
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];
}
}
class BoundedTweets extends Tweets
{
const MAX = 10;
public function add(Tweet $tweet)
{
if (count($this->tweets) > self::MAX) {
throw new OverflowException();
}
parent::add($tweet);
}
}
function letsTweet(Tweets $tweets)
{
// ...
// $tweets has already 10 tweets
$tweets->add(new Tweet('Ooooops'));
}
function letsTweet(Tweets $tweets)
{
// ...
try {
$tweets->add(new Tweet('Ooooops'));
} catch (OverflowException $e) {
// What to do?
}
}
violation
Design by contract
Design by contract
(because public API is not enough)
What does it expect?
What does it guarantee?
What does it maintain?
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)
{
// ...
}
}
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
{
// ...
}
public function retweet($tweetId)
{
try {
$tweet = $this->tweets->get($tweetId);
} catch (TweetDoesNotExist $e) {
return;
}
// ...
}
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);
}
}
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)
{
// ...
}
// ...
}
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
Violations of LSP are
latent violations of OCP
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
LSP violations are difficult
to detect until it is too late
Ensure the expected behaviour of
your base class is preserved in
derived classes
Dependency
Inversion
Principle
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
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());
// ...
}
}
PayForOrder
PayPalApi
Business Layer
Integration Layer
High-level module
Low-level module
PayForOrder
PayPalApi
Abstraction is the key
PaymentProvider
PayPalApi
PayForOrder
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());
// ...
}
}
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
Define the interface
from the usage point of view
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
Concrete things change alot
Abstract things change much
less frequently
PaymentProvider
PayPalProvider
PayForOrder
PayPalApi
3rd party
class PayPalProvider extends PayPalApi implements PaymentProvider
{
public function charge(CreditCard $creditCard, Money $forAmount)
{
$token = $this->createMethodToken($creditCard);
$this->createTransaction($token, $forAmount);
}
}
PaymentProvider
PayPalProvider
PayForOrder
PayPalApi
3rd party
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);
}
}
class TestPaymentProvider implements PaymentProvider
{
//...
}
Interface
Segregation
Principle
Clients should not be forced to depend on
methods they do not use
Many client specific interfaces are
better than one general purpose
interface
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);
}
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);
// ...
}
// ...
}
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
It serves too many different
types of clients
Design interfaces from
clients point of view
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
class EventDispatcher implements EventDispatcherInterface,
EventListenersInterface,
EventSubscribersInterface
{
// ...
}
class DebugEventDispatcher extends EventDispatcher
implements DebugEventListenersInterface
{
// ...
}
Design is all about dependencies
Think about the design!
Listen to your tests
”Always leave the code a little better than
you found it.”
But...
Be pragmatic
"By not considering the future of
your code, you make your code
much more likely to be adaptable
in the future."
At the end of the day what
matters most is a business value
Know the rules well,
so you can break them effectively
Be pragmatic,
be SOLID
 kmenzyk
 krzysztof@menzyk.net
Thanks!
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
Photo Credits
https://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

Mais conteúdo relacionado

Mais procurados

Functional Structures in PHP
Functional Structures in PHPFunctional Structures in PHP
Functional Structures in PHPMarcello Duarte
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mockingKonstantin Kudryashov
 
Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsSam Hennessy
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxMichelangelo van Dam
 
購物車程式架構簡介
購物車程式架構簡介購物車程式架構簡介
購物車程式架構簡介Jace Ju
 
Crafting beautiful software
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful softwareJorn Oomen
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11Michelangelo van Dam
 
PHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにPHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにYuya Takeyama
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Leonardo Proietti
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownpartsBastian Feder
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteLeonardo Proietti
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ EtsyNishan Subedi
 
Hacking Your Way To Better Security - Dutch PHP Conference 2016
Hacking Your Way To Better Security - Dutch PHP Conference 2016Hacking Your Way To Better Security - Dutch PHP Conference 2016
Hacking Your Way To Better Security - Dutch PHP Conference 2016Colin O'Dell
 
Zend Framework and the Doctrine2 MongoDB ODM (ZF1)
Zend Framework and the Doctrine2 MongoDB ODM (ZF1)Zend Framework and the Doctrine2 MongoDB ODM (ZF1)
Zend Framework and the Doctrine2 MongoDB ODM (ZF1)Ryan Mauger
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Fabien Potencier
 
Introduction to DI(C)
Introduction to DI(C)Introduction to DI(C)
Introduction to DI(C)Radek Benkel
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in actionJace Ju
 
Dependency injection - phpday 2010
Dependency injection - phpday 2010Dependency injection - phpday 2010
Dependency injection - phpday 2010Fabien Potencier
 

Mais procurados (20)

Solid principles
Solid principlesSolid principles
Solid principles
 
Functional Structures in PHP
Functional Structures in PHPFunctional Structures in PHP
Functional Structures in PHP
 
Min-Maxing Software Costs
Min-Maxing Software CostsMin-Maxing Software Costs
Min-Maxing Software Costs
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mocking
 
Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy Applications
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
 
購物車程式架構簡介
購物車程式架構簡介購物車程式架構簡介
購物車程式架構簡介
 
Crafting beautiful software
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful software
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
 
PHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにPHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くために
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il cliente
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
 
Hacking Your Way To Better Security - Dutch PHP Conference 2016
Hacking Your Way To Better Security - Dutch PHP Conference 2016Hacking Your Way To Better Security - Dutch PHP Conference 2016
Hacking Your Way To Better Security - Dutch PHP Conference 2016
 
Zend Framework and the Doctrine2 MongoDB ODM (ZF1)
Zend Framework and the Doctrine2 MongoDB ODM (ZF1)Zend Framework and the Doctrine2 MongoDB ODM (ZF1)
Zend Framework and the Doctrine2 MongoDB ODM (ZF1)
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2
 
Introduction to DI(C)
Introduction to DI(C)Introduction to DI(C)
Introduction to DI(C)
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
 
Dependency injection - phpday 2010
Dependency injection - phpday 2010Dependency injection - phpday 2010
Dependency injection - phpday 2010
 

Destaque

Get Soaked - An In Depth Look At PHP Streams
Get Soaked - An In Depth Look At PHP StreamsGet Soaked - An In Depth Look At PHP Streams
Get Soaked - An In Depth Look At PHP StreamsDavey Shafik
 
Techniques d'accélération des pages web
Techniques d'accélération des pages webTechniques d'accélération des pages web
Techniques d'accélération des pages webJean-Pierre Vincent
 
Automation using-phing
Automation using-phingAutomation using-phing
Automation using-phingRajat Pandit
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP GeneratorsMark Baker
 
The quest for global design principles (SymfonyLive Berlin 2015)
The quest for global design principles (SymfonyLive Berlin 2015)The quest for global design principles (SymfonyLive Berlin 2015)
The quest for global design principles (SymfonyLive Berlin 2015)Matthias Noback
 
Top tips my_sql_performance
Top tips my_sql_performanceTop tips my_sql_performance
Top tips my_sql_performanceafup Paris
 
Understanding Craftsmanship SwanseaCon2015
Understanding Craftsmanship SwanseaCon2015Understanding Craftsmanship SwanseaCon2015
Understanding Craftsmanship SwanseaCon2015Marcello Duarte
 
Why elasticsearch rocks!
Why elasticsearch rocks!Why elasticsearch rocks!
Why elasticsearch rocks!tlrx
 
Si le tdd est mort alors pratiquons une autopsie mix-it 2015
Si le tdd est mort alors pratiquons une autopsie mix-it 2015Si le tdd est mort alors pratiquons une autopsie mix-it 2015
Si le tdd est mort alors pratiquons une autopsie mix-it 2015Bruno Boucard
 
Writing infinite scalability web applications with PHP and PostgreSQL
Writing infinite scalability web applications with PHP and PostgreSQLWriting infinite scalability web applications with PHP and PostgreSQL
Writing infinite scalability web applications with PHP and PostgreSQLGabriele Bartolini
 
L'ABC du BDD (Behavior Driven Development)
L'ABC du BDD (Behavior Driven Development)L'ABC du BDD (Behavior Driven Development)
L'ABC du BDD (Behavior Driven Development)Arnauld Loyer
 
Performance serveur et apache
Performance serveur et apachePerformance serveur et apache
Performance serveur et apacheafup Paris
 
TDD with PhpSpec - Lone Star PHP 2016
TDD with PhpSpec - Lone Star PHP 2016TDD with PhpSpec - Lone Star PHP 2016
TDD with PhpSpec - Lone Star PHP 2016CiaranMcNulty
 
The Wonderful World of Symfony Components
The Wonderful World of Symfony ComponentsThe Wonderful World of Symfony Components
The Wonderful World of Symfony ComponentsRyan Weaver
 

Destaque (20)

Get Soaked - An In Depth Look At PHP Streams
Get Soaked - An In Depth Look At PHP StreamsGet Soaked - An In Depth Look At PHP Streams
Get Soaked - An In Depth Look At PHP Streams
 
Elastic Searching With PHP
Elastic Searching With PHPElastic Searching With PHP
Elastic Searching With PHP
 
Techniques d'accélération des pages web
Techniques d'accélération des pages webTechniques d'accélération des pages web
Techniques d'accélération des pages web
 
Diving deep into twig
Diving deep into twigDiving deep into twig
Diving deep into twig
 
PHP5.5 is Here
PHP5.5 is HerePHP5.5 is Here
PHP5.5 is Here
 
Automation using-phing
Automation using-phingAutomation using-phing
Automation using-phing
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP Generators
 
The quest for global design principles (SymfonyLive Berlin 2015)
The quest for global design principles (SymfonyLive Berlin 2015)The quest for global design principles (SymfonyLive Berlin 2015)
The quest for global design principles (SymfonyLive Berlin 2015)
 
Top tips my_sql_performance
Top tips my_sql_performanceTop tips my_sql_performance
Top tips my_sql_performance
 
Mocking Demystified
Mocking DemystifiedMocking Demystified
Mocking Demystified
 
Understanding Craftsmanship SwanseaCon2015
Understanding Craftsmanship SwanseaCon2015Understanding Craftsmanship SwanseaCon2015
Understanding Craftsmanship SwanseaCon2015
 
Why elasticsearch rocks!
Why elasticsearch rocks!Why elasticsearch rocks!
Why elasticsearch rocks!
 
Si le tdd est mort alors pratiquons une autopsie mix-it 2015
Si le tdd est mort alors pratiquons une autopsie mix-it 2015Si le tdd est mort alors pratiquons une autopsie mix-it 2015
Si le tdd est mort alors pratiquons une autopsie mix-it 2015
 
Writing infinite scalability web applications with PHP and PostgreSQL
Writing infinite scalability web applications with PHP and PostgreSQLWriting infinite scalability web applications with PHP and PostgreSQL
Writing infinite scalability web applications with PHP and PostgreSQL
 
L'ABC du BDD (Behavior Driven Development)
L'ABC du BDD (Behavior Driven Development)L'ABC du BDD (Behavior Driven Development)
L'ABC du BDD (Behavior Driven Development)
 
Performance serveur et apache
Performance serveur et apachePerformance serveur et apache
Performance serveur et apache
 
Caching on the Edge
Caching on the EdgeCaching on the Edge
Caching on the Edge
 
Behat 3.0 meetup (March)
Behat 3.0 meetup (March)Behat 3.0 meetup (March)
Behat 3.0 meetup (March)
 
TDD with PhpSpec - Lone Star PHP 2016
TDD with PhpSpec - Lone Star PHP 2016TDD with PhpSpec - Lone Star PHP 2016
TDD with PhpSpec - Lone Star PHP 2016
 
The Wonderful World of Symfony Components
The Wonderful World of Symfony ComponentsThe Wonderful World of Symfony Components
The Wonderful World of Symfony Components
 

Semelhante a Be pragmatic, be SOLID

PHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodePHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodeSWIFTotter Solutions
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosDivante
 
Как получить чёрный пояс по WordPress?
Как получить чёрный пояс по WordPress?Как получить чёрный пояс по WordPress?
Как получить чёрный пояс по WordPress?Yevhen Kotelnytskyi
 
Как получить чёрный пояс по WordPress? v2.0
Как получить чёрный пояс по WordPress? v2.0Как получить чёрный пояс по WordPress? v2.0
Как получить чёрный пояс по WordPress? v2.0Yevhen Kotelnytskyi
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using CodeceptionJeroen van Dijk
 
Demystifying Object-Oriented Programming - ZendCon 2016
Demystifying Object-Oriented Programming - ZendCon 2016Demystifying Object-Oriented Programming - ZendCon 2016
Demystifying Object-Oriented Programming - ZendCon 2016Alena Holligan
 
Objects, Testing, and Responsibility
Objects, Testing, and ResponsibilityObjects, Testing, and Responsibility
Objects, Testing, and Responsibilitymachuga
 
Dependency injection in Drupal 8
Dependency injection in Drupal 8Dependency injection in Drupal 8
Dependency injection in Drupal 8Alexei Gorobets
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patternsSamuel ROZE
 
Clean code for WordPress
Clean code for WordPressClean code for WordPress
Clean code for WordPressmtoppa
 
OOP is more than Cars and Dogs
OOP is more than Cars and Dogs OOP is more than Cars and Dogs
OOP is more than Cars and Dogs Chris Tankersley
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Michelangelo van Dam
 
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)arcware
 
Tidy Up Your Code
Tidy Up Your CodeTidy Up Your Code
Tidy Up Your CodeAbbas Ali
 

Semelhante a Be pragmatic, be SOLID (20)

PHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodePHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better Code
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenarios
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 
Как получить чёрный пояс по WordPress?
Как получить чёрный пояс по WordPress?Как получить чёрный пояс по WordPress?
Как получить чёрный пояс по WordPress?
 
Как получить чёрный пояс по WordPress? v2.0
Как получить чёрный пояс по WordPress? v2.0Как получить чёрный пояс по WordPress? v2.0
Как получить чёрный пояс по WordPress? v2.0
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
Make it SOLID!
Make it SOLID!Make it SOLID!
Make it SOLID!
 
PHP Unit Testing
PHP Unit TestingPHP Unit Testing
PHP Unit Testing
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using Codeception
 
Demystifying Object-Oriented Programming - ZendCon 2016
Demystifying Object-Oriented Programming - ZendCon 2016Demystifying Object-Oriented Programming - ZendCon 2016
Demystifying Object-Oriented Programming - ZendCon 2016
 
Objects, Testing, and Responsibility
Objects, Testing, and ResponsibilityObjects, Testing, and Responsibility
Objects, Testing, and Responsibility
 
Dependency injection in Drupal 8
Dependency injection in Drupal 8Dependency injection in Drupal 8
Dependency injection in Drupal 8
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patterns
 
Solid principles
Solid principlesSolid principles
Solid principles
 
Clean code for WordPress
Clean code for WordPressClean code for WordPress
Clean code for WordPress
 
OOP is more than Cars and Dogs
OOP is more than Cars and Dogs OOP is more than Cars and Dogs
OOP is more than Cars and Dogs
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8
 
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
 
Tidy Up Your Code
Tidy Up Your CodeTidy Up Your Code
Tidy Up Your Code
 

Último

How To Manage Restaurant Staff -BTRESTRO
How To Manage Restaurant Staff -BTRESTROHow To Manage Restaurant Staff -BTRESTRO
How To Manage Restaurant Staff -BTRESTROmotivationalword821
 
Comparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfComparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfDrew Moseley
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesPhilip Schwarz
 
Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Rob Geurden
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfFerryKemperman
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfMarharyta Nedzelska
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsSafe Software
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
Salesforce Implementation Services PPT By ABSYZ
Salesforce Implementation Services PPT By ABSYZSalesforce Implementation Services PPT By ABSYZ
Salesforce Implementation Services PPT By ABSYZABSYZ Inc
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Andreas Granig
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Matt Ray
 
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxUI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxAndreas Kunz
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationBradBedford3
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Angel Borroy López
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringHironori Washizaki
 
Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfStefano Stabellini
 
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsSensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsChristian Birchler
 

Último (20)

How To Manage Restaurant Staff -BTRESTRO
How To Manage Restaurant Staff -BTRESTROHow To Manage Restaurant Staff -BTRESTRO
How To Manage Restaurant Staff -BTRESTRO
 
Comparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfComparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdf
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a series
 
Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdf
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdf
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data Streams
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
Salesforce Implementation Services PPT By ABSYZ
Salesforce Implementation Services PPT By ABSYZSalesforce Implementation Services PPT By ABSYZ
Salesforce Implementation Services PPT By ABSYZ
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
 
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxUI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion Application
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their Engineering
 
Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdf
 
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsSensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
 

Be pragmatic, be SOLID