SlideShare a Scribd company logo
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

Vue js for beginner
Vue js for beginner Vue js for beginner
Vue js for beginner
Chandrasekar G
 
Intégration continue et déploiement continue avec Jenkins
Intégration continue et déploiement continue avec JenkinsIntégration continue et déploiement continue avec Jenkins
Intégration continue et déploiement continue avec Jenkins
Kokou Gaglo
 
Express JS
Express JSExpress JS
Express JS
Designveloper
 
SOA for PL/SQL Developer (OPP 2010)
SOA for PL/SQL Developer (OPP 2010)SOA for PL/SQL Developer (OPP 2010)
SOA for PL/SQL Developer (OPP 2010)
Lucas Jellema
 
NestJS
NestJSNestJS
NestJS
Wilson Su
 
Atomicity In Redis: Thomas Hunter
Atomicity In Redis: Thomas HunterAtomicity In Redis: Thomas Hunter
Atomicity In Redis: Thomas Hunter
Redis Labs
 
Node.js
Node.jsNode.js
Spring Framework - Core
Spring Framework - CoreSpring Framework - Core
Spring Framework - Core
Dzmitry Naskou
 
Angular.pdf
Angular.pdfAngular.pdf
Angular.pdf
Jaouad Assabbour
 
Automation with ansible
Automation with ansibleAutomation with ansible
Automation with ansible
Khizer Naeem
 
FHIR Server 安裝與使用
FHIR Server 安裝與使用FHIR Server 安裝與使用
FHIR Server 安裝與使用
Lorex L. Yang
 
Software Design Patterns in Laravel by Phill Sparks
Software Design Patterns in Laravel by Phill SparksSoftware Design Patterns in Laravel by Phill Sparks
Software Design Patterns in Laravel by Phill Sparks
Phill Sparks
 
Nodejs functions & modules
Nodejs functions & modulesNodejs functions & modules
Nodejs functions & modules
monikadeshmane
 
Java 8-streams-collectors-patterns
Java 8-streams-collectors-patternsJava 8-streams-collectors-patterns
Java 8-streams-collectors-patterns
José Paumard
 
Vue, vue router, vuex
Vue, vue router, vuexVue, vue router, vuex
Vue, vue router, vuex
Samundra khatri
 
[오픈소스컨설팅] 스카우터 사용자 가이드 2020
[오픈소스컨설팅] 스카우터 사용자 가이드 2020[오픈소스컨설팅] 스카우터 사용자 가이드 2020
[오픈소스컨설팅] 스카우터 사용자 가이드 2020
Ji-Woong Choi
 
Introduction to Selenium Web Driver
Introduction to Selenium Web DriverIntroduction to Selenium Web Driver
Introduction to Selenium Web Driver
Return on Intelligence
 
PHP 語法基礎與物件導向
PHP 語法基礎與物件導向PHP 語法基礎與物件導向
PHP 語法基礎與物件導向
Shengyou Fan
 
Spring boot
Spring bootSpring boot
Spring boot
Gyanendra Yadav
 

What's hot (20)

Vue js for beginner
Vue js for beginner Vue js for beginner
Vue js for beginner
 
Intégration continue et déploiement continue avec Jenkins
Intégration continue et déploiement continue avec JenkinsIntégration continue et déploiement continue avec Jenkins
Intégration continue et déploiement continue avec Jenkins
 
Express JS
Express JSExpress JS
Express JS
 
SOA for PL/SQL Developer (OPP 2010)
SOA for PL/SQL Developer (OPP 2010)SOA for PL/SQL Developer (OPP 2010)
SOA for PL/SQL Developer (OPP 2010)
 
NestJS
NestJSNestJS
NestJS
 
Atomicity In Redis: Thomas Hunter
Atomicity In Redis: Thomas HunterAtomicity In Redis: Thomas Hunter
Atomicity In Redis: Thomas Hunter
 
Node.js
Node.jsNode.js
Node.js
 
Spring Framework - Core
Spring Framework - CoreSpring Framework - Core
Spring Framework - Core
 
Angular.pdf
Angular.pdfAngular.pdf
Angular.pdf
 
Automation with ansible
Automation with ansibleAutomation with ansible
Automation with ansible
 
Jest
JestJest
Jest
 
FHIR Server 安裝與使用
FHIR Server 安裝與使用FHIR Server 安裝與使用
FHIR Server 安裝與使用
 
Software Design Patterns in Laravel by Phill Sparks
Software Design Patterns in Laravel by Phill SparksSoftware Design Patterns in Laravel by Phill Sparks
Software Design Patterns in Laravel by Phill Sparks
 
Nodejs functions & modules
Nodejs functions & modulesNodejs functions & modules
Nodejs functions & modules
 
Java 8-streams-collectors-patterns
Java 8-streams-collectors-patternsJava 8-streams-collectors-patterns
Java 8-streams-collectors-patterns
 
Vue, vue router, vuex
Vue, vue router, vuexVue, vue router, vuex
Vue, vue router, vuex
 
[오픈소스컨설팅] 스카우터 사용자 가이드 2020
[오픈소스컨설팅] 스카우터 사용자 가이드 2020[오픈소스컨설팅] 스카우터 사용자 가이드 2020
[오픈소스컨설팅] 스카우터 사용자 가이드 2020
 
