SlideShare ist ein Scribd-Unternehmen logo
1 von 44
Downloaden Sie, um offline zu lesen
How I started to love what
they call
Design Patterns
@samuelroze
Samuel Rozé
VP of Engineering @ Birdie
Symfony
ContinuousPipe
Tolerance
I started years ago...
I probably wrote that
<?php
include 'header.php';
include 'pages/'. $_GET['page'].'.php';
include 'footer.php';
At some point I used Symfony
class EntityController extends AbstractController
{
public function action(
EntityManagerInterface $entityManager,
string $identifier
) {
$entity = $entityManager->getRepository(Entity::class)
->find($identifier);
return $this->render('my-template.html.twig', [
'entity' => $entity,
]);
}
}
Then I updated my entity...
public function action(
EntityManagerInterface $entityManager,
Request $request,
string $identifier
) {
// ...
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if ($form->isValid()) {
$entity = $form->getData();
$entityManager->persist($entity);
$entityManager->flush();
}
}
// ...
}
Then I sent an email
// ...
if ($form->isValid()) {
$entity = $form->getData();
$entityManager->persist($entity);
$entityManager->flush();
$mailer->send(
(new Email())
->setTo('samuel.roze@gmail.com')
->setBody('Very long text here...')
->setFrom('My super application')
// ...
);
}
// ...
Well... that's long!
class EntityController extends AbstractController
{
public function action(
EntityManagerInterface $entityManager,
MailerInterface $mailer,
Request $request,
string $identifier
) {
$entity = $entityManager->getRepository(Entity::class)
->find($identifier);
$form = $this->createForm(EntityFormType::class, $entity);
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if ($form->isValid()) {
$entity = $form->getData();
$entityManager->persist($entity);
$entityManager->flush();
$mailer->send(
(new Email())
->setTo('samuel.roze@gmail.com')
->setBody('Very long text here...')
->setFrom('My super application')
);
}
}
return $this->render('my-template.html.twig', [
'entity' => $entity,
]);
}
}
And then...
It became un-maintanable
Design Patterns
A general reusable solution
to a commonly occurring
problem within a given
context.
1
Wikipedia
All the design patterns do
the same thing: control the
information flow.
1
Anthony Ferrara
Let's do some refactoring!
Why do we refactor?
4 We want to reuse code
4 So we delegate the responsibilities
4 And improve the readability
4 And therefore we ensure maintainability
4 By doing so we enable change
Adapter
Adapter
interface EntityRepository
{
public function find(string $identifier): ?Entity;
public function save(Entity $entity): Entity;
}
Adapter
final class DoctrineEntityRepository implements EntityRepository
{
private $entityManager;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
public function find(string $identifier) : ?Entity
{
return $this->entityManager->getRepository(Entity::class)
->find($identifier);
}
// ...
}
Adapter
final class DoctrineEntityRepository implements EntityRepository
{
// ...
public function save(Entity $entity) : Entity
{
$entity = $this->entityManager->merge($entity);
$this->entityManager->persist($entity);
$this->entityManager->flush();
return $entity;
}
}
class EntityController extends AbstractController
{
public function action(
EntityRepository $entityRepository,
Request $request,
string $identifier
) {
$entity = $entityRepository->find($identifier);
// ...
if ($form->isValid()) {
$entityRepository->save($entity);
$mailer->send(
(new Email())->setBody('Hey, something was updated!')
);
}
}
}
class EntityController
{
public function __construct(EntityRepository $entityRepository, /** ... **/)
{ /** ... **/ }
public function action(Request $request, string $identifier)
{
$entity = $this->entityRepository->find($identifier);
// ...
if ($form->isValid()) {
$this->entityRepository->save($entity);
$this->mailer->send(
Swift_Message::newInstance()
->setBody('Hey, something was updated!')
);
}
}
}
Store the entity in-memory?
final class InMemoryEntityRepository implements EntityRepository
{
private $entities = [];
public function find(string $identifier) : ?Entity
{
return $this->entities[$identifier] ?? null;
}
public function save(Entity $entity) : Entity
{
$this->entities[$entity->getIdentifier()] = $entity;
return $entity;
}
}
Multiple implementations: The Yaml
bits
# config/services.yaml
services:
_defaults:
autoconfigure: true
autowire: true
# ...
AppEntityRepository:
alias: AppInfrastructureDoctrineDoctrineEntityRepository
Fast tests?
# config/services_test.yaml
services:
# ...
AppEntityRepository:
alias: AppTestsInMemoryInMemoryEntityRepository
Event Dispatcher
Dispatching the event
class MyController
{
public function __construct(
EntityRepository $entityRepository,
EventDispatcherInterface $eventDispatcher
) { /* ... */ }
public function action(Request $request, string $identifier)
{
// ...
if ($form->isValid()) {
$this->entityRepository->save($entity);
$this->eventDispatcher->dispatch(
EntitySaved::NAME,
new EntitySaved($entity)
);
}
// ...
}
}
An event
class EntitySaved extends Event
{
const NAME = 'entity.saved';
private $entity;
public function __construct(Entity $entity)
{
$this->entity = $entity;
}
public function getEntity() : Entity
{
return $this->entity;
}
}
A listener
final class SendAnEmailWhenEntityIsSaved
{
public function __construct(MailerInterface $mailer)
{ /** ... **/ }
public function onEntitySaved(EntitySaved $event)
{
$this->mailer->send(/** something **/);
}
}
Wiring it
final class SendAnEmailWhenEntityIsSaved implements EventSubscriberInterface
{
// ...
public static function getSubscribedEvents()
{
return [
EntitySaved::NAME => 'onEntitySaved',
];
}
public function onEntitySaved(EntitySaved $event)
{
// ...
}
}
What is the point?
4 The controller just have to dispatch this event
4 We can create another listener easily
4 Much easier to group things per feature
Decorator
final class DispatchAnEventWhenEntityIsSaved implements EntityRepository
{
public function __construct(
EntityRepository $decoratedRepository,
EventDispatcherInterface $eventDispatcher
) { /** ... **/ }
public function find(string $identifier) : ?Entity
{
return $this->decoratedRepository->find($identifier);
}
public function save(Entity $entity) : Entity
{
$saved = $this->decoratedRepository->save($entity);
$this->eventDispatcher->dispatch(
EntitySaved::NAME, new EntitySaved($saved)
);
return $saved;
}
}
Decorates the repository: Plumbing!
# config/services.yaml
services:
# ...
AppEntityRepositoryDispatchAnEventWhenEntityIsSaved:
decorates: AppEntityRepository
arguments:
- "@AppEntityRepositoryDispatchAnEventWhenEntityIsSaved.inner"
We just have to save
class MyController
{
public function action(Request $request, $identifier)
{
// ...
if ($form->isValid()) {
$this->entityRepository->save($entity);
}
// ...
}
}
Decorates all the things!
What do we have?
4 Easy-to-change entity storage
4 Events dispatched regarding of the storage
implementation
4 Easy-to-turn-on-and-off actions (on events)
4 Easily testable code!
Design patterns: they just
help us to enable change
How to apply that...
4 Closes the door!
4 Uses final keyword
4 private properties
4 Create extension points when required
4 Prevent in case of
Maintainability tips
4 Distinct features in their own namespaces
4 Interfaces' names should reflect their
responsibilities
4 Implementations' names should reflect their
distinction
Thank you!
@samuelroze
birdie.care
https://joind.in/talk/ae6c3

