SlideShare a Scribd company logo
1 of 44
Download to read offline
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

More Related Content

What's hot

Applications Android - cours 11 : Boites de dialogue
Applications Android - cours 11 : Boites de dialogueApplications Android - cours 11 : Boites de dialogue
Applications Android - cours 11 : Boites de dialogueAhmed-Chawki Chaouche
 
Redux Saga - Under the hood
Redux Saga - Under the hoodRedux Saga - Under the hood
Redux Saga - Under the hoodWaqqas Jabbar
 
How to Build ToDo App with Vue 3 + TypeScript
How to Build ToDo App with Vue 3 + TypeScriptHow to Build ToDo App with Vue 3 + TypeScript
How to Build ToDo App with Vue 3 + TypeScriptKaty Slemon
 
Android and NFC / NDEF (with Kotlin)
Android and NFC / NDEF (with Kotlin)Android and NFC / NDEF (with Kotlin)
Android and NFC / NDEF (with Kotlin)Andreas Jakl
 
presentation Ganttproject (TIC et orga)
presentation Ganttproject (TIC et orga)presentation Ganttproject (TIC et orga)
presentation Ganttproject (TIC et orga)Romand
 
AngularJS Architecture
AngularJS ArchitectureAngularJS Architecture
AngularJS ArchitectureEyal Vardi
 
React JS: A Secret Preview
React JS: A Secret PreviewReact JS: A Secret Preview
React JS: A Secret Previewvaluebound
 
Automated Testing With Watir
Automated Testing With WatirAutomated Testing With Watir
Automated Testing With WatirTimothy Fisher
 
Android-Tp4: stockage
Android-Tp4: stockageAndroid-Tp4: stockage
Android-Tp4: stockageLilia Sfaxi
 
Concurrent Rendering Adventures in React 18
Concurrent Rendering Adventures in React 18Concurrent Rendering Adventures in React 18
Concurrent Rendering Adventures in React 18Maurice De Beijer [MVP]
 
React.js and Redux overview
React.js and Redux overviewReact.js and Redux overview
React.js and Redux overviewAlex Bachuk
 
React Router: React Meetup XXL
React Router: React Meetup XXLReact Router: React Meetup XXL
React Router: React Meetup XXLRob Gietema
 
Android-Tp5 : web services
Android-Tp5 : web servicesAndroid-Tp5 : web services
Android-Tp5 : web servicesLilia Sfaxi
 
Introduction to ReactJS
Introduction to ReactJSIntroduction to ReactJS
Introduction to ReactJSKnoldus Inc.
 
Pune Flutter Presents - Flutter 101
Pune Flutter Presents - Flutter 101Pune Flutter Presents - Flutter 101
Pune Flutter Presents - Flutter 101Arif Amirani
 

What's hot (20)

Introduction Node.js
Introduction Node.jsIntroduction Node.js
Introduction Node.js
 
Applications Android - cours 11 : Boites de dialogue
Applications Android - cours 11 : Boites de dialogueApplications Android - cours 11 : Boites de dialogue
Applications Android - cours 11 : Boites de dialogue
 
Redux Saga - Under the hood
Redux Saga - Under the hoodRedux Saga - Under the hood
Redux Saga - Under the hood
 
How to Build ToDo App with Vue 3 + TypeScript
How to Build ToDo App with Vue 3 + TypeScriptHow to Build ToDo App with Vue 3 + TypeScript
How to Build ToDo App with Vue 3 + TypeScript
 
Vuex
VuexVuex
Vuex
 
Android and NFC / NDEF (with Kotlin)
Android and NFC / NDEF (with Kotlin)Android and NFC / NDEF (with Kotlin)
Android and NFC / NDEF (with Kotlin)
 
presentation Ganttproject (TIC et orga)
presentation Ganttproject (TIC et orga)presentation Ganttproject (TIC et orga)
presentation Ganttproject (TIC et orga)
 
AngularJS Architecture
AngularJS ArchitectureAngularJS Architecture
AngularJS Architecture
 
React JS: A Secret Preview
React JS: A Secret PreviewReact JS: A Secret Preview
React JS: A Secret Preview
 
Automated Testing With Watir
Automated Testing With WatirAutomated Testing With Watir
Automated Testing With Watir
 
Android-Tp4: stockage
Android-Tp4: stockageAndroid-Tp4: stockage
Android-Tp4: stockage
 
Concurrent Rendering Adventures in React 18
Concurrent Rendering Adventures in React 18Concurrent Rendering Adventures in React 18
Concurrent Rendering Adventures in React 18
 
React.js and Redux overview
React.js and Redux overviewReact.js and Redux overview
React.js and Redux overview
 
React js
React jsReact js
React js
 
Animations in Flutter
Animations in FlutterAnimations in Flutter
Animations in Flutter
 
