SlideShare uma empresa Scribd logo
1 de 58
Baixar para ler offline
Programação Funcional Reativa:
Lidando com código assíncrono
QCon São Paulo, 2014
Leonardo Borges
@leonardo_borges
www.leonardoborges.com
www.thoughtworks.com
Sobre
‣ Consultor Senior na ThoughtWorks
Australia
‣ Entusiasta de Programação Functional
‣ Clojure geek
‣ Fundador do Grupo de Usuários Clojure
de Sydney
‣ No momento escrevendo o livro
“Clojure Reactive Programming”
var result = 1;!
numbers.forEach(function(n){!
if(n % 2 === 0) {!
result *= n;!
}!
});!
console.log( result );!
// 8!
var numbers = [1,2,3,4,5];
Em programação imperativa, descrevemos computações como uma
serie de ações que modificam o estado do programa
Em programação imperativa, descrevemos computações como uma
serie de ações que modificam o estado do programa
var result = 1;!
numbers.forEach(function(n){!
if(n % 2 === 0) {!
result *= n;!
}!
});!
console.log( result );!
// 8!
var numbers = [1,2,3,4,5];
Requer uma variável
para armazenar
estado
var result = 1;!
numbers.forEach(function(n){!
if(n % 2 === 0) {!
result *= n;!
}!
});!
console.log( result );!
// 8!
var numbers = [1,2,3,4,5];
Iteramos sobre os
itens do array
Em programação imperativa, descrevemos computações como uma
serie de ações que modificam o estado do programa
var result = 1;!
numbers.forEach(function(n){!
if(n % 2 === 0) {!
result *= n;!
}!
});!
console.log( result );!
// 8!
var numbers = [1,2,3,4,5];
E na mesma função
filtramos os itens…
Em programação imperativa, descrevemos computações como uma
serie de ações que modificam o estado do programa
var result = 1;!
numbers.forEach(function(n){!
if(n % 2 === 0) {!
result *= n;!
}!
});!
console.log( result );!
// 8!
var numbers = [1,2,3,4,5];
…e efetuamos a
multiplicação.
Em programação imperativa, descrevemos computações como uma
serie de ações que modificam o estado do programa
Já em programação funcional, descrevemos o que queremos fazer e
não como queremos fazê-lo
var numbers = [1,2,3,4,5];
var result = numbers!
.filter(function(n){ return n % 2 === 0; })!
.reduce(function(acc, n){!
return acc * n;!
});!
console.log( result );!
// 8!
Já em programação funcional, descrevemos o que queremos fazer e
não como queremos fazê-lo
var numbers = [1,2,3,4,5];
var result = numbers!
.filter(function(n){ return n % 2 === 0; })!
.reduce(function(acc, n){!
return acc * n;!
});!
console.log( result );!
// 8!
Nenhuma variável
necessária para a
mesma computação
Já em programação funcional, descrevemos o que queremos fazer e
não como queremos fazê-lo
var numbers = [1,2,3,4,5];
var result = numbers!
.filter(function(n){ return n % 2 === 0; })!
.reduce(function(acc, n){!
return acc * n;!
});!
console.log( result );!
// 8! E temos duas funções que
podem ser re-utilizadas de
forma independente
A programação funcional reativa traz o mesmo princípio
para valores com os quais lidamos no dia-a-dia:
eventos DOM como clicks, key presses, movimentos do
mouse, chamadas Ajax…
Antes de definir um pouco mais
formalmente o que eh FRP, vamos
olhar um exemplo
Movimentos em um jogo
var JUMP = 38, CROUCH = 40,!
LEFT = 37, RIGHT = 39,!
FIRE = 32;!
!
function goRight (){!
$('h1').html("Ir para a direita...");!
}!
!
function goLeft (){!
$('h1').html("Ir para a esquerda...");!
}!
!
function jump (){!
$('h1').html("Pular...");!
}!
!
function crouch (){!
$('h1').html("Abaixar...");!
}!
!
function fire (){!
$('h1').html("Atirar...");!
}
Movimentos em um jogo:
estilo imperativo
$(window.document).keyup(function(event){!
switch(event.keyCode){!
case JUMP :!
jump();!
break;!
case CROUCH:!
crouch();!
break;!
case LEFT :!
goLeft();!
break;!
case RIGHT :!
goRight();!
break;!
case FIRE :!
fire();!
break;!
};!
});
Temos problemas similares
ao exemplo anterior
Porém, podemos imaginar que key
presses são um stream de teclas
Para a versão funcional, utilizaremos
o framework de FRP RxJS
Movimentos em um jogo:
estilo funcional
var source = Rx.Observable.fromEvent(window.document, 'keyup');
function isKey (keyCode){!
return function(event){!
return event.keyCode === keyCode;!
};!
}
source.filter(isKey(FIRE)).subscribe(fire);!
source.filter(isKey(JUMP)).subscribe(jump);!
source.filter(isKey(CROUCH)).subscribe(crouch);!
source.filter(isKey(LEFT)).subscribe(goLeft);!
source.filter(isKey(RIGHT)).subscribe(goRight);!
Um pouco mais sobre FRP
‣ Criado em 1997 por Conal Elliott na forma do framework Fran para Haskell
‣ Desde então foi implementada em diversas linguagens e frameworks: Rx(.NET|
JS|Java), reactive-banana (Haskell), Bacon.js, Elm-lang (compile-to-JS) e
outros…
‣ Introduz duas abstrações principais: Behaviors e Events
Exemplo de Behavior: posição do cursor do mouse
function mouseXYBehavior(){!
var behavior = new Rx.BehaviorSubject([0,0]);!
$(window.document).mousemove(function(event){!
behavior.onNext([event.clientX, event.clientY]);!
});!
return behavior;!
}
var xyBehavior = mouseXYBehavior();!
xyBehavior.subscribe(function(xy){!
$('h1').html('(' + xy[0] + ',' + xy[1] + ')');!
});!
!
console.log( xyBehavior.value );!
Um pouco mais sobre Rx - Rx 101
Rx.Observable.returnValue(42)!
.map(function(value){ return value * 2; })!
.subscribe(function(value){!
console.log( value );!
});!
!
// 84!
Um pouco mais sobre Rx - Rx 101
Rx.Observable.fromArray([10, 20, 30])!
.map(function(value){ return value * 2; })!
.reduce(function(acc, value){ return acc + value; })!
.subscribe(function(value){!
console.log( value );!
});!
!
// 120
Um pouco mais sobre Rx - Rx 101
function projectRange(n){!
return Rx.Observable.fromArray(_.range(n));!
}!
!
Rx.Observable.fromArray([1, 2, 3])!
.flatMap(projectRange)!
.subscribe(function(value){!
console.log( value );!
});!
!
// 0!
// 0!
// 1!
// 0!
// 1!
// 2
?
Rx.Observable.fromArray([1, 2, 3])
1 2 3
Rx.Observable.fromArray([1, 2, 3])!
.flatMap(projectRange)
projectRange(2)
0 1
projectRange(1)
0
projectRange(3)
0 1 2
0 0 1 0 1 2
Combinar Observables dessa forma é uma
técnica poderosa como veremos mais adiante
E comunicação com a rede?
E comunicação com a rede?
‣ Callback hell :(
‣ Promises melhoram um pouco mas tem limitações
‣ Funcionam bem para um nível de valores
‣ Porém são um mecanismo pobre de composição
‣ E se tivermos uma série de valores que muda ao decorrer do tempo?
Exemplo: uma simples aplicação de votos
O que queremos:
‣ Mostrar os resultados da pergunta atual
‣ Atualizar os resultados a cada 2 segundos
‣ Se a pergunta atual for a mesma que a pergunta anterior, atualizamos o
resultado. Senão:
‣ Paramos com a atualização periódica;
‣ Mostramos uma mensagem de countdown;
‣ Mostramos a pergunta anterior com os resultados;
‣ Reiniciamos a atualização periódica
Resultados da parte servidor da aplicação
{!
id: 1,!
question: "Which is the best music style?",!
results: {!
a: 8,!
b: 20,!
c: 15!
}!
}!
A idéia principal
Primeiro, tornamos os resultados em um Observable
4 3 3 2 1 1
Depois, duplicamos o Observable, pulando um elemento
4 3 3 2 1 1
5 4 3 3 2 1
skip(1)
Finalmente, zippamos os Observables
4 3 3 2 1 1
5 4 3 3 2 1
zip
[5,4] [4,3] [3,3] [3,2] [2,1] [1,1]
Agora temos acesso em um único observable a
ambos os resultados
Demo
https://github.com/leonardoborges/qcon2014-frp-code
Recapitulando a idéia principal
function resultsObservable () {!
return Rx.Observable.create(function(observer){!
$.get( "/polls/current/results", function(data) {!
observer.onNext(data);!
observer.onCompleted();!
return function () {!
console.log('disposed');!
};!
});!
});!
}
Recapitulando a idéia principal
function resultsConnectable () {!
var obs = Rx.Observable!
.interval(2000)!
.flatMap(resultsObservable)!
.publish()!
.refCount();!
var obs1 = obs.skip(1);!
return Rx.Observable.zipArray(obs, obs1);!
}!
Tornamos os
resultados em um
Observable
Recapitulando a idéia principal
function resultsConnectable () {!
var obs = Rx.Observable!
.interval(2000)!
.flatMap(resultsObservable)!
.publish()!
.refCount();!
var obs1 = obs.skip(1);!
return Rx.Observable.zipArray(obs, obs1);!
}!
Duplicamos o
mesmo, pulando um
elemento
Recapitulando a idéia principal
function resultsConnectable () {!
var obs = Rx.Observable!
.interval(2000)!
.flatMap(resultsObservable)!
.publish()!
.refCount();!
var obs1 = obs.skip(1);!
return Rx.Observable.zipArray(obs, obs1);!
}!
Finalmente,
“zippamos” os
Observables
Show! Será que existe uma forma mais simples de
implementar a mesma funcionalidade?
Certamente!
A mesma funcionalidade, explorando mais da API de Rx
function resultsBuffer () {!
return Rx.Observable!
.interval(2000)!
.flatMap(resultsObservable)!
.bufferWithCount(2, 1);!
}
Explore e entenda a fundo a API do seu framework de FRP
favorito: muito provavelmente o que você precisa já foi
implementado por alguém
Em ambas as soluções, não precisamos de uma
variável extra para armazenar a pergunta anterior
Pensar de forma funcional e utilizar um framework
de FRP nos permite implementar soluções simples
e robustas
"FRP is about handling time-varying values like they
were regular values" - Haskell Wiki
(FRP lida com valores que mudam ao decorrer do
tempo como se fossem valores regulares)
Exemplo bônus: API Reativa para AWS
function resourcesStream (stackName) {!
return Rx.Observable.create(function(observer){!
cloudFormation.describeStackResources({StackName: stackName}, function(err, data){!
if (err) {!
observer.onError("Error");!
observer.onCompleted();!
} else {!
observer.onNext(data);!
observer.onCompleted();!
}!
});!
});!
}
Exemplo bônus: API Reativa para AWS
function ec2InstanceStream (physicalResourceIds) {!
return Rx.Observable.create(function(observer){!
ec2.describeInstances({InstanceIds: physicalResourceIds}, function (err, data) {!
if (err) {!
observer.onError("Error");!
observer.onCompleted();!
} else {!
observer.onNext(data);!
observer.onCompleted();!
}!
});!
});!
}
Exemplo bônus: API Reativa para AWS
function dbInstanceStream (physicalResourceId) {!
return Rx.Observable.create(function(observer){!
rds.describeDBInstances({DBInstanceIdentifier: physicalResourceId}, function (err, data) {!
if (err) {!
observer.onError("Error");!
observer.onCompleted();!
} else {!
observer.onNext(data);!
observer.onCompleted();!
}!
});!
});!
}
Exemplo bônus: API Reativa para AWS
resourcesStream('my-stack')!
.filter(isEC2)!
.map(".PhysicalResourceId")!
.reduce([], function(acc, resource) { acc.push(resource); return acc;})!
.flatMap(ec2InstanceStream);!
Exemplo bônus: API Reativa para AWS
var ec2Data = resourcesStream('my-stack')!
.filter(isEC2)!
.map(".PhysicalResourceId")!
.reduce([], function(acc, resource) { acc.push(resource); return acc;})!
.flatMap(this.ec2InstanceStream);
var rdsData = resourcesStream('my-stack')!
.filter(isRDS)!
.map(".PhysicalResourceId")!
.reduce([], function(acc, resource) { acc.push(resource); return acc;})!
.flatMap(dbInstanceStream);!
Exemplo bônus: API Reativa para AWS
var ec2Data = resourcesStream('my-stack')!
.filter(isEC2)!
.map(".PhysicalResourceId")!
.reduce([], function(acc, resource) { acc.push(resource); return acc;})!
.flatMap(this.ec2InstanceStream);
var rdsData = resourcesStream('my-stack')!
.filter(isRDS)!
.map(".PhysicalResourceId")!
.reduce([], function(acc, resource) { acc.push(resource); return acc;})!
.flatMap(dbInstanceStream);!
Exemplo bônus: API Reativa para AWS
ec2Data!
.merge(rdsData)!
.reduce([], function(acc, resource) { acc.push(resource); return acc;});!
Simples de entender, manter e
testar. FRP #FTW!
Obrigado!
Perguntas?
Leonardo Borges
@leonardo_borges
www.leonardoborges.com
www.thoughtworks.com
Referências
‣ Código: https://github.com/leonardoborges/qcon2014-frp-code
!
‣ RxJS: https://github.com/Reactive-Extensions/RxJS
‣ RxJava: https://github.com/Netflix/RxJava
!
Outras implementações:
‣ Bacon.js: https://github.com/baconjs/bacon.js
‣ Reactive Banana: http://www.haskell.org/haskellwiki/Reactive-banana
‣ Elm: http://elm-lang.org/

Mais conteúdo relacionado

Mais procurados

Javascript para CSharpers 2 - Functions
Javascript para CSharpers   2 - FunctionsJavascript para CSharpers   2 - Functions
Javascript para CSharpers 2 - FunctionsWesley Lemos
 
O que mudou no Ruby 1.9
O que mudou no Ruby 1.9O que mudou no Ruby 1.9
O que mudou no Ruby 1.9Nando Vieira
 
Node.js - #5 - Process - Rodrigo Branas
Node.js - #5 - Process - Rodrigo BranasNode.js - #5 - Process - Rodrigo Branas
Node.js - #5 - Process - Rodrigo BranasRodrigo Branas
 
Threads 07: Sincronizadores
Threads 07: SincronizadoresThreads 07: Sincronizadores
Threads 07: SincronizadoresHelder da Rocha
 
(Portuguese) Java EE Poliglota
(Portuguese) Java EE Poliglota(Portuguese) Java EE Poliglota
(Portuguese) Java EE PoliglotaPhil Calçado
 
Yet Another Ruby Framework - Como o Rails funciona por dentro
Yet Another Ruby Framework - Como o Rails funciona por dentroYet Another Ruby Framework - Como o Rails funciona por dentro
Yet Another Ruby Framework - Como o Rails funciona por dentroCarlos Brando
 
LINQ - Language Integrated Query
LINQ - Language Integrated QueryLINQ - Language Integrated Query
LINQ - Language Integrated QueryDalton Valadares
 
Introdução ao MongoDB em 30 slides
Introdução ao MongoDB em 30 slidesIntrodução ao MongoDB em 30 slides
Introdução ao MongoDB em 30 slidesDerek Willian Stavis
 
(2018-08-25) [Flask Conf] Introdução ao Sanic - O Flask Assíncrono
(2018-08-25) [Flask Conf] Introdução ao Sanic - O Flask Assíncrono(2018-08-25) [Flask Conf] Introdução ao Sanic - O Flask Assíncrono
(2018-08-25) [Flask Conf] Introdução ao Sanic - O Flask AssíncronoDanilo J. S. Bellini
 
Por que voce precisa (re)aprender linguagens funcionais
Por que voce precisa (re)aprender linguagens funcionaisPor que voce precisa (re)aprender linguagens funcionais
Por que voce precisa (re)aprender linguagens funcionaisLuiz Borba
 

Mais procurados (14)

Javascript para CSharpers 2 - Functions
Javascript para CSharpers   2 - FunctionsJavascript para CSharpers   2 - Functions
Javascript para CSharpers 2 - Functions
 
O que mudou no Ruby 1.9
O que mudou no Ruby 1.9O que mudou no Ruby 1.9
O que mudou no Ruby 1.9
 
Node.js - #5 - Process - Rodrigo Branas
Node.js - #5 - Process - Rodrigo BranasNode.js - #5 - Process - Rodrigo Branas
Node.js - #5 - Process - Rodrigo Branas
 
Palestra2009
Palestra2009Palestra2009
Palestra2009
 
Threads 07: Sincronizadores
Threads 07: SincronizadoresThreads 07: Sincronizadores
Threads 07: Sincronizadores
 
OOP ObjC
OOP ObjCOOP ObjC
OOP ObjC
 
(Portuguese) Java EE Poliglota
(Portuguese) Java EE Poliglota(Portuguese) Java EE Poliglota
(Portuguese) Java EE Poliglota
 
Yet Another Ruby Framework - Como o Rails funciona por dentro
Yet Another Ruby Framework - Como o Rails funciona por dentroYet Another Ruby Framework - Como o Rails funciona por dentro
Yet Another Ruby Framework - Como o Rails funciona por dentro
 
LINQ - Language Integrated Query
LINQ - Language Integrated QueryLINQ - Language Integrated Query
LINQ - Language Integrated Query
 
Introdução ao MongoDB em 30 slides
Introdução ao MongoDB em 30 slidesIntrodução ao MongoDB em 30 slides
Introdução ao MongoDB em 30 slides
 
Palestra cbq
Palestra cbqPalestra cbq
Palestra cbq
 
Monadic Design
Monadic DesignMonadic Design
Monadic Design
 
(2018-08-25) [Flask Conf] Introdução ao Sanic - O Flask Assíncrono
(2018-08-25) [Flask Conf] Introdução ao Sanic - O Flask Assíncrono(2018-08-25) [Flask Conf] Introdução ao Sanic - O Flask Assíncrono
(2018-08-25) [Flask Conf] Introdução ao Sanic - O Flask Assíncrono
 
Por que voce precisa (re)aprender linguagens funcionais
Por que voce precisa (re)aprender linguagens funcionaisPor que voce precisa (re)aprender linguagens funcionais
Por que voce precisa (re)aprender linguagens funcionais
 

Semelhante a Programação functional reativa: lidando com código assíncrono

Light Talk sobre JavaScript Funcional
Light Talk sobre JavaScript FuncionalLight Talk sobre JavaScript Funcional
Light Talk sobre JavaScript FuncionalEmanuel Gonçalves
 
JavaScript - De verdade
JavaScript - De verdadeJavaScript - De verdade
JavaScript - De verdadeLuis Vendrame
 
LabMM3 - Aula teórica 09
LabMM3 - Aula teórica 09LabMM3 - Aula teórica 09
LabMM3 - Aula teórica 09Carlos Santos
 
Evento Front End SP - Organizando o Javascript
 Evento Front End SP - Organizando o Javascript Evento Front End SP - Organizando o Javascript
Evento Front End SP - Organizando o JavascriptMichel Ribeiro
 
Javascript Avançado
Javascript AvançadoJavascript Avançado
Javascript AvançadoBruno Tavares
 
Evolução e futuro do uso de paradigmas no JavaScript
Evolução e futuro do uso de paradigmas no JavaScriptEvolução e futuro do uso de paradigmas no JavaScript
Evolução e futuro do uso de paradigmas no JavaScriptJean Carlo Emer
 
O que é que o Java não tem?
O que é que o Java não tem?O que é que o Java não tem?
O que é que o Java não tem?Denis Costa
 
(A10) LabMM3 - JavaScript - Subalgoritmos
(A10) LabMM3 - JavaScript - Subalgoritmos(A10) LabMM3 - JavaScript - Subalgoritmos
(A10) LabMM3 - JavaScript - SubalgoritmosCarlos Santos
 
Javascript assíncrono - Um bate-papo sobre event loop, event queue, callbacks...
Javascript assíncrono - Um bate-papo sobre event loop, event queue, callbacks...Javascript assíncrono - Um bate-papo sobre event loop, event queue, callbacks...
Javascript assíncrono - Um bate-papo sobre event loop, event queue, callbacks...Cezinha Anjos
 
(A11) LabMM3 - JavaScript - Subalgoritmos e scope
(A11) LabMM3 - JavaScript - Subalgoritmos e scope(A11) LabMM3 - JavaScript - Subalgoritmos e scope
(A11) LabMM3 - JavaScript - Subalgoritmos e scopeCarlos Santos
 
mod3-programação-estruturada
mod3-programação-estruturadamod3-programação-estruturada
mod3-programação-estruturadadiogoa21
 
JS Experience 2017 - Javascript Funcional
JS Experience 2017 - Javascript FuncionalJS Experience 2017 - Javascript Funcional
JS Experience 2017 - Javascript FuncionaliMasters
 
Código legado - PHP Conference Brasil - 2014
Código legado - PHP Conference Brasil - 2014Código legado - PHP Conference Brasil - 2014
Código legado - PHP Conference Brasil - 2014Michael Castillo Granados
 

Semelhante a Programação functional reativa: lidando com código assíncrono (20)

Light Talk sobre JavaScript Funcional
Light Talk sobre JavaScript FuncionalLight Talk sobre JavaScript Funcional
Light Talk sobre JavaScript Funcional
 
Java script aula 05 - funções
Java script   aula 05 - funçõesJava script   aula 05 - funções
Java script aula 05 - funções
 
JavaScript - De verdade
JavaScript - De verdadeJavaScript - De verdade
JavaScript - De verdade
 
LabMM3 - Aula teórica 09
LabMM3 - Aula teórica 09LabMM3 - Aula teórica 09
LabMM3 - Aula teórica 09
 
Java script - funções
Java script - funçõesJava script - funções
Java script - funções
 
JavaScript - A Linguagem
JavaScript - A LinguagemJavaScript - A Linguagem
JavaScript - A Linguagem
 
Principais novidades do PHP7
Principais novidades do PHP7Principais novidades do PHP7
Principais novidades do PHP7
 
Evento Front End SP - Organizando o Javascript
 Evento Front End SP - Organizando o Javascript Evento Front End SP - Organizando o Javascript
Evento Front End SP - Organizando o Javascript
 
Javascript Avançado
Javascript AvançadoJavascript Avançado
Javascript Avançado
 
Evolução e futuro do uso de paradigmas no JavaScript
Evolução e futuro do uso de paradigmas no JavaScriptEvolução e futuro do uso de paradigmas no JavaScript
Evolução e futuro do uso de paradigmas no JavaScript
 
O que é que o Java não tem?
O que é que o Java não tem?O que é que o Java não tem?
O que é que o Java não tem?
 
(A10) LabMM3 - JavaScript - Subalgoritmos
(A10) LabMM3 - JavaScript - Subalgoritmos(A10) LabMM3 - JavaScript - Subalgoritmos
(A10) LabMM3 - JavaScript - Subalgoritmos
 
Recursividade
RecursividadeRecursividade
Recursividade
 
Javascript assíncrono - Um bate-papo sobre event loop, event queue, callbacks...
Javascript assíncrono - Um bate-papo sobre event loop, event queue, callbacks...Javascript assíncrono - Um bate-papo sobre event loop, event queue, callbacks...
Javascript assíncrono - Um bate-papo sobre event loop, event queue, callbacks...
 
(A11) LabMM3 - JavaScript - Subalgoritmos e scope
(A11) LabMM3 - JavaScript - Subalgoritmos e scope(A11) LabMM3 - JavaScript - Subalgoritmos e scope
(A11) LabMM3 - JavaScript - Subalgoritmos e scope
 
Javascript
JavascriptJavascript
Javascript
 
mod3-programação-estruturada
mod3-programação-estruturadamod3-programação-estruturada
mod3-programação-estruturada
 
JS Experience 2017 - Javascript Funcional
JS Experience 2017 - Javascript FuncionalJS Experience 2017 - Javascript Funcional
JS Experience 2017 - Javascript Funcional
 
Código legado - PHP Conference Brasil - 2014
Código legado - PHP Conference Brasil - 2014Código legado - PHP Conference Brasil - 2014
Código legado - PHP Conference Brasil - 2014
 
PHP 5.3 - Funções
PHP 5.3 - FunçõesPHP 5.3 - Funções
PHP 5.3 - Funções
 

Mais de Leonardo Borges

Realtime collaboration with Clojure - EuroClojure - Barcelona, 2015
Realtime collaboration with Clojure - EuroClojure - Barcelona, 2015Realtime collaboration with Clojure - EuroClojure - Barcelona, 2015
Realtime collaboration with Clojure - EuroClojure - Barcelona, 2015Leonardo Borges
 
Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015Leonardo Borges
 
From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019Leonardo Borges
 
The algebra of library design
The algebra of library designThe algebra of library design
The algebra of library designLeonardo Borges
 
Futures e abstração - QCon São Paulo 2015
Futures e abstração - QCon São Paulo 2015Futures e abstração - QCon São Paulo 2015
Futures e abstração - QCon São Paulo 2015Leonardo Borges
 
Functional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event SystemsFunctional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event SystemsLeonardo Borges
 
High Performance web apps in Om, React and ClojureScript
High Performance web apps in Om, React and ClojureScriptHigh Performance web apps in Om, React and ClojureScript
High Performance web apps in Om, React and ClojureScriptLeonardo Borges
 
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013Leonardo Borges
 
Intro to Clojure's core.async
Intro to Clojure's core.asyncIntro to Clojure's core.async
Intro to Clojure's core.asyncLeonardo Borges
 
Functional Reactive Programming in Clojurescript
Functional Reactive Programming in ClojurescriptFunctional Reactive Programming in Clojurescript
Functional Reactive Programming in ClojurescriptLeonardo Borges
 
Clojure/West 2013 in 30 mins
Clojure/West 2013 in 30 minsClojure/West 2013 in 30 mins
Clojure/West 2013 in 30 minsLeonardo Borges
 
Clojure Reducers / clj-syd Aug 2012
Clojure Reducers / clj-syd Aug 2012Clojure Reducers / clj-syd Aug 2012
Clojure Reducers / clj-syd Aug 2012Leonardo Borges
 
The many facets of code reuse in JavaScript
The many facets of code reuse in JavaScriptThe many facets of code reuse in JavaScript
The many facets of code reuse in JavaScriptLeonardo Borges
 
Continuation Passing Style and Macros in Clojure - Jan 2012
Continuation Passing Style and Macros in Clojure - Jan 2012Continuation Passing Style and Macros in Clojure - Jan 2012
Continuation Passing Style and Macros in Clojure - Jan 2012Leonardo Borges
 
Heroku addons development - Nov 2011
Heroku addons development - Nov 2011Heroku addons development - Nov 2011
Heroku addons development - Nov 2011Leonardo Borges
 
Clouds against the Floods (RubyConfBR2011)
Clouds against the Floods (RubyConfBR2011) Clouds against the Floods (RubyConfBR2011)
Clouds against the Floods (RubyConfBR2011) Leonardo Borges
 
Clouds Against the Floods
Clouds Against the FloodsClouds Against the Floods
Clouds Against the FloodsLeonardo Borges
 

Mais de Leonardo Borges (20)

Realtime collaboration with Clojure - EuroClojure - Barcelona, 2015
Realtime collaboration with Clojure - EuroClojure - Barcelona, 2015Realtime collaboration with Clojure - EuroClojure - Barcelona, 2015
Realtime collaboration with Clojure - EuroClojure - Barcelona, 2015
 
Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015
 
From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019
 
The algebra of library design
The algebra of library designThe algebra of library design
The algebra of library design
 
Futures e abstração - QCon São Paulo 2015
Futures e abstração - QCon São Paulo 2015Futures e abstração - QCon São Paulo 2015
Futures e abstração - QCon São Paulo 2015
 
Functional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event SystemsFunctional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event Systems
 
High Performance web apps in Om, React and ClojureScript
High Performance web apps in Om, React and ClojureScriptHigh Performance web apps in Om, React and ClojureScript
High Performance web apps in Om, React and ClojureScript
 
Monads in Clojure
Monads in ClojureMonads in Clojure
Monads in Clojure
 
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013
 
Intro to Clojure's core.async
Intro to Clojure's core.asyncIntro to Clojure's core.async
Intro to Clojure's core.async
 
Functional Reactive Programming in Clojurescript
Functional Reactive Programming in ClojurescriptFunctional Reactive Programming in Clojurescript
Functional Reactive Programming in Clojurescript
 
Clojure/West 2013 in 30 mins
Clojure/West 2013 in 30 minsClojure/West 2013 in 30 mins
Clojure/West 2013 in 30 mins
 
Clojure Reducers / clj-syd Aug 2012
Clojure Reducers / clj-syd Aug 2012Clojure Reducers / clj-syd Aug 2012
Clojure Reducers / clj-syd Aug 2012
 
The many facets of code reuse in JavaScript
The many facets of code reuse in JavaScriptThe many facets of code reuse in JavaScript
The many facets of code reuse in JavaScript
 
Continuation Passing Style and Macros in Clojure - Jan 2012
Continuation Passing Style and Macros in Clojure - Jan 2012Continuation Passing Style and Macros in Clojure - Jan 2012
Continuation Passing Style and Macros in Clojure - Jan 2012
 
Heroku addons development - Nov 2011
Heroku addons development - Nov 2011Heroku addons development - Nov 2011
Heroku addons development - Nov 2011
 
Clouds against the Floods (RubyConfBR2011)
Clouds against the Floods (RubyConfBR2011) Clouds against the Floods (RubyConfBR2011)
Clouds against the Floods (RubyConfBR2011)
 
Clouds Against the Floods
Clouds Against the FloodsClouds Against the Floods
Clouds Against the Floods
 
Arel in Rails 3
Arel in Rails 3Arel in Rails 3
Arel in Rails 3
 
Testing with Spring
Testing with SpringTesting with Spring
Testing with Spring
 

Programação functional reativa: lidando com código assíncrono

  • 1. Programação Funcional Reativa: Lidando com código assíncrono QCon São Paulo, 2014 Leonardo Borges @leonardo_borges www.leonardoborges.com www.thoughtworks.com
  • 2. Sobre ‣ Consultor Senior na ThoughtWorks Australia ‣ Entusiasta de Programação Functional ‣ Clojure geek ‣ Fundador do Grupo de Usuários Clojure de Sydney ‣ No momento escrevendo o livro “Clojure Reactive Programming”
  • 3. var result = 1;! numbers.forEach(function(n){! if(n % 2 === 0) {! result *= n;! }! });! console.log( result );! // 8! var numbers = [1,2,3,4,5]; Em programação imperativa, descrevemos computações como uma serie de ações que modificam o estado do programa
  • 4. Em programação imperativa, descrevemos computações como uma serie de ações que modificam o estado do programa var result = 1;! numbers.forEach(function(n){! if(n % 2 === 0) {! result *= n;! }! });! console.log( result );! // 8! var numbers = [1,2,3,4,5]; Requer uma variável para armazenar estado
  • 5. var result = 1;! numbers.forEach(function(n){! if(n % 2 === 0) {! result *= n;! }! });! console.log( result );! // 8! var numbers = [1,2,3,4,5]; Iteramos sobre os itens do array Em programação imperativa, descrevemos computações como uma serie de ações que modificam o estado do programa
  • 6. var result = 1;! numbers.forEach(function(n){! if(n % 2 === 0) {! result *= n;! }! });! console.log( result );! // 8! var numbers = [1,2,3,4,5]; E na mesma função filtramos os itens… Em programação imperativa, descrevemos computações como uma serie de ações que modificam o estado do programa
  • 7. var result = 1;! numbers.forEach(function(n){! if(n % 2 === 0) {! result *= n;! }! });! console.log( result );! // 8! var numbers = [1,2,3,4,5]; …e efetuamos a multiplicação. Em programação imperativa, descrevemos computações como uma serie de ações que modificam o estado do programa
  • 8. Já em programação funcional, descrevemos o que queremos fazer e não como queremos fazê-lo var numbers = [1,2,3,4,5]; var result = numbers! .filter(function(n){ return n % 2 === 0; })! .reduce(function(acc, n){! return acc * n;! });! console.log( result );! // 8!
  • 9. Já em programação funcional, descrevemos o que queremos fazer e não como queremos fazê-lo var numbers = [1,2,3,4,5]; var result = numbers! .filter(function(n){ return n % 2 === 0; })! .reduce(function(acc, n){! return acc * n;! });! console.log( result );! // 8! Nenhuma variável necessária para a mesma computação
  • 10. Já em programação funcional, descrevemos o que queremos fazer e não como queremos fazê-lo var numbers = [1,2,3,4,5]; var result = numbers! .filter(function(n){ return n % 2 === 0; })! .reduce(function(acc, n){! return acc * n;! });! console.log( result );! // 8! E temos duas funções que podem ser re-utilizadas de forma independente
  • 11. A programação funcional reativa traz o mesmo princípio para valores com os quais lidamos no dia-a-dia: eventos DOM como clicks, key presses, movimentos do mouse, chamadas Ajax…
  • 12. Antes de definir um pouco mais formalmente o que eh FRP, vamos olhar um exemplo
  • 13. Movimentos em um jogo var JUMP = 38, CROUCH = 40,! LEFT = 37, RIGHT = 39,! FIRE = 32;! ! function goRight (){! $('h1').html("Ir para a direita...");! }! ! function goLeft (){! $('h1').html("Ir para a esquerda...");! }! ! function jump (){! $('h1').html("Pular...");! }! ! function crouch (){! $('h1').html("Abaixar...");! }! ! function fire (){! $('h1').html("Atirar...");! }
  • 14. Movimentos em um jogo: estilo imperativo $(window.document).keyup(function(event){! switch(event.keyCode){! case JUMP :! jump();! break;! case CROUCH:! crouch();! break;! case LEFT :! goLeft();! break;! case RIGHT :! goRight();! break;! case FIRE :! fire();! break;! };! });
  • 15. Temos problemas similares ao exemplo anterior
  • 16. Porém, podemos imaginar que key presses são um stream de teclas
  • 17. Para a versão funcional, utilizaremos o framework de FRP RxJS
  • 18. Movimentos em um jogo: estilo funcional var source = Rx.Observable.fromEvent(window.document, 'keyup'); function isKey (keyCode){! return function(event){! return event.keyCode === keyCode;! };! } source.filter(isKey(FIRE)).subscribe(fire);! source.filter(isKey(JUMP)).subscribe(jump);! source.filter(isKey(CROUCH)).subscribe(crouch);! source.filter(isKey(LEFT)).subscribe(goLeft);! source.filter(isKey(RIGHT)).subscribe(goRight);!
  • 19. Um pouco mais sobre FRP ‣ Criado em 1997 por Conal Elliott na forma do framework Fran para Haskell ‣ Desde então foi implementada em diversas linguagens e frameworks: Rx(.NET| JS|Java), reactive-banana (Haskell), Bacon.js, Elm-lang (compile-to-JS) e outros… ‣ Introduz duas abstrações principais: Behaviors e Events
  • 20. Exemplo de Behavior: posição do cursor do mouse function mouseXYBehavior(){! var behavior = new Rx.BehaviorSubject([0,0]);! $(window.document).mousemove(function(event){! behavior.onNext([event.clientX, event.clientY]);! });! return behavior;! } var xyBehavior = mouseXYBehavior();! xyBehavior.subscribe(function(xy){! $('h1').html('(' + xy[0] + ',' + xy[1] + ')');! });! ! console.log( xyBehavior.value );!
  • 21. Um pouco mais sobre Rx - Rx 101 Rx.Observable.returnValue(42)! .map(function(value){ return value * 2; })! .subscribe(function(value){! console.log( value );! });! ! // 84!
  • 22. Um pouco mais sobre Rx - Rx 101 Rx.Observable.fromArray([10, 20, 30])! .map(function(value){ return value * 2; })! .reduce(function(acc, value){ return acc + value; })! .subscribe(function(value){! console.log( value );! });! ! // 120
  • 23. Um pouco mais sobre Rx - Rx 101 function projectRange(n){! return Rx.Observable.fromArray(_.range(n));! }! ! Rx.Observable.fromArray([1, 2, 3])! .flatMap(projectRange)! .subscribe(function(value){! console.log( value );! });! ! // 0! // 0! // 1! // 0! // 1! // 2
  • 24. ?
  • 26. Rx.Observable.fromArray([1, 2, 3])! .flatMap(projectRange) projectRange(2) 0 1 projectRange(1) 0 projectRange(3) 0 1 2 0 0 1 0 1 2
  • 27. Combinar Observables dessa forma é uma técnica poderosa como veremos mais adiante
  • 29. E comunicação com a rede? ‣ Callback hell :( ‣ Promises melhoram um pouco mas tem limitações ‣ Funcionam bem para um nível de valores ‣ Porém são um mecanismo pobre de composição ‣ E se tivermos uma série de valores que muda ao decorrer do tempo?
  • 30. Exemplo: uma simples aplicação de votos
  • 31. O que queremos: ‣ Mostrar os resultados da pergunta atual ‣ Atualizar os resultados a cada 2 segundos ‣ Se a pergunta atual for a mesma que a pergunta anterior, atualizamos o resultado. Senão: ‣ Paramos com a atualização periódica; ‣ Mostramos uma mensagem de countdown; ‣ Mostramos a pergunta anterior com os resultados; ‣ Reiniciamos a atualização periódica
  • 32. Resultados da parte servidor da aplicação {! id: 1,! question: "Which is the best music style?",! results: {! a: 8,! b: 20,! c: 15! }! }!
  • 34. Primeiro, tornamos os resultados em um Observable 4 3 3 2 1 1
  • 35. Depois, duplicamos o Observable, pulando um elemento 4 3 3 2 1 1 5 4 3 3 2 1 skip(1)
  • 36. Finalmente, zippamos os Observables 4 3 3 2 1 1 5 4 3 3 2 1 zip [5,4] [4,3] [3,3] [3,2] [2,1] [1,1]
  • 37. Agora temos acesso em um único observable a ambos os resultados
  • 39. Recapitulando a idéia principal function resultsObservable () {! return Rx.Observable.create(function(observer){! $.get( "/polls/current/results", function(data) {! observer.onNext(data);! observer.onCompleted();! return function () {! console.log('disposed');! };! });! });! }
  • 40. Recapitulando a idéia principal function resultsConnectable () {! var obs = Rx.Observable! .interval(2000)! .flatMap(resultsObservable)! .publish()! .refCount();! var obs1 = obs.skip(1);! return Rx.Observable.zipArray(obs, obs1);! }! Tornamos os resultados em um Observable
  • 41. Recapitulando a idéia principal function resultsConnectable () {! var obs = Rx.Observable! .interval(2000)! .flatMap(resultsObservable)! .publish()! .refCount();! var obs1 = obs.skip(1);! return Rx.Observable.zipArray(obs, obs1);! }! Duplicamos o mesmo, pulando um elemento
  • 42. Recapitulando a idéia principal function resultsConnectable () {! var obs = Rx.Observable! .interval(2000)! .flatMap(resultsObservable)! .publish()! .refCount();! var obs1 = obs.skip(1);! return Rx.Observable.zipArray(obs, obs1);! }! Finalmente, “zippamos” os Observables
  • 43. Show! Será que existe uma forma mais simples de implementar a mesma funcionalidade? Certamente!
  • 44. A mesma funcionalidade, explorando mais da API de Rx function resultsBuffer () {! return Rx.Observable! .interval(2000)! .flatMap(resultsObservable)! .bufferWithCount(2, 1);! }
  • 45. Explore e entenda a fundo a API do seu framework de FRP favorito: muito provavelmente o que você precisa já foi implementado por alguém
  • 46. Em ambas as soluções, não precisamos de uma variável extra para armazenar a pergunta anterior
  • 47. Pensar de forma funcional e utilizar um framework de FRP nos permite implementar soluções simples e robustas
  • 48. "FRP is about handling time-varying values like they were regular values" - Haskell Wiki (FRP lida com valores que mudam ao decorrer do tempo como se fossem valores regulares)
  • 49. Exemplo bônus: API Reativa para AWS function resourcesStream (stackName) {! return Rx.Observable.create(function(observer){! cloudFormation.describeStackResources({StackName: stackName}, function(err, data){! if (err) {! observer.onError("Error");! observer.onCompleted();! } else {! observer.onNext(data);! observer.onCompleted();! }! });! });! }
  • 50. Exemplo bônus: API Reativa para AWS function ec2InstanceStream (physicalResourceIds) {! return Rx.Observable.create(function(observer){! ec2.describeInstances({InstanceIds: physicalResourceIds}, function (err, data) {! if (err) {! observer.onError("Error");! observer.onCompleted();! } else {! observer.onNext(data);! observer.onCompleted();! }! });! });! }
  • 51. Exemplo bônus: API Reativa para AWS function dbInstanceStream (physicalResourceId) {! return Rx.Observable.create(function(observer){! rds.describeDBInstances({DBInstanceIdentifier: physicalResourceId}, function (err, data) {! if (err) {! observer.onError("Error");! observer.onCompleted();! } else {! observer.onNext(data);! observer.onCompleted();! }! });! });! }
  • 52. Exemplo bônus: API Reativa para AWS resourcesStream('my-stack')! .filter(isEC2)! .map(".PhysicalResourceId")! .reduce([], function(acc, resource) { acc.push(resource); return acc;})! .flatMap(ec2InstanceStream);!
  • 53. Exemplo bônus: API Reativa para AWS var ec2Data = resourcesStream('my-stack')! .filter(isEC2)! .map(".PhysicalResourceId")! .reduce([], function(acc, resource) { acc.push(resource); return acc;})! .flatMap(this.ec2InstanceStream); var rdsData = resourcesStream('my-stack')! .filter(isRDS)! .map(".PhysicalResourceId")! .reduce([], function(acc, resource) { acc.push(resource); return acc;})! .flatMap(dbInstanceStream);!
  • 54. Exemplo bônus: API Reativa para AWS var ec2Data = resourcesStream('my-stack')! .filter(isEC2)! .map(".PhysicalResourceId")! .reduce([], function(acc, resource) { acc.push(resource); return acc;})! .flatMap(this.ec2InstanceStream); var rdsData = resourcesStream('my-stack')! .filter(isRDS)! .map(".PhysicalResourceId")! .reduce([], function(acc, resource) { acc.push(resource); return acc;})! .flatMap(dbInstanceStream);!
  • 55. Exemplo bônus: API Reativa para AWS ec2Data! .merge(rdsData)! .reduce([], function(acc, resource) { acc.push(resource); return acc;});!
  • 56. Simples de entender, manter e testar. FRP #FTW!
  • 58. Referências ‣ Código: https://github.com/leonardoborges/qcon2014-frp-code ! ‣ RxJS: https://github.com/Reactive-Extensions/RxJS ‣ RxJava: https://github.com/Netflix/RxJava ! Outras implementações: ‣ Bacon.js: https://github.com/baconjs/bacon.js ‣ Reactive Banana: http://www.haskell.org/haskellwiki/Reactive-banana ‣ Elm: http://elm-lang.org/