Weitere ähnliche Inhalte

Was ist angesagt?

Intégration continue
Intégration continueIntégration continue
Intégration continue
Klee Group
 
Android audio system(오디오 플링거 서비스 초기화)
Android audio system(오디오 플링거 서비스 초기화)Android audio system(오디오 플링거 서비스 초기화)
Android audio system(오디오 플링거 서비스 초기화)
fefe7270
 
How to install adobe dreamweaver 4
How to install adobe dreamweaver 4How to install adobe dreamweaver 4
How to install adobe dreamweaver 4
Jahid Blackrose
 

Was ist angesagt? (20)

Adding System Call to Kernel
Adding System Call to KernelAdding System Call to Kernel
Adding System Call to Kernel
 
Java Input Output and File Handling
Java Input Output and File HandlingJava Input Output and File Handling
Java Input Output and File Handling
 
Intégration continue
Intégration continueIntégration continue
Intégration continue
 
Android audio system(오디오 플링거 서비스 초기화)
Android audio system(오디오 플링거 서비스 초기화)Android audio system(오디오 플링거 서비스 초기화)
Android audio system(오디오 플링거 서비스 초기화)
 
C# Programming: Fundamentals
C# Programming: FundamentalsC# Programming: Fundamentals
C# Programming: Fundamentals
 
Project 2 - how to compile os161?
Project 2 - how to compile os161?Project 2 - how to compile os161?
Project 2 - how to compile os161?
 