React Router: React Meetup XXL
React Router: React Meetup XXLReact Router: React Meetup XXL
React Router: React Meetup XXL
 
Introduction to Redux
Introduction to ReduxIntroduction to Redux
Introduction to Redux
 
Android-Tp5 : web services
Android-Tp5 : web servicesAndroid-Tp5 : web services
Android-Tp5 : web services
 
Introduction to ReactJS
Introduction to ReactJSIntroduction to ReactJS
Introduction to ReactJS
 
Pune Flutter Presents - Flutter 101
Pune Flutter Presents - Flutter 101Pune Flutter Presents - Flutter 101
Pune Flutter Presents - Flutter 101
 

Similar to How I learned to apply Design Patterns and refactor my code for maintainability

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
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
 
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
 
Symfony CoP: Form component
Symfony CoP: Form componentSymfony CoP: Form component
Symfony CoP: Form componentSamuel ROZE
 
Using and reusing CakePHP plugins
Using and reusing CakePHP pluginsUsing and reusing CakePHP plugins
Using and reusing CakePHP pluginsPierre MARTIN
 
Magento Live Australia 2016: Request Flow
Magento Live Australia 2016: Request FlowMagento Live Australia 2016: Request Flow
Magento Live Australia 2016: Request FlowVrann Tulika
 
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 SimpleAlexander Varwijk
 
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 2015Fernando Daciuk
 
How kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonHow kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonKris Wallsmith
 
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 Widgetsvelveeta_512
 
JavaScript and UI Architecture Best Practices
JavaScript and UI Architecture Best PracticesJavaScript and UI Architecture Best Practices
JavaScript and UI Architecture Best PracticesSiarhei Barysiuk
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsMichael Peacock
 
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
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using CodeceptionJeroen van Dijk
 
Test-driven Development with Drupal and Codeception (DrupalCamp Brighton)
Test-driven Development with Drupal and Codeception (DrupalCamp Brighton)Test-driven Development with Drupal and Codeception (DrupalCamp Brighton)
Test-driven Development with Drupal and Codeception (DrupalCamp Brighton)Cogapp
 

Similar to How I learned to apply Design Patterns and refactor my code for maintainability (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
 
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
 
Test-driven Development with Drupal and Codeception (DrupalCamp Brighton)
Test-driven Development with Drupal and Codeception (DrupalCamp Brighton)Test-driven Development with Drupal and Codeception (DrupalCamp Brighton)
Test-driven Development with Drupal and Codeception (DrupalCamp Brighton)
 

More from Samuel ROZE

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)Samuel ROZE
 
Living documentation
Living documentationLiving documentation
Living documentationSamuel ROZE
 
Symfony Messenger (Symfony Live San Francisco)
Symfony Messenger (Symfony Live San Francisco)Symfony Messenger (Symfony Live San Francisco)
Symfony Messenger (Symfony Live San Francisco)Samuel ROZE
 
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 ideaSamuel ROZE
 
Introduction to CQRS and Event Sourcing
Introduction to CQRS and Event SourcingIntroduction to CQRS and Event Sourcing
Introduction to CQRS and Event SourcingSamuel ROZE
 
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 applicationSamuel ROZE
 
Take care of our micro services
Take care of our micro servicesTake care of our micro services
Take care of our micro servicesSamuel ROZE
 
(micro)services avec Symfony et Tolerance
(micro)services avec Symfony et Tolerance(micro)services avec Symfony et Tolerance
(micro)services avec Symfony et ToleranceSamuel ROZE
 
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 workflowsSamuel ROZE
 
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 thatSamuel ROZE
 
Docker orchestration with Kubernetes
Docker orchestration with KubernetesDocker orchestration with Kubernetes
Docker orchestration with KubernetesSamuel ROZE
 
Symfony et serialization avec JMS serializer
Symfony et serialization avec JMS serializer Symfony et serialization avec JMS serializer
Symfony et serialization avec JMS serializer Samuel ROZE
 

More from 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
 

Recently uploaded

Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdfEnhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdfRTS corp
 
Strategies for using alternative queries to mitigate zero results
Strategies for using alternative queries to mitigate zero resultsStrategies for using alternative queries to mitigate zero results
Strategies for using alternative queries to mitigate zero resultsJean Silva
 
Best Angular 17 Classroom & Online training - Naresh IT
Best Angular 17 Classroom & Online training - Naresh ITBest Angular 17 Classroom & Online training - Naresh IT
Best Angular 17 Classroom & Online training - Naresh ITmanoharjgpsolutions
 
VictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News UpdateVictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News UpdateVictoriaMetrics
 
