65
EVOLUINDO ARQUITETURAS REATIVAS Ubiratan Soares QCONSP / 2017

EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

  • Upload
    others

  • View
    17

  • Download
    0

Embed Size (px)

Citation preview

Page 1: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

EVOLUINDO ARQUITETURAS

REATIVASUbiratan Soares QCONSP / 2017

Page 2: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

O QUE É UMA ARQUITETURA EM

MOBILE ?

Page 3: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

MVP

MVVMVIPER

FLUX REDUX

CLEAN

MVC…

MVI

Page 4: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento
Page 5: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

PRINCÍPIOS DE ARQUITETURAOrganização

Facilidade em se encontrar o que se precisa

Menor impedância para se resolver bugs

Menos dor ao escalar em tamanho (codebase e devs)

Estilo de projeto unificado, definido e defendido pelo time

Page 6: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

MOBILE CHALLENGESInterações com usuário e eventos de sistema são assíncronos

I/O deve ser concorrente

Processamento pesado deve ser concorrente

Fragmentação de plataformas

ETC….

Page 7: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

UMA QUEIXA COMUM NA COMUNIDADE

MOBILE ?

Page 8: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

TEM PELO MENOS UM UNIT TEST NO APP?

Page 9: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

EM MOBILE, ARQUITETURA É CRÍTICA

PARA TESTABILIDADE

Page 10: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

QUAL ARQUITETURA ESCOLHER ENTÃO ???

Page 11: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento
Page 12: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento
Page 13: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento
Page 14: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento
Page 15: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

MIXED FEELINGS

Page 16: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento
Page 17: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

NÃO HÁ SILVER BULLETS!

Page 18: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

MODEL VIEW

PRESENTER

Page 19: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

PRESENTATION LAYER

DATA LAYER

DB

REST

ETC

UI

. . .

Page 20: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento
Page 21: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