Kivy - Python UI Library for Any Platform
Kivy - Python UI Library for Any PlatformKivy - Python UI Library for Any Platform
Kivy - Python UI Library for Any Platform
 
Selenium Tutorial Java
Selenium Tutorial  JavaSelenium Tutorial  Java
Selenium Tutorial Java
 
Reflection in C Sharp
Reflection in C SharpReflection in C Sharp
Reflection in C Sharp
 
Shellscripting
ShellscriptingShellscripting
Shellscripting
 
Java 8-streams-collectors-patterns
Java 8-streams-collectors-patternsJava 8-streams-collectors-patterns
Java 8-streams-collectors-patterns
 
expression lambda
expression lambdaexpression lambda
expression lambda
 
Chapitre 6 traitement des exceptions
Chapitre 6  traitement des exceptionsChapitre 6  traitement des exceptions
Chapitre 6 traitement des exceptions
 
How to install adobe dreamweaver 4
How to install adobe dreamweaver 4How to install adobe dreamweaver 4
How to install adobe dreamweaver 4
 
Introduction to C++
Introduction to C++Introduction to C++
Introduction to C++
 
Sinatra
SinatraSinatra
Sinatra
 
Practical Class 12th (c++programs+sql queries and output)
Practical Class 12th (c++programs+sql queries and output) Practical Class 12th (c++programs+sql queries and output)
Practical Class 12th (c++programs+sql queries and output)
 
Kotlin Coroutines and Android sitting in a tree
Kotlin Coroutines and Android sitting in a treeKotlin Coroutines and Android sitting in a tree
Kotlin Coroutines and Android sitting in a tree
 
Homer - Workshop at Kamailio World 2017
Homer - Workshop at Kamailio World 2017Homer - Workshop at Kamailio World 2017
Homer - Workshop at Kamailio World 2017
 
PowerShell 101
PowerShell 101PowerShell 101
PowerShell 101
 

Ähnlich wie How I started to love design patterns

ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf Conference
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friends
Michael Peacock
 

Ähnlich wie How I started to love design patterns (20)

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
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
Using the Windows 8 Runtime from C++
Using the Windows 8 Runtime from C++Using the Windows 8 Runtime from C++
Using the Windows 8 Runtime from C++
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
 
Symfony CoP: Form component
Symfony CoP: Form componentSymfony CoP: Form component
Symfony CoP: Form component
 
Using and reusing CakePHP plugins
Using and reusing CakePHP pluginsUsing and reusing CakePHP plugins
Using and reusing CakePHP plugins
 
Magento Live Australia 2016: Request Flow
Magento Live Australia 2016: Request FlowMagento Live Australia 2016: Request Flow
Magento Live Australia 2016: Request Flow
 
Clean Javascript
Clean JavascriptClean Javascript
Clean Javascript
 
DrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and Simple
DrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and SimpleDrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and Simple
DrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and Simple
 
WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015
 
How kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonHow kris-writes-symfony-apps-london
How kris-writes-symfony-apps-london
 
Getting the Most Out of jQuery Widgets
Getting the Most Out of jQuery WidgetsGetting the Most Out of jQuery Widgets
Getting the Most Out of jQuery Widgets
 
Separation of concerns - DPC12
Separation of concerns - DPC12Separation of concerns - DPC12
Separation of concerns - DPC12
 
JavaScript and UI Architecture Best Practices
JavaScript and UI Architecture Best PracticesJavaScript and UI Architecture Best Practices
JavaScript and UI Architecture Best Practices
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friends
 
Migrare da symfony 1 a Symfony2
 Migrare da symfony 1 a Symfony2  Migrare da symfony 1 a Symfony2
Migrare da symfony 1 a Symfony2
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New Features
 
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
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using Codeception
 

Mehr von Samuel ROZE

Mehr von Samuel ROZE (12)

Event streaming: what will go wrong? (Symfony World 2020)
Event streaming: what will go wrong? (Symfony World 2020)Event streaming: what will go wrong? (Symfony World 2020)
Event streaming: what will go wrong? (Symfony World 2020)
 
Living documentation
Living documentationLiving documentation
Living documentation
 
Symfony Messenger (Symfony Live San Francisco)
Symfony Messenger (Symfony Live San Francisco)Symfony Messenger (Symfony Live San Francisco)
Symfony Messenger (Symfony Live San Francisco)
 
Micro services may not be the best idea
Micro services may not be the best ideaMicro services may not be the best idea
Micro services may not be the best idea
 