[ CNCF Q1 2024 ] Intro to Continuous Profiling and Grafana Pyroscope.pdf
[ CNCF Q1 2024 ] Intro to Continuous Profiling and Grafana Pyroscope.pdf[ CNCF Q1 2024 ] Intro to Continuous Profiling and Grafana Pyroscope.pdf
[ CNCF Q1 2024 ] Intro to Continuous Profiling and Grafana Pyroscope.pdfSteve Caron
 
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptxThe Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptxRTS corp
 
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdfAndrey Devyatkin
 
eSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration toolseSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration toolsosttopstonverter
 
Osi security architecture in network.pptx
Osi security architecture in network.pptxOsi security architecture in network.pptx
Osi security architecture in network.pptxVinzoCenzo
 
Effectively Troubleshoot 9 Types of OutOfMemoryError
Effectively Troubleshoot 9 Types of OutOfMemoryErrorEffectively Troubleshoot 9 Types of OutOfMemoryError
Effectively Troubleshoot 9 Types of OutOfMemoryErrorTier1 app
 
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdf
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdfPros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdf
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdfkalichargn70th171
 
Keeping your build tool updated in a multi repository world
Keeping your build tool updated in a multi repository worldKeeping your build tool updated in a multi repository world
Keeping your build tool updated in a multi repository worldRoberto Pérez Alcolea
 
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...Bert Jan Schrijver
 
Large Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLarge Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLionel Briand
 
Understanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM ArchitectureUnderstanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM Architecturerahul_net
 
Amazon Bedrock in Action - presentation of the Bedrock's capabilities
Amazon Bedrock in Action - presentation of the Bedrock's capabilitiesAmazon Bedrock in Action - presentation of the Bedrock's capabilities
Amazon Bedrock in Action - presentation of the Bedrock's capabilitiesKrzysztofKkol1
 
2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shards2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shardsChristopher Curtin
 
What’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 UpdatesWhat’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 UpdatesVictoriaMetrics
 
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...OnePlan Solutions
 
Understanding Plagiarism: Causes, Consequences and Prevention.pptx
Understanding Plagiarism: Causes, Consequences and Prevention.pptxUnderstanding Plagiarism: Causes, Consequences and Prevention.pptx
Understanding Plagiarism: Causes, Consequences and Prevention.pptxSasikiranMarri
 

Recently uploaded (20)

Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdfEnhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
 
Strategies for using alternative queries to mitigate zero results
Strategies for using alternative queries to mitigate zero resultsStrategies for using alternative queries to mitigate zero results
Strategies for using alternative queries to mitigate zero results
 
Best Angular 17 Classroom & Online training - Naresh IT
Best Angular 17 Classroom & Online training - Naresh ITBest Angular 17 Classroom & Online training - Naresh IT
Best Angular 17 Classroom & Online training - Naresh IT
 
VictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News UpdateVictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News Update
 
[ CNCF Q1 2024 ] Intro to Continuous Profiling and Grafana Pyroscope.pdf
[ CNCF Q1 2024 ] Intro to Continuous Profiling and Grafana Pyroscope.pdf[ CNCF Q1 2024 ] Intro to Continuous Profiling and Grafana Pyroscope.pdf
[ CNCF Q1 2024 ] Intro to Continuous Profiling and Grafana Pyroscope.pdf
 
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptxThe Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
 
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf
 
eSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration toolseSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration tools
 
Osi security architecture in network.pptx
Osi security architecture in network.pptxOsi security architecture in network.pptx
Osi security architecture in network.pptx
 
Effectively Troubleshoot 9 Types of OutOfMemoryError
Effectively Troubleshoot 9 Types of OutOfMemoryErrorEffectively Troubleshoot 9 Types of OutOfMemoryError
Effectively Troubleshoot 9 Types of OutOfMemoryError
 
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdf
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdfPros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdf
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdf
 
Keeping your build tool updated in a multi repository world
Keeping your build tool updated in a multi repository worldKeeping your build tool updated in a multi repository world
Keeping your build tool updated in a multi repository world
 
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
 
Large Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLarge Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and Repair
 
Understanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM ArchitectureUnderstanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM Architecture
 
Amazon Bedrock in Action - presentation of the Bedrock's capabilities
Amazon Bedrock in Action - presentation of the Bedrock's capabilitiesAmazon Bedrock in Action - presentation of the Bedrock's capabilities
Amazon Bedrock in Action - presentation of the Bedrock's capabilities
 
2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shards2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shards
 
What’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 UpdatesWhat’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 Updates
 
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
 
Understanding Plagiarism: Causes, Consequences and Prevention.pptx
Understanding Plagiarism: Causes, Consequences and Prevention.pptxUnderstanding Plagiarism: Causes, Consequences and Prevention.pptx
Understanding Plagiarism: Causes, Consequences and Prevention.pptx
 

How I learned to apply Design Patterns and refactor my code for maintainability

  • 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