54
RXJAVA PROGRAMAÇÃO REATIVA FUNCIONAL COM UBIRATAN SOARES MARÇO / 2016

Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

Embed Size (px)

Citation preview

Page 1: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

RXJAVAPROGRAMAÇÃO REATIVA FUNCIONAL COM

UBIRATAN SOARESMARÇO / 2016

Page 2: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

MOTIVAÇÃO

Java8 trouxe uma API de Streams, que permite operações comuns sobre coleções como Map, Filter, Reduce

Java9 trará uma API de ReactiveStreams, adotadando muitos conceitos presentes em RxJava diretamente no JDK

Funcional Programming ajuda a escrever código mais robusto e conciso de maneira geral

Page 3: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

ERIK MEIJER

“Do ponto de vista de fluxo de dados, qual a diferença entre consultar o DB e processar as posições do ponteiro do mouse ???”

Page 4: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

VELHOS PROBLEMAS SEMPRE NA MODA

Execução orquestrada de código de forma assíncrona

Execução e sincronização de processamento concorrente

Tratamento de erros

Escalabilidade

Page 5: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

UMA NOVA FORMA DE PENSAR

E se ao invés de buscar dados de forma assíncrona, os dados chegassem até mim de forma assíncrona ?

Reativo : algo que reage a um estímulo !!!

Fundamento matemático : teoria da categorias !!!

Page 6: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

POR QUÊ “REACTIVE PROGRAMMING”

As demandas atuais tipicamente pedem aplicações

Responsivas

Resilientes

Orientadas a eventos

Escaláveis

Page 7: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

HANS DOCKTER

“Programar é arte de encontrar as abstrações corretas”

Page 8: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

RELEITURA DE CONCEITOS

Pensamento em termos de fluxo de dados : eventos discretos e fluxo desses eventos

É possível reagir a eventos e combinar os mesmos

O estado do sistema deve mudar conforme a passagem de eventos no tempo

Eventos no fluxo são imutáveis

Sistema que idealmente nunca bloqueia (I/O, cálculos, etc)

Page 9: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

DADOS E SINCRONICIDADE

Um valor Múltiplos valores

Síncrona T getData( ) Iterable<T> getData( )

Assíncrona Future<T> getData( ) Observable<T> getData( )

Page 10: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

RELEITURA DE CONTRATOS

Iterable<T> Observer<T>

Obter o próximo T next( ) onNext( T )

Sinalizar erro throws Exception( ) onError( Thowable )

Saber se terminou hasNext( ) onComplete( )

PULLED WAY

PUSHED WAY

Page 11: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

CONCEITOS BÁSICOS

OBSERVABLE

OBSERVER

OPERATOR

SCHEDULER

Page 12: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

OBSERVABLE

Representa o fluxo de dados (ou eventos, ou itens emitidos)

Por padrão, executa de forma sequencial (não concorrente)

Repassa cada item emitido para um observador (callback)

Pode ser associado ao conceito de source da Streams API do java8, porém seguindo push model quanto aos dados

Page 13: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

CRIANDO OBSERVABLES (I)

Observable<String> source = Observable.just("GOOGLE", "APPLE", "MICROSOFT");

source.subscribe(System.out::println);

GOOGLEAPPLEMICROSOFT

PROCESS FINISHED WITH EXIT CODE 0

Page 14: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

CRIANDO OBSERVABLES (II)

Observable.fromCallable(() -> “RxJava is Awesome”)

.subscribe(System.out::println);

List<String> names = Arrays.asList("Banana", "Apple", "Orange");

Observable.from(names).subscribe(System.out::println);

Page 15: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

CRIANDO OBSERVABLES (III)

Observable.interval(1, TimeUnit.SECONDS)

.map(time -> "AT SECOND " + time)

.subscribe(System.out::println);

AT SECOND 0AT SECOND 1AT SECOND 2AT SECOND 3…

WARNING : estamos roubando aqui, se você executar esse código, não verá esse log !!!!

Page 16: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

OBSERVER

Consome o fluxo de dados

Respeita o contrato no estilo pushed data

É o ponto no qual os erros flutuam : um erro que aconteça durante uma operação interrompe a sequência de emissões

Callbacks sinalizam o término da sequência

Adições ao Observer Pattern do GOF

Page 17: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

OBSERVER

public interface Observer<T> {

}

void onCompleted();

void onError(Throwable e);

void onNext(T data);

Page 18: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

PIPELINE DE OPERAÇÕES

Observable.from(…)

.flatMap(…)

.filter(…)

.map(…)

.observeOn(…)

.subscribeOn(…)

.subscribe(…);

upstream sequence

downstream sequence

Page 19: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

Observable.zip( restApi.getAvaliableItems(), restApi.getRecommendedItems(clientId),

new ItemsResultsZipper())