Introduction to Selenium Web Driver
Introduction to Selenium Web DriverIntroduction to Selenium Web Driver
Introduction to Selenium Web Driver
 
PHP 語法基礎與物件導向
PHP 語法基礎與物件導向PHP 語法基礎與物件導向
PHP 語法基礎與物件導向
 
Spring boot
Spring bootSpring boot
Spring boot
 

Similar to How I started to love design patterns

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
Samuel ROZE
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
Jonathan Wage
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
Lars Jankowfsky
 
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...ZFConf Conference
 
Symfony CoP: Form component
Symfony CoP: Form componentSymfony CoP: Form component
Symfony CoP: Form component
Samuel ROZE
 
Using and reusing CakePHP plugins
Using and reusing CakePHP pluginsUsing and reusing CakePHP plugins
Using and reusing CakePHP plugins
Pierre MARTIN
 
Magento Live Australia 2016: Request Flow
Magento Live Australia 2016: Request FlowMagento Live Australia 2016: Request Flow
Magento Live Australia 2016: Request Flow
Vrann Tulika
 
Clean Javascript
Clean JavascriptClean Javascript
Clean Javascript
Ryunosuke SATO
 
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
Alexander 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 2015
Fernando Daciuk
 
How kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonHow kris-writes-symfony-apps-london
How kris-writes-symfony-apps-london
Kris 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 Widgets
velveeta_512
 
JavaScript and UI Architecture Best Practices
JavaScript and UI Architecture Best PracticesJavaScript and UI Architecture Best Practices
JavaScript and UI Architecture Best Practices
Siarhei 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
 
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
Łukasz Chruściel
 
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
Michelangelo van Dam
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using Codeception
Jeroen van Dijk
 

Similar to 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
 

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 documentation
Samuel 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 idea
Samuel ROZE
 
Introduction to CQRS and Event Sourcing
Introduction to CQRS and Event SourcingIntroduction to CQRS and Event Sourcing
Introduction to CQRS and Event Sourcing
Samuel 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 application
Samuel ROZE
 
Take care of our micro services
Take care of our micro servicesTake care of our micro services
Take care of our micro services
Samuel ROZE
 
(micro)services avec Symfony et Tolerance
(micro)services avec Symfony et Tolerance(micro)services avec Symfony et Tolerance
(micro)services avec Symfony et Tolerance
Samuel 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 workflows
Samuel 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 that
Samuel ROZE
 
Docker orchestration with Kubernetes
Docker orchestration with KubernetesDocker orchestration with Kubernetes
Docker orchestration with Kubernetes
Samuel 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

Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Anthony Dahanne
 
BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024
Ortus Solutions, Corp
 
Accelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with PlatformlessAccelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with Platformless
WSO2
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
Globus
 
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data AnalysisProviding Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Globus
 
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Shahin Sheidaei
 
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
Tier1 app
 
Explore Modern SharePoint Templates for 2024
Explore Modern SharePoint Templates for 2024Explore Modern SharePoint Templates for 2024
Explore Modern SharePoint Templates for 2024
Sharepoint Designs
 
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Globus
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
Paco van Beckhoven
 
Visitor Management System in India- Vizman.app
Visitor Management System in India- Vizman.appVisitor Management System in India- Vizman.app
Visitor Management System in India- Vizman.app
NaapbooksPrivateLimi
 
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
informapgpstrackings
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
Globus
 
GlobusWorld 2024 Opening Keynote session
GlobusWorld 2024 Opening Keynote sessionGlobusWorld 2024 Opening Keynote session
GlobusWorld 2024 Opening Keynote session
Globus
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns
 
Strategies for Successful Data Migration Tools.pptx
Strategies for Successful Data Migration Tools.pptxStrategies for Successful Data Migration Tools.pptx
Strategies for Successful Data Migration Tools.pptx
varshanayak241
 
How Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptxHow Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptx
wottaspaceseo
 
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.ILBeyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Natan Silnitsky
 
A Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdfA Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdf
kalichargn70th171
 
Large Language Models and the End of Programming
Large Language Models and the End of ProgrammingLarge Language Models and the End of Programming
Large Language Models and the End of Programming
Matt Welsh
 

Recently uploaded (20)

Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
 
BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024
 
Accelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with PlatformlessAccelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with Platformless
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
 
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data AnalysisProviding Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
 
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
 
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
 
Explore Modern SharePoint Templates for 2024
Explore Modern SharePoint Templates for 2024Explore Modern SharePoint Templates for 2024
Explore Modern SharePoint Templates for 2024
 
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
 
Visitor Management System in India- Vizman.app
Visitor Management System in India- Vizman.appVisitor Management System in India- Vizman.app
Visitor Management System in India- Vizman.app
 
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
 
GlobusWorld 2024 Opening Keynote session
GlobusWorld 2024 Opening Keynote sessionGlobusWorld 2024 Opening Keynote session
GlobusWorld 2024 Opening Keynote session
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology Solutions
 
Strategies for Successful Data Migration Tools.pptx
Strategies for Successful Data Migration Tools.pptxStrategies for Successful Data Migration Tools.pptx
Strategies for Successful Data Migration Tools.pptx
 
How Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptxHow Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptx
 
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.ILBeyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
 
A Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdfA Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdf
 
Large Language Models and the End of Programming
Large Language Models and the End of ProgrammingLarge Language Models and the End of Programming
Large Language Models and the End of Programming
 

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