rs on rails 2011
DESCRIPTION
Discutindo Rails e Arquiteturas. Palestra para a RS on Rails 2011TRANSCRIPT
Discutindo Railse Arquiteturas
a apresentação já vai começar ...
Discutindo Railse Arquiteturas
Fabio Akitawww.akitaonrails.com
@akitaonrails
1 ano atrás 4 pessoas
Hoje 20 pessoas+ USD 1 Milhão/ano
1 ano atrás 4 pessoas
Hoje 20 pessoas+ USD 1 Milhão/ano
1 ano atrás 4 pessoas
Hoje 20 pessoas+ USD 1 Milhão/ano
~1990
Anos 80 Fim Anos 90 Século XXI
Perl
C
Anos 80 Fim Anos 90 Século XXI
Basic
dBase III
Clipper
Pascal
Delphi
ASP
PHP
Python
.NET
Java
ABAP
Ruby
ObjCVB6
1.8.71.9.2
1.9.3-dev2.3.123.0.9
3.1-RC4
1.8.71.9.2
1.9.3-dev2.3.123.0.9
3.1-RC4
1.8.71.9.2
1.9.3-dev2.3.123.0.9
3.1-RC4
Web Server
Rack Middlewares
Routes
Controller
ModelView
Request
Web Server
Rack Middlewares
Routes
Controller
ModelView
Request
Web Server
Rack Middlewares
Routes
Controller
ModelView
Request
Web Server
Rack Middlewares
Routes
Controller
ModelView
Request
Web Server
Rack Middlewares
Routes
Controller
ModelView
Request
Web Server
Rack Middlewares
Routes
Controller
ModelView
Request
Web Server
Rack Middlewares
Routes
Controller
ModelView
Request
Web Server
Rack Middlewares
Routes
Controller
ModelView
Request
Web Server
Rack Middlewares
Routes
Controller
ModelView
Request
Web Server
Rack Middlewares
Routes
Controller
ModelView
Request
Web Server
Rack Middlewares
Routes
Controller
ModelView
Request
Web Server
Rack Middlewares
Routes
Controller
ModelView
Response Request
Application Server Rack:
Unicorn, Passenger
Web Server
Rack Middlewares
Routes
Controller
ModelView
Response Request
Web Server:
NginXApache
Application Server Rack:
Unicorn, Passenger
Web Server
Rack Middlewares
Routes
Controller
ModelView
Response Request
NginX, Apache
Unicorn, Passenger
Reverse Proxy
ActiveRecord/DataMapper
RDBMS/NoSQL
NginX, Apache
Unicorn, Passenger
Reverse Proxy
ActiveRecord/DataMapper
RDBMS/NoSQLWeb Services (REST, SOAP)
RestClient/Savon
HAProxy
NginX, Apache
Unicorn, Passenger
Reverse Proxy
ActiveRecord/DataMapper
RDBMS/NoSQLWeb Services (REST, SOAP)
RestClient/Savon
HAProxy
Varnish
NginX, Apache
Unicorn, Passenger
Reverse Proxy
ActiveRecord/DataMapper
RDBMS/NoSQLWeb Services (REST, SOAP)
RestClient/Savon
HAProxy
Memcached
Varnish
HTTPD
Request Request Request Request Request Request
RailsApp
RailsApp
RailsApp
RailsApp
RailsApp
RailsApp
RDBMS
HTTPD HTTPD HTTPD HTTPD HTTPD
HTTPD
Request Request Request Request Request Request
RailsApp
RailsApp
RailsApp
RailsApp
RailsApp
RailsApp
RDBMS
HTTPD HTTPD HTTPD HTTPD HTTPD
HTTPD
Request Request Request Request Request Request
RailsApp
RailsApp
RailsApp
RailsApp
RailsApp
RailsApp
RDBMS
HTTPD HTTPD HTTPD HTTPD HTTPD
Mais curto possível!
Thread Context Switch
Thread Context Switch
Request RailsApp
Eventos AssíncronosEnvio de mensagens
HTTPD
Request Request Request Request Request Request
RailsApp
RailsApp
RailsApp
RailsApp
RailsApp
RailsApp
RDBMS
HTTPD HTTPD HTTPD HTTPD HTTPD
NginX
Request Request Request Request Request Request
RDBMS
Async App
NginX
Request Request Request Request Request Request
RDBMS
Async App“Look Ma!
No Threads!”
NginX
Request Request Request Request Request Request
RDBMS
Async App“Look Ma!
No Threads!”
5k ~ 10kconexões
NginX
Request Request Request Request Request Request
RDBMS
Async App“Look Ma!
No Threads!”
5k ~ 10kconexões
ConexõesLongas
EventMachine.run do conn = { :host => "0.0.0.0", :port => 8080 } EventMachine::WebSocket.start(conn) do |ws| ws.onopen do puts "WebSocket connection open" # publish message to the client ws.send "Hello Client" end ws.onclose { puts "Connection closed" } ws.onmessage do |msg| puts "Recieved message: #{msg}" ws.send "Pong: #{msg}" end endend
EventMachine.run do conn = { :host => "0.0.0.0", :port => 8080 } EventMachine::WebSocket.start(conn) do |ws| ws.onopen do puts "WebSocket connection open" # publish message to the client ws.send "Hello Client" end ws.onclose { puts "Connection closed" } ws.onmessage do |msg| puts "Recieved message: #{msg}" ws.send "Pong: #{msg}" end endend
EventMachine.run do conn = { :host => "0.0.0.0", :port => 8080 } EventMachine::WebSocket.start(conn) do |ws| ws.onopen do puts "WebSocket connection open" # publish message to the client ws.send "Hello Client" end ws.onclose { puts "Connection closed" } ws.onmessage do |msg| puts "Recieved message: #{msg}" ws.send "Pong: #{msg}" end endend
EventMachine.run do conn = { :host => "0.0.0.0", :port => 8080 } EventMachine::WebSocket.start(conn) do |ws| ws.onopen do puts "WebSocket connection open" # publish message to the client ws.send "Hello Client" end ws.onclose { puts "Connection closed" } ws.onmessage do |msg| puts "Recieved message: #{msg}" ws.send "Pong: #{msg}" end endend
EventMachine.run do conn = { :host => "0.0.0.0", :port => 8080 } EventMachine::WebSocket.start(conn) do |ws| ws.onopen do puts "WebSocket connection open" # publish message to the client ws.send "Hello Client" end ws.onclose { puts "Connection closed" } ws.onmessage do |msg| puts "Recieved message: #{msg}" ws.send "Pong: #{msg}" end endend
EventMachine.run do conn = { :host => "0.0.0.0", :port => 8080 } EventMachine::WebSocket.start(conn) do |ws| ws.onopen do puts "WebSocket connection open" # publish message to the client ws.send "Hello Client" end ws.onclose { puts "Connection closed" } ws.onmessage do |msg| puts "Recieved message: #{msg}" ws.send "Pong: #{msg}" end endend
EventMachine.run do conn = { :host => "0.0.0.0", :port => 8080 } EventMachine::WebSocket.start(conn) do |ws| ws.onopen do puts "WebSocket connection open" # publish message to the client ws.send "Hello Client" end ws.onclose { puts "Connection closed" } ws.onmessage do |msg| puts "Recieved message: #{msg}" ws.send "Pong: #{msg}" end endend
EventMachine.run do conn = { :host => "0.0.0.0", :port => 8080 } EventMachine::WebSocket.start(conn) do |ws| ws.onopen do puts "WebSocket connection open" # publish message to the client ws.send "Hello Client" end ws.onclose { puts "Connection closed" } ws.onmessage do |msg| puts "Recieved message: #{msg}" ws.send "Pong: #{msg}" end endend
EventMachine.run do conn = { :host => "0.0.0.0", :port => 8080 } EventMachine::WebSocket.start(conn) do |ws| ws.onopen do puts "WebSocket connection open" # publish message to the client ws.send "Hello Client" end ws.onclose { puts "Connection closed" } ws.onmessage do |msg| puts "Recieved message: #{msg}" ws.send "Pong: #{msg}" end endend
<script src="http://js.pusherapp.com/1.8/pusher.min.js"></script>
<script>var pusher = new Pusher('API_KEY');var myChannel = pusher.subscribe('MEU_CANAL');</script>
<script src="http://js.pusherapp.com/1.8/pusher.min.js"></script>
<script>var pusher = new Pusher('API_KEY');var myChannel = pusher.subscribe('MEU_CANAL');</script>
<script src="http://js.pusherapp.com/1.8/pusher.min.js"></script>
<script>var pusher = new Pusher('API_KEY');var myChannel = pusher.subscribe('MEU_CANAL');</script>
myChannel.bind('coisa-criada', function(thing) { alert('Uma coisa foi criada: ' + thing.name);});
myChannel.bind('coisa-criada', function(thing) { alert('Uma coisa foi criada: ' + thing.name);});
myChannel.bind('coisa-criada', function(thing) { alert('Uma coisa foi criada: ' + thing.name);});
require 'pusher'
Pusher.app_id = 'APP_ID'Pusher.key = 'API_KEY'Pusher.secret = 'SECRET_KEY'
class ThingsController < ApplicationController def create @thing = Thing.new(params[:thing])
if @thing.save Pusher['MEU_CANAL'].trigger('coisa-criada', @thing.attributes) end endend
require 'pusher'
Pusher.app_id = 'APP_ID'Pusher.key = 'API_KEY'Pusher.secret = 'SECRET_KEY'
class ThingsController < ApplicationController def create @thing = Thing.new(params[:thing])
if @thing.save Pusher['MEU_CANAL'].trigger('coisa-criada', @thing.attributes) end endend
require 'pusher'
Pusher.app_id = 'APP_ID'Pusher.key = 'API_KEY'Pusher.secret = 'SECRET_KEY'
class ThingsController < ApplicationController def create @thing = Thing.new(params[:thing])
if @thing.save Pusher['MEU_CANAL'].trigger('coisa-criada', @thing.attributes) end endend
require 'pusher'
Pusher.app_id = 'APP_ID'Pusher.key = 'API_KEY'Pusher.secret = 'SECRET_KEY'
class ThingsController < ApplicationController def create @thing = Thing.new(params[:thing])
if @thing.save Pusher['MEU_CANAL'].trigger('coisa-criada', @thing.attributes) end endend
Arquitetura de Altíssima Concorrência
(
W. Edward Deming
IN GOD WE TRUST
Todos os outros devem trazer dados
EXPERIENCE BY ITSELF BRINGSNOTHING
ACD
P
Ciclo “Plan-Do-Check-Act”(melhoria contínua)
ACD
P
STANDARD
Ciclo “Plan-Do-Check-Act”(melhoria contínua)
ACD
P
Ciclo “Plan-Do-Check-Act”(melhoria contínua)
ACD
P
Ciclo “Plan-Do-Check-Act”(melhoria contínua)
ACD
P
Ciclo “Plan-Do-Check-Act”(melhoria contínua)
ACD
P
Ciclo “Plan-Do-Check-Act”(melhoria contínua)
)
Perl
Python
PHP
Ruby
OMG!
2007
2008
2009
2010
2011
Ruby on Rails
2.0.0
2.1.0
2.2.0
2.3.0
3.0.0
2.0.5
2.1.2
2.2.3
2.3.12
3.0.9
2007
2008
2009
2010
2011
6
3
4
12
10
Ruby on Rails
2.0.0
2.1.0
2.2.0
2.3.0
3.0.0
2.0.5
2.1.2
2.2.3
2.3.12
3.0.9
2007
2008
2009
2010
2011
Ruby on Rails
34Versões!
Web Server
Request
RailsApp
/public/stylesheets
Web Server
Request
RailsApp
ArquivosEstáticos
/public/stylesheets
Variáveis/* CSS */
.content-navigation { border-color: #3bbfce; color: #2b9eab;}
.border { padding: 8px; margin: 8px; border-color: #3bbfce;}
$blue: #3bbfce;$margin: 16px;
.content-navigation { border-color: $blue; color: darken($blue, 9%);}
.border { padding: $margin / 2; margin: $margin / 2; border-color: $blue;}
Nestingtable.hl { margin: 2em 0; td.ln { text-align: right; }}
li { font: { family: serif; weight: bold; size: 1.2em; }}
/* CSS */
table.hl { margin: 2em 0;}table.hl td.ln { text-align: right;}
li { font-family: serif; font-weight: bold; font-size: 1.2em;}
Mixins@mixin table-base { th { text-align: center; font-weight: bold; } td, th {padding: 2px}}
@mixin left($dist) { float: left; margin-left: $dist;}
#data { @include left(10px); @include table-base;}
/* CSS */
#data { float: left; margin-left: 10px;}#data th { text-align: center; font-weight: bold;}#data td, #data th { padding: 2px;}
Selector Inheritance.error { border: 1px #f00; background: #fdd;}.error.intrusion { font-size: 1.3em; font-weight: bold;}
.badError { @extend .error; border-width: 3px;}
/* CSS */
.error, .badError { border: 1px #f00; background: #fdd;}
.error.intrusion,
.badError.intrusion { font-size: 1.3em; font-weight: bold;}
.badError { border-width: 3px;}
class Animal constructor: (@name) ->
move: (meters) -> alert @name + " moved " + meters + "m."
class Snake extends Animal move: -> alert "Slithering..." super 5
class Horse extends Animal move: -> alert "Galloping..." super 45
sam = new Snake "Sammy the Python"tom = new Horse "Tommy the Palomino"
sam.move()tom.move()
class Animal constructor: (@name) ->
move: (meters) -> alert @name + " moved " + meters + "m."
class Snake extends Animal move: -> alert "Slithering..." super 5
class Horse extends Animal move: -> alert "Galloping..." super 45
sam = new Snake "Sammy the Python"tom = new Horse "Tommy the Palomino"
sam.move()tom.move()
var Animal, Horse, Snake, sam, tom;var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child;};Animal = (function() { function Animal(name) { this.name = name; } Animal.prototype.move = function(meters) { return alert(this.name + " moved " + meters + "m."); }; return Animal;})();Snake = (function() { __extends(Snake, Animal); function Snake() { Snake.__super__.constructor.apply(this, arguments); } Snake.prototype.move = function() { alert("Slithering..."); return Snake.__super__.move.call(this, 5); }; return Snake;})();Horse = (function() { __extends(Horse, Animal); function Horse() { Horse.__super__.constructor.apply(this, arguments); } Horse.prototype.move = function() { alert("Galloping..."); return Horse.__super__.move.call(this, 45); }; return Horse;})();sam = new Snake("Sammy the Python");tom = new Horse("Tommy the Palomino");sam.move();tom.move();loadrun
102
Web Server(Produção)
Request
RailsApp
/app/assets
Web Server(Desenvolvimento)
Request
/public
Web Server(Produção)
Request
RailsApp
/app/assets
Web Server(Desenvolvimento)
Request
Sprockets
/public
Web Server(Produção)
Request
RailsApp
/app/assets
Web Server(Desenvolvimento)
Request
Sprockets
Tilt
/public
Web Server(Produção)
Request
RailsApp
/app/assets
Web Server(Desenvolvimento)
Request
Sprockets
Tilt
Ugli!er
/public
ENGINE FILE EXTENSIONS REQUIRED LIBRARIES
ERB .erb, .rhtmlnone
Interpolated String .strnone
Erubis .erb, .rhtml, .erubis erubis
Haml .haml haml
Sass .sasssass
Scss .scsssass
Less CSS .less less
Builder .builder builder
Liquid .liquid liquid
RDiscount
.markdown, .mkd, .md
rdiscount
Redcarpet
.markdown, .mkd, .md
redcarpet
BlueCloth .markdown, .mkd, .md bluecloth
Kramdown
.markdown, .mkd, .md
kramdown
Maruku
.markdown, .mkd, .md
maruku
RedCloth .textile redcloth
RDoc .rdoc rdoc
Radius .radius radius
Markaby .mab markaby
Nokogiri .nokogiri nokogiri
CoffeeScript .coffee coffee-script
Creole (Wiki markup) .creole creole
jQuery Tamanho Tempo
Original Size 621kb
Google Closure 234kb 6.5s
YUI Compressor 240kb 2.7s
UglifyJS 235kb 1.3s
jQuery Tamanho Tempo
Original Size 621kb
Google Closure 234kb 6.5s
YUI Compressor 240kb 2.7s
UglifyJS 235kb 1.3s
jQuery Tamanho Tempo
Original Size 621kb
Google Closure 234kb 6.5s
YUI Compressor 240kb 2.7s
UglifyJS 235kb 1.3s
jQuery Tamanho Tempo
Original Size 621kb
Google Closure 234kb 6.5s
YUI Compressor 240kb 2.7s
UglifyJS 235kb 1.3s
jQuery Tamanho Tempo
Original Size 621kb
Google Closure 234kb 6.5s
YUI Compressor 240kb 2.7s
UglifyJS 235kb 1.3s
Rails 3.1:Release Candidate
(may 2011)
RubyConfBrasil
3 e 4 de Novembrowww.rubyconf.com.br
<epílogo>
Como o cliente explicou
Como o Líder de Projeto entendeu
Como o Analista desenhou
Como o Programador escreveu
Como o Consultor de Negócios descreveu
Como o projeto foi documentado
Como Operações instalou
Como o cliente foi cobrado Como foi o suporte
O que o cliente realmente queria
Requerimentos:ENTENDIDO!
LOL
DESIGN
DESIGN
Pattern PADRÃO
Pattern PADRÃO
Default
STANDARD
“Pattern”
NÃO é “Standard”!
Christopher Alexander
cada padrão (“pattern”)representa nosso melhor chute agora ... os padrões ainda são hipóteses, ... e portanto todos são
tentativas, todos livres para evoluir sob o impacto de novas experiências e
observações."
Christopher Alexander
2 + 2 = 5!
2 + 2 = 5!
2 + 2 = 4!
Bertrand Russel
Bertrand Russel
Aqui estão os fatos. Que conclusões podemos
chegar com eles?
Aqui está a conclusão. Que fatos podemos suportar com eles?
80
20
80
20
80
20
80“Long Tail”
@pedroh96
Pedro Franceschi
15 anos
@pedroh96
Pedro Franceschi
9 anos
@pedroh96
Pedro Franceschi
6 anos
@pedroh96
Pedro Franceschi
@pedroh96
Pedro Franceschi
<epílogo>
Obrigado!
.com.br
www.akitaonrails.com
u.akita.ws/rsonrails11
Obrigado!
.com.br
www.akitaonrails.com
u.akita.ws/rsonrails11