.subscribeOn(Schedulers.io())

.observeOn(AndroidSchedulers.mainThread())

.subscribe(new Observer<List<Item>>() { @Override public void onCompleted() { … } @Override public void onError(Throwable e) { … } @Override public void onNext(List<Item> items) { … } });

podemos fazer melhor ?

Page 20: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

OPERADORES

Funções que permitem manipular a sequência de eventos observáveis, sejam os itens emitidos, seja a própria sequência (ou múltiplas delas)

Reactive Extensions define um enorme catálogo de operadores quanto à semântica, em categorias bem definidas

Page 21: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

CATEGORIA OPERADORES

CRIAÇÃO just( ), from( ), range( ), interval( ), defer( ) …

COMBINAÇÃO zip( ), merge( ), combineLatest( ), concat( ) …

TRANSFORMAÇÃO map( ), flatMap( ), concatMap( ) …

FILTRAGEM filter( ), take( ), skip( ), debounce( ) …

MUITO MAIS ! cache( ), replay( ), retry( ), retryWhen( ) …

Page 22: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

MARBLE DIAGRAMS

A B C D E

onNext( ) é chamado cinco vezes

Page 23: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

MARBLE DIAGRAMS

A B C

1 2 3 4 5

x

I

onError( )

onCompleted( )

Page 24: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

MAP

1 2 3 4 5

A B C D E

MAP { INT X -> CHAR Y }

Page 25: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

FILTER

1 2 3 4 5

2 4

FILTER { INT X -> INT Y}

Page 26: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

MERGE

1 3 5

2 4

1 2 3 4 5

MERGE

I

I

I

Page 27: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

CONCAT

1 3 5

2 4

1 3 5 2 4

CONCAT

I

I

I

Page 28: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

AMB

1 3 5

2 4

1 3 5

AMB

I

I

I

Page 29: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

INTERVAL

INTERVAL {🕒}

1 2 3 4 5

🕒 🕒 🕒🕒 🕒

Page 30: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

rxmarbles.comDisponível como app Android

Page 31: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

SCHEDULER

Escalonador de trabalho entre threads distintas

Abstração em volta de Executors ( java.util.concurrent )

Qualquer Observable pode ser produzido em um Scheduler e observado em outro

Mecanismo fundamental para aplicações móveis

Page 32: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

Observable.range(1, 2) .map(i -> i * 2) .observeOn(Schedulers.io()) .doOnNext(i -> System.out.println( "Emitting " + i + " on thread " + threadName())) .observeOn(Schedulers.computation()) .map(i -> i * 10) .subscribe(i -> System.out.println( "Received " + i + " on thread " + threadName()));

Emitting 2 on thread RxCachedThreadScheduler-1Received 20 on thread RxComputationThreadPool-3Emitting 4 on thread RxCachedThreadScheduler-1Received 40 on thread RxComputationThreadPool-3

sleep(3000);

Page 33: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

Observable.just("Google", "Apple", "Microsoft", "IBM") .subscribleOn(Schedulers.computation()) .subscribe(s -> System.out.println( "Received " + s + " on thread " + threadName()));

Received Google on thread RxComputationThreadPool-1Received Apple on thread RxComputationThreadPool-1Received Microsoft on thread RxComputationThreadPool-1Received IBM on thread RxComputationThreadPool-1

sleep(3000);

Page 34: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

NUÂNCIAS SOBRE SCHEDULERS (I)

Schedulers.io( ) encapsula um thread pool de tamanho variável

Schedulers.computation( ) encapsula um thread pool de tamanho fixo

Operam sobre deamon threads

São extensíveis para encapsular threads importantes, como por exemplo a UI thread do Android ou do JavaFX

Alguns factory methods de Observable já associam um scheduler à sequência (como interval( ) )

Page 35: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

NUÂNCIAS SOBRE SCHEDULERS (II)

subscribeOn( ) instrui o framework sobre em qual thread os itens serão emitidos para o consumidor

observeOn( ) instrui o framework sobre quais schedulers podem operar nas etapas intermediárias do pipeline de operações

subscribeOn( ) em geral é usado uma vez no pipeline

observeOn( ) é utilizado conforme a necesside de concorrência nas etapas do pipeline

Page 36: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

TRATAMENTO DE ERROS

Evento terminal destrói a sequência. Period.

Recuperação controlada via operadores onErrorResumeNext( ), onErrorReturn( ) e outros

Sugestão : implemente um wrapper com o retorno de onError( throwable), isso ajudará no stacktrace em casos de erro

Page 37: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

CONCEITOS AVANÇADOS

Page 38: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

FLATMAP

"Transform the items emitted by an Observable into Observables, then flatten the emissions from those into a single Observable

