Scale-proof Frontend: a real world architecture - Ivan Prignano, Nicola Racco - Codemotion Milan...

Post on 05-Jul-2015

378 views 0 download

description

Quali problemi si possono riscontrare quando si progetta e sviluppa un'applicazione web che dovrà servire centinaia di migliaia di utenti? Hit per minute, scalabilità, e altro jargon sistemistico visto dal punto di vista dello sviluppo front end.

transcript

Scale-proof Frontend:a real world architecture

28 Novembre 2014 Milano

IvanPrignano

@iprignano

NicolaRacco

@nicolaracco

Front-end developer Back-end developer

intro: ivan

www.mikamai.com

UNCONVENTIONAL EVERYTHING

27 M giocatori / giorno 67 M giocatori / mese

Il Progetto

Nicola ora

• Tornei a più fasi

• Generazione dinamica delle bracket

• Backend per approvazione utenti e gestione torneo

• Scalabilità in base al carico

Sistema di gestione e visualizzazione di tornei

2

8

BDD

Stack tecnologico

Ivan ora

Ruby on Rails

“Ruby on Rails is an open-source web framework that’s optimized for programmer happiness and sustainable productivity.

It lets you write beautiful code by favoring convention over configuration.”

WEB FRAMEWORK

• Minificazione asset out-of-the-box

• Turbolinks (pjax) out-of-the-box

SassCSS PREPROCESSOR

@import "mixins"

$red: #ff0000

.box width: 100%

.box-title color: $red @include boldness()

.box { width: 100%;}

.box .box-title { color: #ff0000;

font-weight: bold; text-transform: uppercase;

}

SlimTEMPLATING ENGINE

.box.box-title Sono un titolo!#box-content = @content

<div class=“box”><div class=“box-title”> Sono un titolo!</div><div id=“box-content”>

Sono un contenuto!</div>

</div>

CoffeeScriptCOMPILE-TO-JS LANGUAGE

class Brackets.Tooltips constructor: (el) -> alert(el)

new Brackets.Tooltips('.elemento')

Brackets.Tooltips = (function() { function Tooltips(el) { alert(el); }

return Tooltips;

})();

new Brackets.Tooltips('.elemento');

Come funziona

ancora Ivan

Registrazione utente Approvazione team

Chiusura registrazioniPubblicazione torneo

Avanzamento di fase Annuncio vincitori

Registrazione utente Approvazione team

Chiusura registrazioniPubblicazione torneo

Avanzamento di fase Annuncio vincitori

Problema:la generazione dell’albero

Nicola!

JSON

JSON EVERYWHERE

209,"with_recording":false,"score":[0,0],"result_type":5,"best_of":1},"from":[{"position":97,"payload":

{"id":null,"with_recording":false,"score":[0,0],"result_type":5}},{"position":99,"payload":{"id":209,"with_recording":false,"score":

[0,0],"result_type":5}}]},{"position":102,"payload":{"id":88,"with_recording":false,"score":[1,0],"result_type":3,"best_of":

1},"from":[{"position":101,"payload":{"id":88,"with_recording":false,"score":[0,0],"result_type":5}},

{"position":103,"payload":{"id":77,"with_recording":false,"score":[0,0],"result_type":5}}]}]},{"position":108,"payload":{"id":

151,"with_recording":true,"score":[0,1],"result_type":2,"best_of":1},"from":[{"position":106,"payload":{"id":

168,"with_recording":false,"score":[0,0],"result_type":5,"best_of":1},"from":[{"position":105,"payload":

{"id":null,"with_recording":false,"score":[0,0],"result_type":5}},{"position":107,"payload":{"id":

168,"with_recording":false,"score":[0,0],"result_type":5}}]},{"position":110,"payload":{"id":151,"with_recording":true,"score":

[0,1],"result_type":2,"best_of":1},"from":[{"position":109,"payload":{"id":84,"with_recording":false,"score":

HTML plain? Perché no!PRIMA PROVA

Semplice da scrivere e stilare

Facile da testare

PRO

Poco performante su grandi numeri

Zoom limitato

CONTRO

SVG!SECONDA PROVA

Semplice quanto la versione HTML

Uber Zooming

PRO

Poco performante su device mobile

CONTRO

Registrazione utente Approvazione team

Chiusura registrazioniPubblicazione torneo

Avanzamento di fase Annuncio vincitori

Ivan

Registrazione utente Approvazione team

Chiusura registrazioniPubblicazione torneo

Avanzamento di fase Annuncio vincitori

Problema:modali per il match report

Ivan

Preloading static data

$.when( @startGetAllStaticData()... ).done => @staticData = { champions: @champions spells: @summonerSpells items: @items versions: @versions }

# Show the brackets!

Preloading static data

$.when( @startGetAllStaticData()... ).done => @staticData = { champions: @champions spells: @summonerSpells items: @items versions: @versions }

# Show the brackets!

Preloading static data

$.when( @startGetAllStaticData()... ).done => @staticData = { champions: @champions spells: @summonerSpells items: @items versions: @versions }

# Show the brackets!

API Proxy

Cache delle chiamate

Nel caso le API ufficiali fossero down, il servizio funziona comunque

1 chiamata dal frontend = multiple sul backend

Brackets Proxy API

history.pushState()

https://dominio.com/brackets/1

history.pushState()

https://dominio.com/brackets/1/battles/64

Share dinamico

Share dinamico

Inoltre…

Nicola

JSON

Risultati

Nicola

da 2 a 16.384128^2

~10.350 connessioniConcurrency di 300

<0.05s

Possibili miglioramenti

Ivan

Static data spriting

SVG spriting

SSSSVG 2000Supercool Server-side Scalable Vector Graphics 2000

Offloading della creazione

delle SVG sul server

Conclusioni

Premature optimisation

!==

Unnecessary optimisation

Nicola

Refactor often, refactor early

Ivan

CACHE

ALL THE THINGS

Domande?