Introduction to CQRS and Event Sourcing
Introduction to CQRS and Event SourcingIntroduction to CQRS and Event Sourcing
Introduction to CQRS and Event Sourcing
 
CQRS and Event Sourcing in a Symfony application
CQRS and Event Sourcing in a Symfony applicationCQRS and Event Sourcing in a Symfony application
CQRS and Event Sourcing in a Symfony application
 
Take care of our micro services
Take care of our micro servicesTake care of our micro services
Take care of our micro services
 
(micro)services avec Symfony et Tolerance
(micro)services avec Symfony et Tolerance(micro)services avec Symfony et Tolerance
(micro)services avec Symfony et Tolerance
 
Using continuouspipe to speed up our workflows
Using continuouspipe to speed up our workflowsUsing continuouspipe to speed up our workflows
Using continuouspipe to speed up our workflows
 
Behat c'est plus que ça | Behat is more than that
Behat c'est plus que ça | Behat is more than thatBehat c'est plus que ça | Behat is more than that
Behat c'est plus que ça | Behat is more than that
 
Docker orchestration with Kubernetes
Docker orchestration with KubernetesDocker orchestration with Kubernetes
Docker orchestration with Kubernetes
 
Symfony et serialization avec JMS serializer
Symfony et serialization avec JMS serializer Symfony et serialization avec JMS serializer
Symfony et serialization avec JMS serializer
 

Kürzlich hochgeladen

%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
masabamasaba
 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
chiefasafspells
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 

Kürzlich hochgeladen (20)

%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptx
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the Situation
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 