The FlatMap operator transforms an Observable by applying a function that you specify to each item emitted by the source Observable, where that function returns an Observable that itself emits items. FlatMap then merges the emissions of these resulting Observables, emitting these merged results as its own sequence.

This method is useful, for example, when you have an Observable that emits a series of items that themselves have Observable members or are in other ways transformable into Observables, so that you can create a new Observable that emits the complete collection of items emitted by the sub-Observables of these items. "

Page 39: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR
Page 40: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

FLATTENING

MAPPING

Page 41: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

List<String> companies = Arrays.asList("Google", "Apple", "Microsoft");

List<String> leaders = Arrays.asList("Larry", "Steve", "Bill");

Observable<List<String>> obs = Observable.just(companies, leaders);

Observable<String> flat = obs.flatMap(strings -> Observable.from(strings));

flat.subscribe(System.out::println);

GoogleAppleMicrosoftLarrySteveBill

flatMap( ) desmontou 2 sequências de items e juntou individualmente os itens de cada sequência em uma única sequência final

mapeamento

Page 42: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

MAIS SOBRE FLATMAP

flatmap( ) é o mecanismo padrão para encadeamento de operações assíncronas

flatmap( ) não garante a ordem dos itens emitidos na sequência gerada final; se a ordem dos itens for importante, usar concatMap( )

Page 43: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

TRANSFORMERS

Aplicáveis através do operador compose( )

Manipulam a sequência como um todo, ideais para evitar repetições de código em etapas comuns do pipeline

Casos comuns : setup de schedulers, composição de filtros, etc

Page 44: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

restApi.callMethod01() .subscribleOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(…);

restApi.callMethod02() .subscribleOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(…);

PODEMOS FAZER MELHOR !!!

Page 45: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

public static <T> Observable.Transformer<T, T> applySchedulers() { return observable ->

observable.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); }

restApi.callMethod01() .compose(Transformers.applySchedulers() ) .subscribe(…);

restApi.callMethod02() .compose(Transformers.applySchedulers() ) .subscribe(…);

Page 46: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

HOT AND COLD OBSERVABLES

Hot Observables começam a emitir itens no momento em que são criados

Cold Observables começam a emitir itens no momento em que são observados

Hot Observables são passíveis de perda de emissões

Cold Observables podem produzir side-effects

Alguns operadores transformam a temperatura da sequência

Page 47: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

BACKPRESSURE

Cenário no qual a sequência observável (produtor) emite mais itens do que o observador (consumidor) consegue processar

Menos provável em sequências de itens de natureza estritamente computacional

Mais provável em sequências sendo geradas por IO

Page 48: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

LIDANDO COM BACKPRESSURE

Dois tipos de cenário, de acordo com a natureza dos itens emitidos

Perda de emissões implica em perda de informação

Perda de emissões não implica perda de informação

Page 49: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

BACKPRESSURE COM PERDA DE DADOS

Estratégia : diminuir a quantidade de dados que chegam até o consumidor segundo alguma heurística de perda

Diversos operadores disponíveis : sample( ), debounce( ), throttleFirst( ), etc

Page 50: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

BACKPRESSURE SEM PERDA DE DADOS

Duas estratégias imediatas

(i) Bufferizar dados para processamento posterior, com operadores como cache( ), buffer( ), window( ) etc

(ii) Informar a upstream sequence que é preciso diminuir o ritmo na emissão de itens, usando Producer API

Page 51: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

RXJAVA VS JAVA8 STREAMS (I)

Streams são desenhadas para processamento computacional, in-memory e com fácil paralelização

Streams trazem Collectors API para melhor semântica de agrupamentos

Streams pode adaptar sources através de Spliterators API

Streams operam estritamente em pull mode, eg, não baseado em callbacks

Não há backpressure

Page 52: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

RXJAVA VS JAVA8 STREAMS (II)

RxJava opera essencialmente em push mode, eg, baseado em callbacks

RxJava contém a noção de tempo na API, permitindo inclusive sincronização de eventos no tempo

RxJava oferece controle fino sobre concorrência via Schedulers

RxJava é desenhada tanto para uso de processamento computacional quanto para IO

RxJava tende a ser mais burocrática que Streams para processamento computacional tipo map/filter/collect/reduce

Page 53: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

PROBLEMAS COM RXJAVA

Debugging pode ser difícil (stacktraces gigantescos)

Verbosidade (Java 6,7)

Curva de aprendizado : muitos conceitos, em geral complexos

Page 54: Ubiratan Soares - Programação reativa funcional com RXJava - #JavaOneBR #oowBR

OBRIGADOTHAT`S ALL FOLKS !!!

@ubiratanfsoares

speakerdeck.com/ubiratansoaresubiratansoares.github.io