public interface ViewDelegate {

void displayResults(DataModel model);

void networkingError();

void displayEmptyState();

void displayErrorState();

// More delegation }

Page 22: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

public class MainActivity extends AppCompatActivity implements ViewDelegate {

Presenter presenter; // How to resolve this instance ???

@Override protected void onStart() { super.onStart(); presenter.bindView(this); presenter.fetchData(); }

@Override public void displayResults(DataModel model) { // Put data into view }

@Override public void networkingError() { // Up to you }

@Override public void displayEmptyState() { // And this too! }

@Override public void displayErrorState() { // Please, do not mess with your user } }

Page 23: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

public class Presenter {

public void bindView(ViewDelegate delegate) { this.delegate = delegate; }

public void fetchData() { source.fetchData(new DataSource.Callback() {

@Override public void onDataLoaded(DataModel model) { delegate.displayResults(model); }

@Override public void onError(Throwable t) {

if (t instanceof NetworkingError) { delegate.networkingError(); } else if (t instanceof NoDataAvailable) { … } } }); } }

Page 24: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

DATASOURCE

REST GATEWAY

PRESENTER

VIEW DELEGATION CALLBACKS

PLATAFORM CONTROLLER

CALLBACKUNIT TESTS

(Mocked Contract)

FUNCTIONAL UI TESTS INTEGRATION TESTS

INTEGRATION TESTS (DOUBLES)

UNIT TESTS (Mocked Source

+ Mocked View)DA

TAM

ODE

L

Page 25: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

String description = “Blah” String date = “2010-02-26T19:35:24Z” int step = 2

String description = “Blah” LocalDateTime dateTime = (JSR310) TrackingStep currentStep = (enum)

String description = “Blah” String formattedDate = “26/02/2010” String currentStep = “Concluído”

Response Model

Domain Model

View Model

DATA MODEL

Page 26: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

PROBLEMAS EM POTENCIALQual representação de dados utilizar? Unificada ou separada?

Onde aplicar parsing? E formatação para a UI?

Callbacks aninhados

Memory leaks no nível do mecanismo de entrega

Etc

Page 27: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

BRACE YOURSELVES

RX IS COMING

Page 28: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

THE RXJAVA REVOLUTIONRxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais

Threading transparente

Tratamento unificado de erros via adição ao Observer Pattern

Battle-tested

Page 29: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

COMO ADICIONAR RX

NESSA ARQUITETURA ??

Page 30: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

PRESENTATION LAYER

DATA LAYER

DB

REST

ETC

UI

. . .

Callback(T)Callback(T) Callback(T)

Page 31: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

SUBSTITUIR CALLBACKS POR SEQUÊNCIAS OBSERVÁVEIS

Page 32: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

PRIMEIRA INTERAÇÃO

CAMADA DE DADOS REATIVA

Page 33: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

REST GATEWAY

VIEW DELEGATION

VIEW

DATA SOURCE

Observable<T>

PRESENTER

Callback(T)

OBSERVER<T>

Page 34: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

public interface HelpDeskEventsSource {

Observable<HelpDeskEvent> fetchWith(MessagesForOrderParameters params);

Observable<HelpDeskEvent> sendMessage(MessageToSellerParameters params);

Observable<HelpDeskEvent> requireMediation(MediationParameters params);

}

ADEUS CALLBACKS !!!👌

Page 35: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

public class HelpDeskStreamInfrastructure implements HelpDeskEventsSource {

@Override public Observable<HelpDeskEvent> fetchWith(MessagesForOrderParameters params) { return restAPI.getHelpDeskTickets(params) .subscribeOn(Schedulers.io()) .map(HelpDeskPayloadMapper::map) .filter(Preconditions::notNullOrEmpty) .flatMap(Observable::from); }

@Override public Observable<HelpDeskEvent> sendMessage(MessageToSellerParameters params) { MessageToSellerBody body = SendMessageToSellerBodyMapper.convert(params);

return restAPI.sendHelpdeskMessageToSeller(body) .subscribeOn(Schedulers.io()) .flatMap(emptyBody -> fetchWith(sameFromSeller(params))); }

} Chained request, easy !!!!

Page 36: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

VANTAGENS OBSERVADASFacilidades via frameworks utilitários para REST / DB

Validação de dados de entrada e tradução de modelos como etapas do pipeline

Tratamento de erros, auto retry, exponential backoff no “baixo nível”

Page 37: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

PROBLEMAS OBSERVADOSConsumir os dados no nível da apresentação nos força a rodar comportamentos na thread principal do app (orquestração dos callbacks)

Indireção forçada para prover Scheduler via DI, para propósitos de testes

Muitas responsabilidades no Presenter

Page 38: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

SEGUNDA INTERAÇÃO

CAMADA DE APRESENTAÇÃO REATIVA

Page 39: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

REST GATEWAY

VIEW DELEGATION

VIEW

DATA SOURCE

Observable<T>

PRESENTER

OBSERVER<T>

Observable<T>

SUBSCRIPTION

Page 40: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

public interface SomeView<T> {

Func1<Observable<T>, Subscription> results();

Func1<Observable<Unit>, Subscription> showEmptyState();

Func1<Observable<Unit>, Subscription> hideEmptyState();

Func1<Observable<Unit>, Subscription> showLoading();

Func1<Observable<Unit>, Subscription> hideLoading();

// More delegation }

Page 41: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

public static <T> Subscription bind(Observable<T> observable, Func1<Observable<T>, Subscription> uiFunc) { return uiFunc.call(observable); }

public static <T> Func1<Observable<T>, Subscription> uiFunction(Action1<T> uiAction) { return uiFunction(uiAction, () -> {}); }

public static <T> Func1<Observable<T>, Subscription> uiFunction(Action1<T> uiAction, Action0 done) {

return observable -> observable .observeOn(AndroidSchedulers.mainThread()) .subscribe( uiAction, throwable -> Logger.e(throwable.getMessage()), done ); }

Page 42: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

public static <T> Subscription bind(Observable<T> observable, Func1<Observable<T>, Subscription> uiFunc) { return uiFunc.call(observable); }

public static <T> Func1<Observable<T>, Subscription> uiFunction(Action1<T> uiAction) { return uiFunction(uiAction, () -> {}); }

public static <T> Func1<Observable<T>, Subscription> uiFunction(Action1<T> uiAction, Action0 done) {

return observable -> observable .observeOn(AndroidSchedulers.mainThread()) .subscribe( uiAction, throwable -> Logger.e(throwable.getMessage()), done ); }

Page 43: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

public static <T> Subscription bind(Observable<T> observable, Func1<Observable<T>, Subscription> uiFunc) { return uiFunc.call(observable); }

public static <T> Func1<Observable<T>, Subscription> uiFunction(Action1<T> uiAction) { return uiFunction(uiAction, () -> {}); }

public static <T> Func1<Observable<T>, Subscription> uiFunction(Action1<T> uiAction, Action0 done) {

return observable -> observable .observeOn(AndroidSchedulers.mainThread()) .subscribe( uiAction, throwable -> Logger.e(throwable.getMessage()), done ); }

Page 44: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

public class HelpDeskMessagingActivity extends BaseActivity implements HelpDeskMessagesStreamView {

@Override public Func1<Observable<String>, Subscription> restoreNotSentMessage() { return uiFunction(message -> { Toast.makeText(this, "Erro ao enviar mensagem", LENGTH_SHORT).show(); messageInput.setText(message); }); }

@Override public Func1<Observable<Unit>, Subscription> enableComplaintOption() { return uiFunction(action -> complaintButton.setVisibility(VISIBLE)); }

@Override public Func1<Observable<Unit>, Subscription> disableComplaintOption() { return uiFunction(action -> complaintButton.setVisibility(GONE)); }

@Override public Func1<Observable<Unit>, Subscription> showEmptyState() { return uiFunction(action -> emptyStateContainer.setVisibility(VISIBLE)); }

// More delegate methods

Page 45: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

public class HelpDeskMessagingActivity extends BaseActivity implements HelpDeskMessagesStreamView {

@Override public Func1<Observable<String>, Subscription> restoreNotSentMessage() { return uiFunction(message -> { Toast.makeText(this, "Erro ao enviar mensagem", LENGTH_SHORT).show(); messageInput.setText(message); }); }

@Override public Func1<Observable<Unit>, Subscription> enableComplaintOption() { return uiFunction(action -> complaintButton.setVisibility(VISIBLE)); }

@Override public Func1<Observable<Unit>, Subscription> disableComplaintOption() { return uiFunction(action -> complaintButton.setVisibility(GONE)); }

@Override public Func1<Observable<Unit>, Subscription> showEmptyState() { return uiFunction(action -> emptyStateContainer.setVisibility(VISIBLE)); }

// More delegate methods

Page 46: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

public void userRequiredMediation(String productId, String sellerId) {

MediationParameters parameters = new RequiredMediationParameters.Builder() .productId(productId)

// … .sellerId(sellerId) .build();

executionPipeline(parameters); }

private void executionPipeline(MediationParameters parameters) {

Observable<HelpDeskEventViewModel> execution = source.requireMediation(parameters) .doOnSubscribe(this::prepareToLoad) .map(ViewModelMappers::map) .flatMap(Observable::from) .doOnCompleted(this::finishLoadingMessages);

subscription().add(bind(execution, view().onMessagesLoaded()));

}

PRESENTER LEVEL

Page 47: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

VANTAGENS OBSERVADASPresenter não precisa da noção de threading

Possibilidade de combinação de múltiplas fontes de forma organizada

Presenter passar a orquestrar a UI através de um pipeline de execução bem definido

Tradução de ViewModels é uma etapa do pipeline

Page 48: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

PROBLEMAS OBSERVADOSProtocolo View ainda estava gordo

“Repetição” de código entre Presenters, normalmente relacionada a comportamentos de UI similares

- Mostrar empty state se não houver dados

- Mostrar loading ao iniciar operação; esconder ao terminar

- Controlar interação com Pull-to-refresh

- Estado de erro no caso de problemas, caso não exista conteúdo

- Vários outros

Page 49: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

TERCEIRA INTERAÇÃO

REACTIVE VIEW SEGREGATION

Page 50: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

public interface SomeView<T> {

Func1<Observable<T>, Subscription> results();

Func1<Observable<Unit>, Subscription> showEmptyState();

Func1<Observable<Unit>, Subscription> hideEmptyState();

Func1<Observable<Unit>, Subscription> showLoading();

Func1<Observable<Unit>, Subscription> hideLoading();

Func1<Observable<Unit>, Subscription> networkError();

Func1<Observable<Unit>, Subscription> networkUnavailable();

Func1<Observable<Unit>, Subscription> networkSlow(); }

Page 51: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

UI BEHAVIOR

VIEW PROTOCOL

UI BEHAVIOR UI BEHAVIOR

UI BEHAVIOR . . .

Page 52: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

public interface EmptyStateView<T> {

Func1<Observable<Unit>, Subscription> showEmptyState();

Func1<Observable<Unit>, Subscription> hideEmptyState(); }

public interface LoadingView<T> {

Func1<Observable<Unit>, Subscription> showLoading();

Func1<Observable<Unit>, Subscription> hideLoading(); }

Page 53: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

public interface SomeView<T> extends LoadingView, EmptyStateView, NetworkingReporterView {

Func1<Observable<T>, Subscription> displayResults(); }

public interface NetworkingReporterView<T> {

Func1<Observable<Unit>, Subscription> networkError();

Func1<Observable<Unit>, Subscription> networkUnavailable();

Func1<Observable<Unit>, Subscription> networkSlow(); }

Page 54: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

- Cada comportamento poderia ter o seu “mini-presenter” associado, e o Presenter “grande” faria a orquestração dos colaboradores

- Melhor estratégia : fazer a composição ser uma etapa do pipeline !!!

Page 55: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

f(g(x))

Page 56: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

public class LoadingWhileProcessing<T> implements Observable.Transformer<T, T> {

private PublishSubject<Unit> show, hide = PublishSubject.create();

public Subscription bindLoadingContent(LoadingView view) { CompositeSubscription composite = new CompositeSubscription(); composite.add(bind(show, view.showLoading())); composite.add(bind(hide, view.hideLoading())); return composite; }

@Override public Observable<T> call(Observable<T> upstream) { return upstream .doOnSubscribe(this::showLoading) .doOnTerminate(this::hideLoading); }

private void hideLoading() { hide.onNext(Unit.instance()); }

private void showLoading() { show.onNext(Unit.instance()); } }

Page 57: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

public class OrdersHistoryPresenter extends ReactivePresenter<OrdersHistoryView> {

// Binding all behaviors on view [ ... ]

public void fetchOrders(SearchCriteria criteria) { bind(executionPipeline(criteria), view().displayOrders()); }

private Observable<OrderHistoryType> executionPipeline(SearchCriteria criteria) {

return source.search(criteria) .compose(networkErrorFeedback) .compose(loadingWhenProcessing) .compose(coordinateRefresh) .compose(emptyStateWhenMissingData) .compose(errorWhenProblems) .map(OrdersHistoryViewModelMapper::map); } }

Page 58: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

@Test public void shouldTransformView_RegardlessEmptyStream() {

// When stream has no data Observable<String> stream = Observable.empty();

// and we add transformation to pipeline stream.compose(loadingWhileProcessing) .subscribe( s -> {}, throwable -> {}, () -> {} );

// we should interact with view, anyway verify(view.showLoadingAction).call(uiMethod()); verify(view.hideLoadingAction).call(uiMethod()); }

Page 59: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

VANTAGENSCada evento delegado para a UI agora é unit-testable de uma forma muito fácil !!!

Presenters apenas orquestram a UI (como prega MVP)

Presenter não liga para qual tipo de View está associado

Transformers são facilmente reutilizáveis

Page 60: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

PROBLEMAS ENCONTRADOS (I)1) Boilerplate para o binding de comportamentos

@Override public void bind(OrdersHistoryView view) { super.bind(view); subscription().add(loadingWhileProcessing.bindLoadingContent(view)); subscription().add(networkErrorFeedback.bindNetworkingReporter(view)); subscription().add(coordinateRefresh.bindRefreshableView(view)); subscription().add(emptyStateWhenMissingData.bindEmptyStateView(view)); subscription().add(errorStateWhenProblem.bindErrorStateView(view)); }

✔ Possível solução (WIP) : ViewBinder

Page 61: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

PROBLEMAS ENCONTRADOS (II)2) Comportamentos injetados via DI no Presenter; possível confusão ao fazer pull das dependências

✔ Possível solução (WIP) : ViewBinder fornecido via DI + configuração definida na apresentação

3) Cooperação entre comportamentos ✔ Possível solução (WIP) : Transformers agregadores

Page 62: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

CONCLUSÕES

Page 63: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

LIÇÕES APRENDIDASEscolher um modelo de arquitetura não é uma tarefa trivial

Evoluir um modelo para obter vantagens de um paradigma (FRP) é ainda menos trivial

Não tenha medo de errar; adote iterações na evolução da arquitetura

Esforço se paga no médio prazo

Page 64: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

https://speakerdeck.com/ubiratansoares/evoluindo-arquiteturas-reativas

Page 65: EVOLUINDO ARQUITETURAS REATIVAS - QConSP · RxJava permite operações assíncronas em um estilo síncrono, turbinadas por operadores funcionais Threading transparente Tratamento

OBRIGADO@ubiratanfsoares

ubiratansoares.github.io

https://br.linkedin.com/in/ubiratanfsoares