Components as microservices

SOA in the front-end world

Matteo Figus / @matteofigus

@matteofigus

Coding, technology, conferences
London, UK
OpenTable

Restaurant Reservations - Free • Instant • Confirmed

more than 32K restaurants worldwide

more than 16M reservations every month

more than 450K reviews per month

Europe, North and South America, Asia

millions of requests per minute

more than 50 engineers make changes every day

Agenda

  • Microsites architecture
  • OpenComponents architecture
  • Agile in the front-end world

The Microsites architecture

Step #1 - Dismantling the monolith

Continuous delivery in dates

2012 - Setup continuous integration pipeline

2013 - All the code moved to github

2014 - First project implements continous deployment

2015 - 10+ deployments per day

couple days ago - New engineer makes 1 PR and gets its code to prod on day 1

The monolithic architecture (2012)

  • Unique giant DB managed by DBAs
  • Stored procedures to handle data
  • Huge .NET applications dialing directly with the DB

The monolith

Deployments every 15 days

Not very resilient

Not very robust

Code consistency (one single language)

Dedicated team for infrastructure

Dedicated team for testing

A couple of years later...

Microsites

www.opentable.com/san-francisco-restaurants

  • "start" microsite
  • San Francisco metro
  • => http://start-123/?domain=com&metro=4

Microsites

  • Team of 2 to 4 full-stack engineers
  • Minimal complexity
  • Minimal dependencies
  • Easier to test, maintain, extend
  • Multiple daily deployments
  • Ownership

The common parts

The common parts

Microsite rendering (server-side)

  • http://search-456/?metro=4&dateTime=2015-10-23T19:00
  • Execute logic
  • GET shared components from Components API
  • <html>
      <head>
        <!-- css component -->
        <!-- js head component -->
        ...
      </head>
      <body>
        <!-- header component -->
        ...
        <!-- footer component -->
        <!-- js body component -->
        ...
      </body>
    </html>
    

Components for common UI elements

$ curl http://components-789/header/1.X.X/?userType=Admin&metroId=72 -H Accept-Language:en-US

{
  "href": "http://components-789/header/1.X.X?userType=Admin&metroId=72",aefaef
  "html": "<div><img src=\"//srs.opentable.com/logo.jpg\" />...</div>"
}

Microsites + Shared components

Consistency

Coordination

Optimal front-end loading

Easy to spin-up new microsites

OpenComponents

A framework for developing and deploying HTML components

github.com/opentable/oc

Demo time!

Getting started

$ npm install -g oc

$ mkdir demo && cd demo
$ oc init test-component jade
$ echo 'div this is my component' > test-component/template.jade

$ oc dev . 3030
$ oc preview http://localhost:3030/test-component

Ship it!

$ oc registry add http://oc-registry.herokuapp.com
$ oc publish /test-component

$ oc preview http://oc-registry.herokuapp.com/test-component

Static resources? Let me handle this!

// template.jade

img(src=staticPath+'img/img.jpg')

// server.js

module.exports.data = function(context, cb){
  cb(null, {
    staticPath: context.staticPath
  });
};

Client-side rendering

<html>
  <body>
    ...
    <oc-component href="http://oc-registry.com/component/1.X.X/?a=b">
    </oc-component>
    ...
    <script src="http://oc-registry.com/oc-client/client.js">
    </script>
  </body>
</html>

Server-side rendered components

$ curl http://oc-registry.com/hello-world

{
  "href": "https://oc-registry.com/hello-world",
  "name": "hello-world",
  "version": "1.0.0",
  "requestVersion": "",
  "html": "<div>hello John Doe</div>",
  "type": "oc-component",
  "renderMode": "rendered"
}

Server-side unrendered components

$ curl http://oc-registry.com/hello-world 
-H Accept:application/vnd.oc.unrendered+json
{
  "href": "https://oc-registry.com/hello-world",
  "name": "hello-world",
  "version": "1.0.0",
  "requestVersion": "",
  "data": { "name": "John doe" },
  "template": {
    "src": "https://s3.amazonaws.com/your-s3-bucket/components/hello-world/1.0.0/template.js",
    "type": "handlebars",
    "key": "cad2a9671257d5033d2abfd739b1660993021d02"
  },
  "type": "oc-component",
  "renderMode": "unrendered"
}

Server-side rendering with node.js

npm install oc-client --save

var Client = require('oc-client'),
    client = new Client({
      registries: {
        serverRendering: 'http://oc-registry.intranet/'
        clientRendering: 'http://oc-registry.com/'
      },
      components: {'hello-world': '~1.0.0'}
    });

client.renderComponent('hello-world', function(err, componentHtml){
  console.log(componentHtml); // => rendered html
});

Features

Enables people to create and publish new components independently

Granular ownership

Performances

Robustness

Serve as framework for experimenting and A/B testing new ideas in the front-end

Microsites have control

What is a microservice?

Good question, dear

The art of destroying software

https://player.vimeo.com/video/108441214

Why are you doing this?

Ownership

Microservices / Microsites / Microteams

  • Minimal dependencies
  • Minimal complexity
  • Closer to Business
  • Trusted to handle ownership
  • Optimised for resilience

Conclusions

SOA is not just about code

Test, test, test

Failure is a feature

Componentise all the web!

Thank you

http://tech.opentable.co.uk/blog/2015/02/09/dismantling-the-monolith-microsites-at-opentable/

github.com/opentable/oc

github.com/matteofigus/oc-components-examples

github.com/opentable/hobknob


follow me on twitter - @matteofigus

matteofigus.github.io