SlideShare a Scribd company logo
1 of 130
Download to read offline
HTTP caching and Symfony2



Be lazy, be ESI



   Alessandro Nadalin
         May, 13 2011
Symfony2 sucks
    at caching
because it doesn't have an application caching layer
high five, that's great
Sf2 embraces the HTTP caching specification

          and that's not because
Fabien is
  lazy
that's because
Fabien kicks asses
HTTP cache
     is a

   King
 in Symfony2
Caching in Symfony2
Caching is, obviously, a matter of the response
since the response is an object,
 we have some basic OO stuff
    to handle HTTP cache
Creating a response

public function indexAction()
{
  $res = $this->render('MyBundle:Default:home.html.twig', array(
     'title' => 'My blog',
  ));

    return $res;
}
Creating a response

public function indexAction()
{
  $res = $this->render('MyBundle:Default:home.html.twig', array(
     'title' => 'My blog',
  ));

    return $res;
}
Creating a response

public function indexAction()
{
  $res = $this->render('MyBundle:Default:home.html.twig', array(
     'title' => 'My blog',
  ));

    return $res;
}
Creating a response

public function indexAction()
{
  $res = $this->render('MyBundle:Default:home.html.twig', array(
     'title' => 'My blog',
  ));

    return $res;
}
Creating a response

public function indexAction()
{
  $res = $this->render('MyBundle:Default:home.html.twig', array(
     'title' => 'My blog',
  ));

    return $res;
}
Creating a response

public function indexAction()
{
  $res = $this->render('MyBundle:Default:home.html.twig', array(
     'title' => 'My blog',
  ));

    return $res;
}
Expiration
Expiration

public function indexAction()
{
  $res = $this->render('MyBundle:Default:home.html.twig', array(
     'title' => 'My blog',
  ));

    $date = new DateTime();
    $date->modify('+600 seconds');

    $res->setExpires($date);

    return $res;
}
Expiration

public function indexAction()
{
  $res = $this->render('MyBundle:Default:home.html.twig', array(
     'title' => 'My blog',
  ));

    $date = new DateTime();
    $date->modify('+600 seconds');

    $res->setExpires($date);

    return $res;
}
Expiration

public function indexAction()
{
  $res = $this->render('MyBundle:Default:home.html.twig', array(
     'title' => 'My blog',
  ));

    $date = new DateTime();
    $date->modify('+600 seconds');

    $res->setExpires($date);

    return $res;
}
Expiration through Cache-Control

public function indexAction()
{
  $res = $this->render('MyBundle:Default:home.html.twig', array(
     'title' => 'My blog',
  ));

    $res->setMaxAge(600);
    $res->setSharedMaxAge(600);

    return $res;
}
Expiration through Cache-Control

public function indexAction()
{
  $res = $this->render('MyBundle:Default:home.html.twig', array(
     'title' => 'My blog',
  ));

    $res->setMaxAge(600);
    $res->setSharedMaxAge(600);

    return $res;
}
Expiration through Cache-Control

public function indexAction()
{
  $res = $this->render('MyBundle:Default:home.html.twig', array(
     'title' => 'My blog',
  ));

    $res->setMaxAge(600);
    $res->setSharedMaxAge(600);

    return $res;
}
Expiration through Cache-Control

public function indexAction()
{
  $res = $this->render('MyBundle:Default:home.html.twig', array(
     'title' => 'My blog',
  ));

    $res->setMaxAge(600);
    $res->setSharedMaxAge(600);

    return $res;
}
              Shared caches, like Symfony2 reverse proxy
Validation
Validation