How I started to love design patterns

  • 1. How I started to love what they call Design Patterns @samuelroze
  • 2. Samuel Rozé VP of Engineering @ Birdie Symfony ContinuousPipe Tolerance
  • 3.
  • 5. I probably wrote that <?php include 'header.php'; include 'pages/'. $_GET['page'].'.php'; include 'footer.php';
  • 6. At some point I used Symfony class EntityController extends AbstractController { public function action( EntityManagerInterface $entityManager, string $identifier ) { $entity = $entityManager->getRepository(Entity::class) ->find($identifier); return $this->render('my-template.html.twig', [ 'entity' => $entity, ]); } }
  • 7. Then I updated my entity... public function action( EntityManagerInterface $entityManager, Request $request, string $identifier ) { // ... if ($request->isMethod('POST')) { $form->handleRequest($request); if ($form->isValid()) { $entity = $form->getData(); $entityManager->persist($entity); $entityManager->flush(); } } // ... }
  • 8. Then I sent an email // ... if ($form->isValid()) { $entity = $form->getData(); $entityManager->persist($entity); $entityManager->flush(); $mailer->send( (new Email()) ->setTo('samuel.roze@gmail.com') ->setBody('Very long text here...') ->setFrom('My super application') // ... ); } // ...
  • 9. Well... that's long! class EntityController extends AbstractController { public function action( EntityManagerInterface $entityManager, MailerInterface $mailer, Request $request, string $identifier ) { $entity = $entityManager->getRepository(Entity::class) ->find($identifier); $form = $this->createForm(EntityFormType::class, $entity); if ($request->isMethod('POST')) { $form->handleRequest($request); if ($form->isValid()) { $entity = $form->getData(); $entityManager->persist($entity); $entityManager->flush(); $mailer->send( (new Email()) ->setTo('samuel.roze@gmail.com') ->setBody('Very long text here...') ->setFrom('My super application') ); } } return $this->render('my-template.html.twig', [ 'entity' => $entity, ]); } }
  • 10. And then... It became un-maintanable
  • 12. A general reusable solution to a commonly occurring problem within a given context. 1 Wikipedia
  • 13.
  • 14. All the design patterns do the same thing: control the information flow. 1 Anthony Ferrara
  • 15. Let's do some refactoring!
  • 16. Why do we refactor? 4 We want to reuse code 4 So we delegate the responsibilities 4 And improve the readability 4 And therefore we ensure maintainability 4 By doing so we enable change
  • 18.
  • 19. Adapter interface EntityRepository { public function find(string $identifier): ?Entity; public function save(Entity $entity): Entity; }
  • 20. Adapter final class DoctrineEntityRepository implements EntityRepository { private $entityManager; public function __construct(EntityManagerInterface $entityManager) { $this->entityManager = $entityManager; } public function find(string $identifier) : ?Entity { return $this->entityManager->getRepository(Entity::class) ->find($identifier); } // ... }
  • 21. Adapter final class DoctrineEntityRepository implements EntityRepository { // ... public function save(Entity $entity) : Entity { $entity = $this->entityManager->merge($entity); $this->entityManager->persist($entity); $this->entityManager->flush(); return $entity; } }
  • 22. class EntityController extends AbstractController { public function action( EntityRepository $entityRepository, Request $request, string $identifier ) { $entity = $entityRepository->find($identifier); // ... if ($form->isValid()) { $entityRepository->save($entity); $mailer->send( (new Email())->setBody('Hey, something was updated!') ); } } }
  • 23. class EntityController { public function __construct(EntityRepository $entityRepository, /** ... **/) { /** ... **/ } public function action(Request $request, string $identifier) { $entity = $this->entityRepository->find($identifier); // ... if ($form->isValid()) { $this->entityRepository->save($entity); $this->mailer->send( Swift_Message::newInstance() ->setBody('Hey, something was updated!') ); } } }
  • 24. Store the entity in-memory? final class InMemoryEntityRepository implements EntityRepository { private $entities = []; public function find(string $identifier) : ?Entity { return $this->entities[$identifier] ?? null; } public function save(Entity $entity) : Entity { $this->entities[$entity->getIdentifier()] = $entity; return $entity; } }
  • 25. Multiple implementations: The Yaml bits # config/services.yaml services: _defaults: autoconfigure: true autowire: true # ... AppEntityRepository: alias: AppInfrastructureDoctrineDoctrineEntityRepository
  • 26. Fast tests? # config/services_test.yaml services: # ... AppEntityRepository: alias: AppTestsInMemoryInMemoryEntityRepository
  • 28.
  • 29. Dispatching the event class MyController { public function __construct( EntityRepository $entityRepository, EventDispatcherInterface $eventDispatcher ) { /* ... */ } public function action(Request $request, string $identifier) { // ... if ($form->isValid()) { $this->entityRepository->save($entity); $this->eventDispatcher->dispatch( EntitySaved::NAME, new EntitySaved($entity) ); } // ... } }
  • 30. An event class EntitySaved extends Event { const NAME = 'entity.saved'; private $entity; public function __construct(Entity $entity) { $this->entity = $entity; } public function getEntity() : Entity { return $this->entity; } }
  • 31. A listener final class SendAnEmailWhenEntityIsSaved { public function __construct(MailerInterface $mailer) { /** ... **/ } public function onEntitySaved(EntitySaved $event) { $this->mailer->send(/** something **/); } }
  • 32. Wiring it final class SendAnEmailWhenEntityIsSaved implements EventSubscriberInterface { // ... public static function getSubscribedEvents() { return [ EntitySaved::NAME => 'onEntitySaved', ]; } public function onEntitySaved(EntitySaved $event) { // ... } }
  • 33. What is the point? 4 The controller just have to dispatch this event 4 We can create another listener easily 4 Much easier to group things per feature
  • 35.
  • 36. final class DispatchAnEventWhenEntityIsSaved implements EntityRepository { public function __construct( EntityRepository $decoratedRepository, EventDispatcherInterface $eventDispatcher ) { /** ... **/ } public function find(string $identifier) : ?Entity { return $this->decoratedRepository->find($identifier); } public function save(Entity $entity) : Entity { $saved = $this->decoratedRepository->save($entity); $this->eventDispatcher->dispatch( EntitySaved::NAME, new EntitySaved($saved) ); return $saved; } }
  • 37. Decorates the repository: Plumbing! # config/services.yaml services: # ... AppEntityRepositoryDispatchAnEventWhenEntityIsSaved: decorates: AppEntityRepository arguments: - "@AppEntityRepositoryDispatchAnEventWhenEntityIsSaved.inner"
  • 38. We just have to save class MyController { public function action(Request $request, $identifier) { // ... if ($form->isValid()) { $this->entityRepository->save($entity); } // ... } }
  • 39. Decorates all the things!
  • 40. What do we have? 4 Easy-to-change entity storage 4 Events dispatched regarding of the storage implementation 4 Easy-to-turn-on-and-off actions (on events) 4 Easily testable code!
  • 41. Design patterns: they just help us to enable change
  • 42. How to apply that... 4 Closes the door! 4 Uses final keyword 4 private properties 4 Create extension points when required 4 Prevent in case of
  • 43. Maintainability tips 4 Distinct features in their own namespaces 4 Interfaces' names should reflect their responsibilities 4 Implementations' names should reflect their distinction