public function articleAction($id)
{
  $article = $this->get('entity_manager')->query($id)...
  $res = $this->render('MyBundle:Default:article.html.twig', array(
     'article'  => '$article',
  ));

  $etag = "article:{$article->getId()}:{$article->getVersion()}";

  $res->setETag($etag);
  $res->setLastModified($article->getModifiedAt());

 return $res;
Validation

public function articleAction($id)
{
  $article = $this->get('entity_manager')->query($id)...
  $res = $this->render('MyBundle:Default:article.html.twig', array(
     'article'  => '$article',
  ));

  $etag = "article:{$article->getId()}:{$article->getVersion()}";

  $res->setETag($etag);
  $res->setLastModified($article->getModifiedAt());

 return $res;
Validation

public function articleAction($id)
{
  $article = $this->get('entity_manager')->query($id)...
  $res = $this->render('MyBundle:Default:article.html.twig', array(
     'article'  => '$article',
  ));

  $etag = "article:{$article->getId()}:{$article->getVersion()}";

  $res->setETag($etag);
  $res->setLastModified($article->getModifiedAt());

 return $res;
Validation

public function articleAction($id)
{
  $article = $this->get('entity_manager')->query($id)...
  $res = $this->render('MyBundle:Default:article.html.twig', array(
     'article'  => '$article',
  ));

  $etag = "article:{$article->getId()}:{$article->getVersion()}";

  $res->setETag($etag);
  $res->setLastModified($article->getModifiedAt());

 return $res;
Validation

public function articleAction($id)
{
  $article = $this->get('entity_manager')->query($id)...
  $res = $this->render('MyBundle:Default:article.html.twig', array(
     'article'  => '$article',
  ));

  $etag = "article:{$article->getId()}:{$article->getVersion()}";
                        Datetime object
  $res->setETag($etag);
  $res->setLastModified($article->getModifiedAt());

 return $res;
Automagically get a Datetime from Doctrine2


namespace AcmeBlogBundleEntity;

/**
 * @orm:Entity
 * @orm:Table(name="article")
 */
class Article
{
   /**
    * @orm:Column(type="datetime", name="modified_at")
    */
   protected $modifiedAt;
Automagically get a Datetime from Doctrine2


namespace AcmeBlogBundleEntity;

/**
 * @orm:Entity
 * @orm:Table(name="article")
 */
class Article
{
   /**
    * @orm:Column(type="datetime", name="modified_at")
    */
   protected $modifiedAt;
but hey, you say
what's the advatage of using validation if we always hit

         the DB and create a new Response?
Validation, the right way

public function articleAction($id)
{
  $res          = new Response()

  $etag        = Memcache::get("Article:{$id}:etag");
  $lastModified = Memcache::get("Article:{$id}:last_modified");
  $res->setETag($etag);
  $res->setLastModified($lastModified);

  if ($res->isNotModified($this->get('request'))) {
     return $res;
  }

   $article = $this->get('entity_manager')->query($id)...
 ...
Validation, the right way

public function articleAction($id)
{
  $res          = new Response()

  $etag        = Memcache::get("Article:{$id}:etag");
  $lastModified = Memcache::get("Article:{$id}:last_modified");
  $res->setETag($etag);
  $res->setLastModified($lastModified);

  if ($res->isNotModified($this->get('request'))) {
     return $res;
  }

   $article = $this->get('entity_manager')->query($id)...
 ...
Validation, the right way

public function articleAction($id)
{
  $res          = new Response()

  $etag        = Memcache::get("Article:{$id}:etag");
  $lastModified = Memcache::get("Article:{$id}:last_modified");
  $res->setETag($etag);
  $res->setLastModified($lastModified);

  if ($res->isNotModified($this->get('request'))) {
     return $res;
  }

   $article = $this->get('entity_manager')->query($id)...
 ...
Validation, the right way

public function articleAction($id)
{
  $res          = new Response()

  $etag        = Memcache::get("Article:{$id}:etag");
  $lastModified = Memcache::get("Article:{$id}:last_modified");
  $res->setETag($etag);
  $res->setLastModified($lastModified);

  if ($res->isNotModified($this->get('request'))) {
     return $res;
  }

   $article = $this->get('entity_manager')->query($id)...
 ...
relax
Calculating an Etag, or a date, is cheaper
  than generating a full MVC response
Control your power
Additional management


public function articleAction($id)
{
  $res = new Response()

  $res->setVary(array(
     'Accept-Encoding',
  ));

  $res->setPublic();

  $res->setNotModified();

 ...
Varying the response


public function articleAction($id)
{
  $res = new Response()

  $res->setVary(array(
    'Accept-Encoding',
  ));

  $res->setPublic();

  $res->setNotModified();

 ...
Cacheable by all caches


public function articleAction($id)
{
  $res = new Response()

  $res->setVary(array(
     'Accept-Encoding',
  ));

  $res->setPublic();

  $res->setNotModified();

 ...
or by local only


public function articleAction($id)
{
  $res = new Response()

  $res->setVary(array(
     'Accept-Encoding',
  ));

  $res->setPrivate();

  $res->setNotModified();

 ...
Good old 304


public function articleAction($id)
{
  $res = new Response()

  $res->setVary(array(
     'Accept-Encoding',
  ));

  $res->setPrivate();

  $res->setNotModified();

 ...
Stale


public function articleAction($id)
{
  $res = new Response()

  $res->setVary(array(
     'Accept-Encoding',
  ));

  $res->setPrivate();

  $res->expire();

 ...
but hey, you say
HTTP's cache fails when dealing with really dynamic pages,
because consumers will always have to hit the origin server,
although a part of the page would be cacheable ( header and
                                       footer, for example )
no bueno, you say
NOPE
ESI was built for that
            http://www.w3.org/TR/esi-lang


<esi:include src="http://mysite.com/twitterfeeds.html" />
ESI and Symfony2

# controller
$response->setSharedMaxAge(3600);

# app/config/config.yml
framework:
  esi: { enabled: true }

# template
{% render '...:twitterFeeds' with {}, {'standalone': true} %}

# fragment controller
$response->setSharedMaxAge(15);
ESI and Symfony2

# controller
$response->setSharedMaxAge(3600);

# app/config/config.yml
framework:
  esi: { enabled: true }

# template
{% render '...:twitterFeeds' with {}, {'standalone': true} %}

# fragment controller
$response->setSharedMaxAge(15);
ESI and Symfony2

# controller
$response->setSharedMaxAge(3600);

# app/config/config.yml
framework:
  esi: { enabled: true }

# template
{% render '...:twitterFeeds' with {}, {'standalone': true} %}

# fragment controller
$response->setSharedMaxAge(15);
ESI and Symfony2

# controller
$response->setSharedMaxAge(3600);

# app/config/config.yml
framework:
  esi: { enabled: true }

# template
{% render '...:twitterFeeds' with {}, {'standalone': true} %}

# fragment controller
$response->setSharedMaxAge(15);
ESI and Symfony2

# controller
$response->setSharedMaxAge(3600);

# app/config/config.yml
framework:
  esi: { enabled: true }

# template
{% render '...:twitterFeeds' with {}, {'standalone': true} %}

# fragment controller
$response->setSharedMaxAge(15);
Use Symfony2 reverse proxy
Use Symfony2 reverse proxy
         (slower)
or Varnish
http://www.varnish-cache.org/
Varnish configuration

backend apache {
    .host = "127.0.0.1";
    .port = "8080";
}

sub vcl_recv {
  unset req.http.Accept-Encoding;
  unset req.http.Vary;
  set req.http.Surrogate-Capability = "abc=ESI/1.0";
}

sub vcl_fetch {
  esi;

  ...
Varnish configuration

backend apache {
    .host = "127.0.0.1";
       tell Symfony2
    .port = "8080";     you're behind a reverse proxy
}
              able to handle the ESI specification
sub vcl_recv {
  unset req.http.Accept-Encoding;
  unset req.http.Vary;
  set req.http.Surrogate-Capability = "abc=ESI/1.0";
}

sub vcl_fetch {
  esi;

    ...
}
Why HTTP caching
      is so
   important?
Ask yourself:
as a developer, what do I want
      on my application?
Evolve



Loose coupling




    Work less
Evolve

Because you want your platform to extensible

                                               Loose coupling




                                                   Work less
Evolve

Because you want your platform to extensible

                                                Loose coupling

Because you want it to be easy to integrate with, evolve, plug
and mantain

                                                      Work less
Evolve

Because you want your platform to extensible

                                                Loose coupling

Because you want it to be easy to integrate with, evolve, plug
and mantain

                                                      Work less

Because every LoC is bug-prone and our man-day is a hard-to-
scale cost
enters our Hero #1
enters our Hero #2
http://www.lullabot.com/articles/a-beginners-guide-to-caching-data
2007
2011?
it supports
HTTP caching!
  http://drupal.org/node/147310
it supports
HTTP caching!
   http://drupal.org/node/147310
 ( people is supposed to clap their hands here )
but
wait.... how?
Default headers
Expires = 'Sun, 19 Nov 1978 05:00:00 GMT',

Cache-Control = 'no-cache, must-revalidate',

ETag = $_SERVER['REQUEST_TIME'],
Default headers
Expires = 'Sun, 19 Nov 1978 05:00:00 GMT',

Cache-Control = 'no-cache, must-revalidate',

ETag = $_SERVER['REQUEST_TIME'],
Default headers
Expires = 'Sun, 19 Nov 1978 05:00:00 GMT',

Cache-Control = 'no-cache, must-revalidate',

ETag = $_SERVER['REQUEST_TIME'],
Default headers
Expires = 'Sun, 19 Nov 1978 05:00:00 GMT',

Cache-Control = 'no-cache, must-revalidate',

ETag = $_SERVER['REQUEST_TIME'],
is that even legal?
"but you can redefine them!"
drupal_add_http_header()
function drupal_add_http_header()
{
  ...


    ...

    drupal_send_headers($headers);
}
so, what

drupal_send_headers()

    can do so evil?
header()       ,

   of course
which means
drupal_add_http_header('Dumb-Header', 'I'm batman!');
...
// other logic
...
drupal_add_http_header('Dumb-Header', 'I'm not');

var_dump(headers_list());
drupal_add_http_header('Dumb-Header', 'I'm batman!');
...
// other logic
...
drupal_add_http_header('Dumb-Header', 'I'm not');

var_dump(headers_list());

array
 0 => string 'X-Powered-By: PHP/5.3.2-1ubuntu4.7'
 1 => string 'Cache: I'm not'
drupal_add_http_header('Dumb-Header', 'I-m batman!');
...
// other logic
...
drupal_add_http_header('Dumb-Header', false);

var_dump(headers_list());
drupal_add_http_header('Dumb-Header', 'I-m batman!');
...
// other logic
...
drupal_add_http_header('Dumb-Header', false);

var_dump(headers_list());

array
 0 => string 'X-Powered-By: PHP/5.3.2-1ubuntu4.7'
 1 => string 'Cache: I'm batman'
drupal_add_http_header('Dumb-Header', 'I-m batman!');
...
// other logic
...
drupal_add_http_header('Dumb-Header', ' ');

var_dump(headers_list());
drupal_add_http_header('Dumb-Header', 'I-m batman!');
...
// other logic
...
drupal_add_http_header('Dumb-Header', ' ');

var_dump(headers_list());

array
 0 => string 'X-Powered-By: PHP/5.3.2-1ubuntu4.7'
 1 => string 'Cache:'
or
you can use header_remove()
           ( PHP 5.3 )
and create a new class to
   manage/keep track of
headers and caching directives
but we're lazy

               and

we don't want to reinvent the wheel
Goals
Work less
                             evolve
            loose coupling
Goals
Work less
                             evolve
            loose coupling
everything is done for us!

            :)



          but....
tmp files, cache tables, procedural code...

               mmmmh....

        gotta be something better
Frameworks
symfony ONE
Cache is used for compiling routes, autoloading, ...
Cache is used for compiling routes, autoloading, ...




   ...but also for storing the view
Goals
Work less
                             evolve
            loose coupling
Goals
Work less
                             evolve
            loose coupling
at least because we use a framework
HTTP
Goals
Work less
                             evolve
            loose coupling
Less work
because the hard work is delegated to the browser/proxy
Evolve
because cache is abstracted from the application
Loose coupling
because caching is bound to the protocol, HTTP, not
to your implementation ( Sf, RoR, Django )
Alessandro Nadalin
Alessandro Nadalin
Alessandro Nadalin

    odino.org
Alessandro Nadalin

    odino.org
    @_odino_
Alessandro Nadalin

    odino.org
    @_odino_
    http://joind.in/talk/view/2988
Alessandro Nadalin

    odino.org
    @_odino_
    http://joind.in/talk/view/2988




                Thanks!
Credits
http://www.flickr.com/photos/snakphotography/5004775320/sizes/o/in/photostream/
  http://www.flickr.com/photos/ashatenbroeke/4367373081/sizes/z/in/photostream/
      http://www.flickr.com/photos/juanpg/3333385784/sizes/z/in/photostream/
       http://www.flickr.com/photos/congvo/301678287/sizes/l/in/photostream/
     http://www.flickr.com/photos/adamrice/280300202/sizes/l/in/photostream/
      http://www.flickr.com/photos/tomer_a/541411897/sizes/o/in/photostream/
      http://www.flickr.com/photos/subpra/4514008262/sizes/l/in/photostream/
    http://www.flickr.com/photos/lippincott/2539720043/sizes/l/in/photostream/
     http://www.flickr.com/photos/rawryder/5086090931/sizes/l/in/photostream/
    http://www.flickr.com/photos/robboudon/5312731161/sizes/l/in/photostream/
 http://www.flickr.com/photos/bc-burnslibrary/4158243488/sizes/o/in/photostream/
http://www.flickr.com/photos/13606325@N08/2416993706/sizes/o/in/photostream/
    http://www.flickr.com/photos/neothezion/5135841069/sizes/l/in/photostream/
               http://www.flickr.com/photos/planetschwa/2494067809/
               http://www.flickr.com/photos/thomasthomas/258931782/
     http://www.flickr.com/photos/jungle_boy/220181177/sizes/l/in/photostream/
     http://www.flickr.com/photos/ramduk/3708039504/sizes/z/in/photostream/
    http://www.flickr.com/photos/sashawolff/3228711025/sizes/l/in/photostream/

More Related Content

What's hot

Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICKonstantin Kudryashov
 
Introduction to CQRS and Event Sourcing
Introduction to CQRS and Event SourcingIntroduction to CQRS and Event Sourcing
Introduction to CQRS and Event SourcingSamuel ROZE
 
Symfony CoP: Form component
Symfony CoP: Form componentSymfony CoP: Form component
Symfony CoP: Form componentSamuel ROZE
 
Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsSam Hennessy
 
Everything About PowerShell
Everything About PowerShellEverything About PowerShell
Everything About PowerShellGaetano Causio
 
Things I Believe Now That I'm Old
Things I Believe Now That I'm OldThings I Believe Now That I'm Old
Things I Believe Now That I'm OldRoss Tuck
 
Decoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDDecoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDAleix Vergés
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of LithiumNate Abele
 
Introduction to Zend Framework web services
Introduction to Zend Framework web servicesIntroduction to Zend Framework web services
Introduction to Zend Framework web servicesMichelangelo van Dam
 
MTDDC 2010.2.5 Tokyo - Brand new API
MTDDC 2010.2.5 Tokyo - Brand new APIMTDDC 2010.2.5 Tokyo - Brand new API
MTDDC 2010.2.5 Tokyo - Brand new APISix Apart KK
 
WordPress as an application framework
WordPress as an application frameworkWordPress as an application framework
WordPress as an application frameworkDustin Filippini
 
PHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkPHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkG Woo
 
jQuery and Rails, Sitting in a Tree
jQuery and Rails, Sitting in a TreejQuery and Rails, Sitting in a Tree
jQuery and Rails, Sitting in a Treeadamlogic
 
Hacking Your Way To Better Security - Dutch PHP Conference 2016
Hacking Your Way To Better Security - Dutch PHP Conference 2016Hacking Your Way To Better Security - Dutch PHP Conference 2016
Hacking Your Way To Better Security - Dutch PHP Conference 2016Colin O'Dell
 
Introduction à CoffeeScript pour ParisRB
Introduction à CoffeeScript pour ParisRB Introduction à CoffeeScript pour ParisRB
Introduction à CoffeeScript pour ParisRB jhchabran
 
Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015Konstantin Kudryashov
 

What's hot (20)

Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DIC
 
Introduction to CQRS and Event Sourcing
Introduction to CQRS and Event SourcingIntroduction to CQRS and Event Sourcing
Introduction to CQRS and Event Sourcing
 
Symfony CoP: Form component
Symfony CoP: Form componentSymfony CoP: Form component
Symfony CoP: Form component
 
Bacbkone js
Bacbkone jsBacbkone js
Bacbkone js
 
Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy Applications
 
Everything About PowerShell
Everything About PowerShellEverything About PowerShell
Everything About PowerShell
 
Things I Believe Now That I'm Old
Things I Believe Now That I'm OldThings I Believe Now That I'm Old
Things I Believe Now That I'm Old
 
Decoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDDecoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDD
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of Lithium
 
Introduction to Zend Framework web services
Introduction to Zend Framework web servicesIntroduction to Zend Framework web services
Introduction to Zend Framework web services
 
MTDDC 2010.2.5 Tokyo - Brand new API
MTDDC 2010.2.5 Tokyo - Brand new APIMTDDC 2010.2.5 Tokyo - Brand new API
MTDDC 2010.2.5 Tokyo - Brand new API
 
BEAR DI
BEAR DIBEAR DI
BEAR DI
 
WordPress as an application framework
WordPress as an application frameworkWordPress as an application framework
WordPress as an application framework
 
PHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkPHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php framework
 
Mocking Demystified
Mocking DemystifiedMocking Demystified
Mocking Demystified
 
Daily notes
Daily notesDaily notes
Daily notes
 
jQuery and Rails, Sitting in a Tree
jQuery and Rails, Sitting in a TreejQuery and Rails, Sitting in a Tree
jQuery and Rails, Sitting in a Tree
 
Hacking Your Way To Better Security - Dutch PHP Conference 2016
Hacking Your Way To Better Security - Dutch PHP Conference 2016Hacking Your Way To Better Security - Dutch PHP Conference 2016
Hacking Your Way To Better Security - Dutch PHP Conference 2016
 
Introduction à CoffeeScript pour ParisRB
Introduction à CoffeeScript pour ParisRB Introduction à CoffeeScript pour ParisRB
Introduction à CoffeeScript pour ParisRB
 
Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015
 

Similar to Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011

Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Leonardo Proietti
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & RESTHugo Hamon
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutesBarang CK
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosDivante
 
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needDutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needKacper Gunia
 
Propel sfugmd
Propel sfugmdPropel sfugmd
Propel sfugmdiKlaus
 
PHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4DevelopersPHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4DevelopersKacper Gunia
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency InjectionRifat Nabi
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in actionJace Ju
 
HirshHorn theme: how I created it
HirshHorn theme: how I created itHirshHorn theme: how I created it
HirshHorn theme: how I created itPaul Bearne
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologyDaniel Knell
 
Your code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConYour code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConRafael Dohms
 
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowForget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowKacper Gunia
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
 
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011camp_drupal_ua
 

Similar to Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011 (20)

Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutes
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenarios
 
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needDutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
 
Propel sfugmd
Propel sfugmdPropel sfugmd
Propel sfugmd
 
PHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4DevelopersPHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4Developers
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
 
HirshHorn theme: how I created it
HirshHorn theme: how I created itHirshHorn theme: how I created it
HirshHorn theme: how I created it
 
Lithium Best
Lithium Best Lithium Best
Lithium Best
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technology
 
Oops in php
Oops in phpOops in php
Oops in php
 
Hooks WCSD12
Hooks WCSD12Hooks WCSD12
Hooks WCSD12
 
Your code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConYour code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnCon
 
Presentation1
Presentation1Presentation1
Presentation1
 
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowForget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers Cracow
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
XQuery Rocks
XQuery RocksXQuery Rocks
XQuery Rocks
 
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011
 

More from Alessandro Nadalin

Spa, isomorphic and back to the server our journey with js @ frontend con po...
Spa, isomorphic and back to the server  our journey with js @ frontend con po...Spa, isomorphic and back to the server  our journey with js @ frontend con po...
Spa, isomorphic and back to the server our journey with js @ frontend con po...Alessandro Nadalin
 
SPA, isomorphic and back to the server: our journey with JavaScript @ JsDay 2...
SPA, isomorphic and back to the server: our journey with JavaScript @ JsDay 2...SPA, isomorphic and back to the server: our journey with JavaScript @ JsDay 2...
SPA, isomorphic and back to the server: our journey with JavaScript @ JsDay 2...Alessandro Nadalin
 
Scaling at Namshi @ Seamless Ecommerce Dubai 2017
Scaling at Namshi @ Seamless Ecommerce Dubai 2017Scaling at Namshi @ Seamless Ecommerce Dubai 2017
Scaling at Namshi @ Seamless Ecommerce Dubai 2017Alessandro Nadalin
 
Accelerated Mobile Pages @ Dubytes meetup Dec 2016 in Dubai
Accelerated Mobile Pages @ Dubytes meetup Dec 2016 in DubaiAccelerated Mobile Pages @ Dubytes meetup Dec 2016 in Dubai
Accelerated Mobile Pages @ Dubytes meetup Dec 2016 in DubaiAlessandro Nadalin
 
A tech team of ~10 @ Rocket Tech Summit 2016 in Berlin
A tech team of ~10 @ Rocket Tech Summit 2016 in BerlinA tech team of ~10 @ Rocket Tech Summit 2016 in Berlin
A tech team of ~10 @ Rocket Tech Summit 2016 in BerlinAlessandro Nadalin
 
React native in the wild @ Codemotion 2016 in Rome
React native in the wild @ Codemotion 2016 in RomeReact native in the wild @ Codemotion 2016 in Rome
React native in the wild @ Codemotion 2016 in RomeAlessandro Nadalin
 
Dockerize it! @ Codemotion 2016 in Rome
Dockerize it! @ Codemotion 2016 in RomeDockerize it! @ Codemotion 2016 in Rome
Dockerize it! @ Codemotion 2016 in RomeAlessandro Nadalin
 
Deploying 3 times a day without a downtime @ Rocket Tech Summit in Berlin
Deploying 3 times a day without a downtime @ Rocket Tech Summit in BerlinDeploying 3 times a day without a downtime @ Rocket Tech Summit in Berlin
Deploying 3 times a day without a downtime @ Rocket Tech Summit in BerlinAlessandro Nadalin
 
Hey, I just met AngularJS, and this is crazy, so here’s my JavaScript, let’s ...
Hey, I just met AngularJS, and this is crazy, so here’s my JavaScript, let’s ...Hey, I just met AngularJS, and this is crazy, so here’s my JavaScript, let’s ...
Hey, I just met AngularJS, and this is crazy, so here’s my JavaScript, let’s ...Alessandro Nadalin
 
Don't screw it up: how to build durable web apis @ PHPDay 2014 in Verona (ITA)
Don't screw it up: how to build durable web apis @ PHPDay 2014 in Verona (ITA)Don't screw it up: how to build durable web apis @ PHPDay 2014 in Verona (ITA)
Don't screw it up: how to build durable web apis @ PHPDay 2014 in Verona (ITA)Alessandro Nadalin
 
Angular js is the future. maybe. @ ConFoo 2014 in Montreal (CA)
Angular js is the future. maybe. @ ConFoo 2014 in Montreal (CA)Angular js is the future. maybe. @ ConFoo 2014 in Montreal (CA)
Angular js is the future. maybe. @ ConFoo 2014 in Montreal (CA)Alessandro Nadalin
 
OrientDB, the fastest document-based graph database @ Confoo 2014 in Montreal...
OrientDB, the fastest document-based graph database @ Confoo 2014 in Montreal...OrientDB, the fastest document-based graph database @ Confoo 2014 in Montreal...
OrientDB, the fastest document-based graph database @ Confoo 2014 in Montreal...Alessandro Nadalin
 
A Rocket Internet experience @ ForumPHP Paris 2013
A Rocket Internet experience @ ForumPHP Paris 2013A Rocket Internet experience @ ForumPHP Paris 2013
A Rocket Internet experience @ ForumPHP Paris 2013Alessandro Nadalin
 
HTTP colon slash slash: end of the road? @ CakeFest 2013 in San Francisco
HTTP colon slash slash: end of the road? @ CakeFest 2013 in San FranciscoHTTP colon slash slash: end of the road? @ CakeFest 2013 in San Francisco
HTTP colon slash slash: end of the road? @ CakeFest 2013 in San FranciscoAlessandro Nadalin
 
Tips and Tricks for your Service Oriented Architecture @ CakeFest 2013 in San...
Tips and Tricks for your Service Oriented Architecture @ CakeFest 2013 in San...Tips and Tricks for your Service Oriented Architecture @ CakeFest 2013 in San...
Tips and Tricks for your Service Oriented Architecture @ CakeFest 2013 in San...Alessandro Nadalin
 
The rocket internet experience @ PHP.TO.START 2013 in Turin
The rocket internet experience @ PHP.TO.START 2013 in TurinThe rocket internet experience @ PHP.TO.START 2013 in Turin
The rocket internet experience @ PHP.TO.START 2013 in TurinAlessandro Nadalin
 
GraphDB in PHP @ Codemotion 03/23/2012
GraphDB in PHP @ Codemotion 03/23/2012GraphDB in PHP @ Codemotion 03/23/2012
GraphDB in PHP @ Codemotion 03/23/2012Alessandro Nadalin
 
REST in peace @ IPC 2012 in Mainz
REST in peace @ IPC 2012 in MainzREST in peace @ IPC 2012 in Mainz
REST in peace @ IPC 2012 in MainzAlessandro Nadalin
 
HTTP colon slash slash: the end of the road?
HTTP colon slash slash: the end of the road?HTTP colon slash slash: the end of the road?
HTTP colon slash slash: the end of the road?Alessandro Nadalin
 

More from Alessandro Nadalin (20)

Spa, isomorphic and back to the server our journey with js @ frontend con po...
Spa, isomorphic and back to the server  our journey with js @ frontend con po...Spa, isomorphic and back to the server  our journey with js @ frontend con po...
Spa, isomorphic and back to the server our journey with js @ frontend con po...
 
SPA, isomorphic and back to the server: our journey with JavaScript @ JsDay 2...
SPA, isomorphic and back to the server: our journey with JavaScript @ JsDay 2...SPA, isomorphic and back to the server: our journey with JavaScript @ JsDay 2...
SPA, isomorphic and back to the server: our journey with JavaScript @ JsDay 2...
 
Scaling at Namshi @ Seamless Ecommerce Dubai 2017
Scaling at Namshi @ Seamless Ecommerce Dubai 2017Scaling at Namshi @ Seamless Ecommerce Dubai 2017
Scaling at Namshi @ Seamless Ecommerce Dubai 2017
 
Accelerated Mobile Pages @ Dubytes meetup Dec 2016 in Dubai
Accelerated Mobile Pages @ Dubytes meetup Dec 2016 in DubaiAccelerated Mobile Pages @ Dubytes meetup Dec 2016 in Dubai
Accelerated Mobile Pages @ Dubytes meetup Dec 2016 in Dubai
 
A tech team of ~10 @ Rocket Tech Summit 2016 in Berlin
A tech team of ~10 @ Rocket Tech Summit 2016 in BerlinA tech team of ~10 @ Rocket Tech Summit 2016 in Berlin
A tech team of ~10 @ Rocket Tech Summit 2016 in Berlin
 
React native in the wild @ Codemotion 2016 in Rome
React native in the wild @ Codemotion 2016 in RomeReact native in the wild @ Codemotion 2016 in Rome
React native in the wild @ Codemotion 2016 in Rome
 
Dockerize it! @ Codemotion 2016 in Rome
Dockerize it! @ Codemotion 2016 in RomeDockerize it! @ Codemotion 2016 in Rome
Dockerize it! @ Codemotion 2016 in Rome
 
Deploying 3 times a day without a downtime @ Rocket Tech Summit in Berlin
Deploying 3 times a day without a downtime @ Rocket Tech Summit in BerlinDeploying 3 times a day without a downtime @ Rocket Tech Summit in Berlin
Deploying 3 times a day without a downtime @ Rocket Tech Summit in Berlin
 
Hey, I just met AngularJS, and this is crazy, so here’s my JavaScript, let’s ...
Hey, I just met AngularJS, and this is crazy, so here’s my JavaScript, let’s ...Hey, I just met AngularJS, and this is crazy, so here’s my JavaScript, let’s ...
Hey, I just met AngularJS, and this is crazy, so here’s my JavaScript, let’s ...
 
Don't screw it up: how to build durable web apis @ PHPDay 2014 in Verona (ITA)
Don't screw it up: how to build durable web apis @ PHPDay 2014 in Verona (ITA)Don't screw it up: how to build durable web apis @ PHPDay 2014 in Verona (ITA)
Don't screw it up: how to build durable web apis @ PHPDay 2014 in Verona (ITA)
 
Namshi in 2014: let's rock!
Namshi in 2014: let's rock!Namshi in 2014: let's rock!
Namshi in 2014: let's rock!
 
Angular js is the future. maybe. @ ConFoo 2014 in Montreal (CA)
Angular js is the future. maybe. @ ConFoo 2014 in Montreal (CA)Angular js is the future. maybe. @ ConFoo 2014 in Montreal (CA)
Angular js is the future. maybe. @ ConFoo 2014 in Montreal (CA)
 
OrientDB, the fastest document-based graph database @ Confoo 2014 in Montreal...
OrientDB, the fastest document-based graph database @ Confoo 2014 in Montreal...OrientDB, the fastest document-based graph database @ Confoo 2014 in Montreal...
OrientDB, the fastest document-based graph database @ Confoo 2014 in Montreal...
 
A Rocket Internet experience @ ForumPHP Paris 2013
A Rocket Internet experience @ ForumPHP Paris 2013A Rocket Internet experience @ ForumPHP Paris 2013
A Rocket Internet experience @ ForumPHP Paris 2013
 
HTTP colon slash slash: end of the road? @ CakeFest 2013 in San Francisco
HTTP colon slash slash: end of the road? @ CakeFest 2013 in San FranciscoHTTP colon slash slash: end of the road? @ CakeFest 2013 in San Francisco
HTTP colon slash slash: end of the road? @ CakeFest 2013 in San Francisco
 
Tips and Tricks for your Service Oriented Architecture @ CakeFest 2013 in San...
Tips and Tricks for your Service Oriented Architecture @ CakeFest 2013 in San...Tips and Tricks for your Service Oriented Architecture @ CakeFest 2013 in San...
Tips and Tricks for your Service Oriented Architecture @ CakeFest 2013 in San...
 
The rocket internet experience @ PHP.TO.START 2013 in Turin
The rocket internet experience @ PHP.TO.START 2013 in TurinThe rocket internet experience @ PHP.TO.START 2013 in Turin
The rocket internet experience @ PHP.TO.START 2013 in Turin
 
GraphDB in PHP @ Codemotion 03/23/2012
GraphDB in PHP @ Codemotion 03/23/2012GraphDB in PHP @ Codemotion 03/23/2012
GraphDB in PHP @ Codemotion 03/23/2012
 
REST in peace @ IPC 2012 in Mainz
REST in peace @ IPC 2012 in MainzREST in peace @ IPC 2012 in Mainz
REST in peace @ IPC 2012 in Mainz
 
HTTP colon slash slash: the end of the road?
HTTP colon slash slash: the end of the road?HTTP colon slash slash: the end of the road?
HTTP colon slash slash: the end of the road?
 

Recently uploaded

"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demoHarshalMandlekar2
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESmohitsingh558521
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
What is Artificial Intelligence?????????
What is Artificial Intelligence?????????What is Artificial Intelligence?????????
What is Artificial Intelligence?????????blackmambaettijean
 
Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rick Flair
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 

Recently uploaded (20)

"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demo
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
What is Artificial Intelligence?????????
What is Artificial Intelligence?????????What is Artificial Intelligence?????????
What is Artificial Intelligence?????????
 
Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 

Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011

  • 1. HTTP caching and Symfony2 Be lazy, be ESI Alessandro Nadalin May, 13 2011
  • 2. Symfony2 sucks at caching
  • 3. because it doesn't have an application caching layer
  • 5. Sf2 embraces the HTTP caching specification and that's not because
  • 6. Fabien is lazy
  • 9. HTTP cache is a King in Symfony2
  • 11. Caching is, obviously, a matter of the response
  • 12. since the response is an object, we have some basic OO stuff to handle HTTP cache
  • 13. Creating a response public function indexAction() { $res = $this->render('MyBundle:Default:home.html.twig', array( 'title' => 'My blog', )); return $res; }
  • 14. Creating a response public function indexAction() { $res = $this->render('MyBundle:Default:home.html.twig', array( 'title' => 'My blog', )); return $res; }
  • 15. Creating a response public function indexAction() { $res = $this->render('MyBundle:Default:home.html.twig', array( 'title' => 'My blog', )); return $res; }
  • 16. Creating a response public function indexAction() { $res = $this->render('MyBundle:Default:home.html.twig', array( 'title' => 'My blog', )); return $res; }
  • 17. Creating a response public function indexAction() { $res = $this->render('MyBundle:Default:home.html.twig', array( 'title' => 'My blog', )); return $res; }
  • 18. Creating a response public function indexAction() { $res = $this->render('MyBundle:Default:home.html.twig', array( 'title' => 'My blog', )); return $res; }
  • 20. Expiration public function indexAction() { $res = $this->render('MyBundle:Default:home.html.twig', array( 'title' => 'My blog', )); $date = new DateTime(); $date->modify('+600 seconds'); $res->setExpires($date); return $res; }
  • 21. Expiration public function indexAction() { $res = $this->render('MyBundle:Default:home.html.twig', array( 'title' => 'My blog', )); $date = new DateTime(); $date->modify('+600 seconds'); $res->setExpires($date); return $res; }
  • 22. Expiration public function indexAction() { $res = $this->render('MyBundle:Default:home.html.twig', array( 'title' => 'My blog', )); $date = new DateTime(); $date->modify('+600 seconds'); $res->setExpires($date); return $res; }
  • 23. Expiration through Cache-Control public function indexAction() { $res = $this->render('MyBundle:Default:home.html.twig', array( 'title' => 'My blog', )); $res->setMaxAge(600); $res->setSharedMaxAge(600); return $res; }
  • 24. Expiration through Cache-Control public function indexAction() { $res = $this->render('MyBundle:Default:home.html.twig', array( 'title' => 'My blog', )); $res->setMaxAge(600); $res->setSharedMaxAge(600); return $res; }
  • 25. Expiration through Cache-Control public function indexAction() { $res = $this->render('MyBundle:Default:home.html.twig', array( 'title' => 'My blog', )); $res->setMaxAge(600); $res->setSharedMaxAge(600); return $res; }
  • 26. Expiration through Cache-Control public function indexAction() { $res = $this->render('MyBundle:Default:home.html.twig', array( 'title' => 'My blog', )); $res->setMaxAge(600); $res->setSharedMaxAge(600); return $res; } Shared caches, like Symfony2 reverse proxy
  • 28. Validation public function articleAction($id) { $article = $this->get('entity_manager')->query($id)... $res = $this->render('MyBundle:Default:article.html.twig', array( 'article' => '$article', )); $etag = "article:{$article->getId()}:{$article->getVersion()}"; $res->setETag($etag); $res->setLastModified($article->getModifiedAt()); return $res;
  • 29. Validation public function articleAction($id) { $article = $this->get('entity_manager')->query($id)... $res = $this->render('MyBundle:Default:article.html.twig', array( 'article' => '$article', )); $etag = "article:{$article->getId()}:{$article->getVersion()}"; $res->setETag($etag); $res->setLastModified($article->getModifiedAt()); return $res;
  • 30. Validation public function articleAction($id) { $article = $this->get('entity_manager')->query($id)... $res = $this->render('MyBundle:Default:article.html.twig', array( 'article' => '$article', )); $etag = "article:{$article->getId()}:{$article->getVersion()}"; $res->setETag($etag); $res->setLastModified($article->getModifiedAt()); return $res;
  • 31. Validation public function articleAction($id) { $article = $this->get('entity_manager')->query($id)... $res = $this->render('MyBundle:Default:article.html.twig', array( 'article' => '$article', )); $etag = "article:{$article->getId()}:{$article->getVersion()}"; $res->setETag($etag); $res->setLastModified($article->getModifiedAt()); return $res;
  • 32. Validation public function articleAction($id) { $article = $this->get('entity_manager')->query($id)... $res = $this->render('MyBundle:Default:article.html.twig', array( 'article' => '$article', )); $etag = "article:{$article->getId()}:{$article->getVersion()}"; Datetime object $res->setETag($etag); $res->setLastModified($article->getModifiedAt()); return $res;
  • 33. Automagically get a Datetime from Doctrine2 namespace AcmeBlogBundleEntity; /** * @orm:Entity * @orm:Table(name="article") */ class Article { /** * @orm:Column(type="datetime", name="modified_at") */ protected $modifiedAt;
  • 34. Automagically get a Datetime from Doctrine2 namespace AcmeBlogBundleEntity; /** * @orm:Entity * @orm:Table(name="article") */ class Article { /** * @orm:Column(type="datetime", name="modified_at") */ protected $modifiedAt;
  • 36. what's the advatage of using validation if we always hit the DB and create a new Response?
  • 37. Validation, the right way public function articleAction($id) { $res = new Response() $etag = Memcache::get("Article:{$id}:etag"); $lastModified = Memcache::get("Article:{$id}:last_modified"); $res->setETag($etag); $res->setLastModified($lastModified); if ($res->isNotModified($this->get('request'))) { return $res; } $article = $this->get('entity_manager')->query($id)... ...
  • 38. Validation, the right way public function articleAction($id) { $res = new Response() $etag = Memcache::get("Article:{$id}:etag"); $lastModified = Memcache::get("Article:{$id}:last_modified"); $res->setETag($etag); $res->setLastModified($lastModified); if ($res->isNotModified($this->get('request'))) { return $res; } $article = $this->get('entity_manager')->query($id)... ...
  • 39. Validation, the right way public function articleAction($id) { $res = new Response() $etag = Memcache::get("Article:{$id}:etag"); $lastModified = Memcache::get("Article:{$id}:last_modified"); $res->setETag($etag); $res->setLastModified($lastModified); if ($res->isNotModified($this->get('request'))) { return $res; } $article = $this->get('entity_manager')->query($id)... ...
  • 40. Validation, the right way public function articleAction($id) { $res = new Response() $etag = Memcache::get("Article:{$id}:etag"); $lastModified = Memcache::get("Article:{$id}:last_modified"); $res->setETag($etag); $res->setLastModified($lastModified); if ($res->isNotModified($this->get('request'))) { return $res; } $article = $this->get('entity_manager')->query($id)... ...
  • 41. relax
  • 42. Calculating an Etag, or a date, is cheaper than generating a full MVC response
  • 44. Additional management public function articleAction($id) { $res = new Response() $res->setVary(array( 'Accept-Encoding', )); $res->setPublic(); $res->setNotModified(); ...
  • 45. Varying the response public function articleAction($id) { $res = new Response() $res->setVary(array( 'Accept-Encoding', )); $res->setPublic(); $res->setNotModified(); ...
  • 46. Cacheable by all caches public function articleAction($id) { $res = new Response() $res->setVary(array( 'Accept-Encoding', )); $res->setPublic(); $res->setNotModified(); ...
  • 47. or by local only public function articleAction($id) { $res = new Response() $res->setVary(array( 'Accept-Encoding', )); $res->setPrivate(); $res->setNotModified(); ...
  • 48. Good old 304 public function articleAction($id) { $res = new Response() $res->setVary(array( 'Accept-Encoding', )); $res->setPrivate(); $res->setNotModified(); ...
  • 49. Stale public function articleAction($id) { $res = new Response() $res->setVary(array( 'Accept-Encoding', )); $res->setPrivate(); $res->expire(); ...
  • 51. HTTP's cache fails when dealing with really dynamic pages, because consumers will always have to hit the origin server, although a part of the page would be cacheable ( header and footer, for example )
  • 53. NOPE
  • 54. ESI was built for that http://www.w3.org/TR/esi-lang <esi:include src="http://mysite.com/twitterfeeds.html" />
  • 55. ESI and Symfony2 # controller $response->setSharedMaxAge(3600); # app/config/config.yml framework: esi: { enabled: true } # template {% render '...:twitterFeeds' with {}, {'standalone': true} %} # fragment controller $response->setSharedMaxAge(15);
  • 56. ESI and Symfony2 # controller $response->setSharedMaxAge(3600); # app/config/config.yml framework: esi: { enabled: true } # template {% render '...:twitterFeeds' with {}, {'standalone': true} %} # fragment controller $response->setSharedMaxAge(15);
  • 57. ESI and Symfony2 # controller $response->setSharedMaxAge(3600); # app/config/config.yml framework: esi: { enabled: true } # template {% render '...:twitterFeeds' with {}, {'standalone': true} %} # fragment controller $response->setSharedMaxAge(15);
  • 58. ESI and Symfony2 # controller $response->setSharedMaxAge(3600); # app/config/config.yml framework: esi: { enabled: true } # template {% render '...:twitterFeeds' with {}, {'standalone': true} %} # fragment controller $response->setSharedMaxAge(15);
  • 59. ESI and Symfony2 # controller $response->setSharedMaxAge(3600); # app/config/config.yml framework: esi: { enabled: true } # template {% render '...:twitterFeeds' with {}, {'standalone': true} %} # fragment controller $response->setSharedMaxAge(15);
  • 61. Use Symfony2 reverse proxy (slower)
  • 63. Varnish configuration backend apache { .host = "127.0.0.1"; .port = "8080"; } sub vcl_recv { unset req.http.Accept-Encoding; unset req.http.Vary; set req.http.Surrogate-Capability = "abc=ESI/1.0"; } sub vcl_fetch { esi; ...
  • 64. Varnish configuration backend apache { .host = "127.0.0.1"; tell Symfony2 .port = "8080"; you're behind a reverse proxy } able to handle the ESI specification sub vcl_recv { unset req.http.Accept-Encoding; unset req.http.Vary; set req.http.Surrogate-Capability = "abc=ESI/1.0"; } sub vcl_fetch { esi; ... }
  • 65. Why HTTP caching is so important?
  • 66. Ask yourself: as a developer, what do I want on my application?
  • 68. Evolve Because you want your platform to extensible Loose coupling Work less
  • 69. Evolve Because you want your platform to extensible Loose coupling Because you want it to be easy to integrate with, evolve, plug and mantain Work less
  • 70. Evolve Because you want your platform to extensible Loose coupling Because you want it to be easy to integrate with, evolve, plug and mantain Work less Because every LoC is bug-prone and our man-day is a hard-to- scale cost
  • 72.
  • 73.
  • 75.
  • 77. 2007
  • 78. 2011?
  • 79. it supports HTTP caching! http://drupal.org/node/147310
  • 80. it supports HTTP caching! http://drupal.org/node/147310 ( people is supposed to clap their hands here )
  • 81. but
  • 83. Default headers Expires = 'Sun, 19 Nov 1978 05:00:00 GMT', Cache-Control = 'no-cache, must-revalidate', ETag = $_SERVER['REQUEST_TIME'],
  • 84. Default headers Expires = 'Sun, 19 Nov 1978 05:00:00 GMT', Cache-Control = 'no-cache, must-revalidate', ETag = $_SERVER['REQUEST_TIME'],
  • 85. Default headers Expires = 'Sun, 19 Nov 1978 05:00:00 GMT', Cache-Control = 'no-cache, must-revalidate', ETag = $_SERVER['REQUEST_TIME'],
  • 86. Default headers Expires = 'Sun, 19 Nov 1978 05:00:00 GMT', Cache-Control = 'no-cache, must-revalidate', ETag = $_SERVER['REQUEST_TIME'],
  • 87. is that even legal?
  • 88. "but you can redefine them!"
  • 90. function drupal_add_http_header() { ... ... drupal_send_headers($headers); }
  • 92. header() , of course
  • 94. drupal_add_http_header('Dumb-Header', 'I'm batman!'); ... // other logic ... drupal_add_http_header('Dumb-Header', 'I'm not'); var_dump(headers_list());
  • 95. drupal_add_http_header('Dumb-Header', 'I'm batman!'); ... // other logic ... drupal_add_http_header('Dumb-Header', 'I'm not'); var_dump(headers_list()); array 0 => string 'X-Powered-By: PHP/5.3.2-1ubuntu4.7' 1 => string 'Cache: I'm not'
  • 96. drupal_add_http_header('Dumb-Header', 'I-m batman!'); ... // other logic ... drupal_add_http_header('Dumb-Header', false); var_dump(headers_list());
  • 97. drupal_add_http_header('Dumb-Header', 'I-m batman!'); ... // other logic ... drupal_add_http_header('Dumb-Header', false); var_dump(headers_list()); array 0 => string 'X-Powered-By: PHP/5.3.2-1ubuntu4.7' 1 => string 'Cache: I'm batman'
  • 98. drupal_add_http_header('Dumb-Header', 'I-m batman!'); ... // other logic ... drupal_add_http_header('Dumb-Header', ' '); var_dump(headers_list());
  • 99. drupal_add_http_header('Dumb-Header', 'I-m batman!'); ... // other logic ... drupal_add_http_header('Dumb-Header', ' '); var_dump(headers_list()); array 0 => string 'X-Powered-By: PHP/5.3.2-1ubuntu4.7' 1 => string 'Cache:'
  • 100. or
  • 101. you can use header_remove() ( PHP 5.3 )
  • 102. and create a new class to manage/keep track of headers and caching directives
  • 103. but we're lazy and we don't want to reinvent the wheel
  • 104. Goals Work less evolve loose coupling
  • 105. Goals Work less evolve loose coupling
  • 106. everything is done for us! :) but....
  • 107. tmp files, cache tables, procedural code... mmmmh.... gotta be something better
  • 109.
  • 111. Cache is used for compiling routes, autoloading, ...
  • 112. Cache is used for compiling routes, autoloading, ... ...but also for storing the view
  • 113. Goals Work less evolve loose coupling
  • 114. Goals Work less evolve loose coupling
  • 115. at least because we use a framework
  • 116. HTTP
  • 117. Goals Work less evolve loose coupling
  • 119. because the hard work is delegated to the browser/proxy
  • 120. Evolve
  • 121. because cache is abstracted from the application
  • 123. because caching is bound to the protocol, HTTP, not to your implementation ( Sf, RoR, Django )
  • 126. Alessandro Nadalin odino.org
  • 127. Alessandro Nadalin odino.org @_odino_
  • 128. Alessandro Nadalin odino.org @_odino_ http://joind.in/talk/view/2988
  • 129. Alessandro Nadalin odino.org @_odino_ http://joind.in/talk/view/2988 Thanks!
  • 130. Credits http://www.flickr.com/photos/snakphotography/5004775320/sizes/o/in/photostream/ http://www.flickr.com/photos/ashatenbroeke/4367373081/sizes/z/in/photostream/ http://www.flickr.com/photos/juanpg/3333385784/sizes/z/in/photostream/ http://www.flickr.com/photos/congvo/301678287/sizes/l/in/photostream/ http://www.flickr.com/photos/adamrice/280300202/sizes/l/in/photostream/ http://www.flickr.com/photos/tomer_a/541411897/sizes/o/in/photostream/ http://www.flickr.com/photos/subpra/4514008262/sizes/l/in/photostream/ http://www.flickr.com/photos/lippincott/2539720043/sizes/l/in/photostream/ http://www.flickr.com/photos/rawryder/5086090931/sizes/l/in/photostream/ http://www.flickr.com/photos/robboudon/5312731161/sizes/l/in/photostream/ http://www.flickr.com/photos/bc-burnslibrary/4158243488/sizes/o/in/photostream/ http://www.flickr.com/photos/13606325@N08/2416993706/sizes/o/in/photostream/ http://www.flickr.com/photos/neothezion/5135841069/sizes/l/in/photostream/ http://www.flickr.com/photos/planetschwa/2494067809/ http://www.flickr.com/photos/thomasthomas/258931782/ http://www.flickr.com/photos/jungle_boy/220181177/sizes/l/in/photostream/ http://www.flickr.com/photos/ramduk/3708039504/sizes/z/in/photostream/ http://www.flickr.com/photos/sashawolff/3228711025/sizes/l/in/photostream/