SlideShare a Scribd company logo
Reactive
Frustrations
Futurice & upday
@tpolansk
Tomek Polanski
The Stages of Rx
@tpolansk
The Amazement
@tpolansk
0 – 4 months
The Frustration
@tpolansk
4 months – 1 year
Cautious Optimism
@tpolansk
1 year – 3+ years
Anonymous class
@tpolansk
button.setListener(
new OnClickListener() {
@Override
public void onClick(View v) {
println(“Hi”);
}
});
@tpolansk
button.setListener(v -> println(“Hi”));
@tpolansk
Forgetting to
subscribe
@tpolansk
just(“Will this work?”)
.doOnNext(text -> println(text))
.subscribe(…)
@tpolansk
How Do Observables
Behave?
@tpolansk
combineLatest(first,
second,
(f, s) -> f + s)
.doOnNext(value -> println(value))
@tpolansk
first
second
println(value)
.…
concat(first, second)
.doOnNext(value -> println(value))
@tpolansk
first second
println(value)
Observable<…> getValue()
Observable<…> getValueOnce()
Observable<…> getValueStream()
Observable<…> getValueOnceAndStream()
@tpolansk
combineLatest(firstOnce,
secondOnceAndStream,
(f, s) -> f + s)
.doOnNext(value -> println(value))
@tpolansk
firstOnce
secondOnceAndStream
concat(firstOnce, secondStream)
.doOnNext(value -> println(value))
@tpolansk
firstOnce secondStream
Too Many Events
@tpolansk
Observable<R> x(Func1<T, Observable<R>>
func)
@tpolansk
Func1< >
func
TObservable<R> Observable<R>
flatMap, switchMap and concatMapflatMap switchMap concatMap
Crashing Errors
@tpolansk
getCountStream()
.subscribe(count -> println(count)
@tpolansk
),
error -> println(error))
Costly subscribe
@tpolansk
@tpolansk
create(subscriber -> subscriber.onNext(1))
.map(val -> val + 1)
.filter(val -> val % 2 == 0)
create
map
filter
subscriber -> subscriber.onNext(1)
val -> val + 1
val -> val % 2 == 0
.subscribe(val -> println(val))
just(blockingFunc())
@tpolansk
fromCallable(() -> blockingFunc())
just blockingFunc()
fromCallable () -> blockingFunc()
Observable<…> obs =
fromCallable(() -> expensiveFunc())
@tpolansk
expensiveFunc()
obs.subscribe(…)
obs.subscribe(…)
1x2x
Wrong Threads
@tpolansk
@tpolansk
create(subscriber -> subscriber.onNext(1))subscriber -> subscriber.onNext(1)
.subscribeOn(…).subscribeOn(…)
.observeOn(…)
.map(val -> val + 1)
Confusing zip
@tpolansk
Side-effects with
debounce
@tpolansk
Leaking
Subscriptions
@tpolansk
Subscription s = getCountStream()
.subscribe(…)
@tpolansk
subscribe
Subscription s
…
s
s.unsubscribe()
Logging Wrong Events
@tpolansk
getCountStream()
@tpolansk
.doOnNext(count -> println(count)).doOnNext(count -> println(count))
.doOnEach(notify -> println(notify))
The Conclusion
@tpolansk
No More Thread
Synchronization
+
Transforming Async
Events
@tpolansk
Can Make Application
Truly Reactive
@tpolansk
Rx Is Just a Tool
@tpolansk
Don’t Be Dogmatic
@tpolansk
Questions, Feedback
&
Frustrations
@tpolansk

More Related Content

Viewers also liked

Nove polozhennya pro_navchalni_kabineti_pri_mat_disciplin_1
Nove polozhennya pro_navchalni_kabineti_pri_mat_disciplin_1Nove polozhennya pro_navchalni_kabineti_pri_mat_disciplin_1
Nove polozhennya pro_navchalni_kabineti_pri_mat_disciplin_1
tan4ikbah
 
Board
BoardBoard
Board
lifaens
 
2014_09_21_ABOUT-SKY-SERVICES_V3
2014_09_21_ABOUT-SKY-SERVICES_V32014_09_21_ABOUT-SKY-SERVICES_V3
2014_09_21_ABOUT-SKY-SERVICES_V3
Vladimer Svanadze
 
Azalea gardens
Azalea gardens Azalea gardens
Azalea gardens
abanyanresidence
 
ASCH-EN ESPERIMENTUA
ASCH-EN ESPERIMENTUAASCH-EN ESPERIMENTUA
ASCH-EN ESPERIMENTUA
maiderfer
 
Олішевський Микола
Олішевський МиколаОлішевський Микола
Олішевський Микола
tan4ikbah
 
Bollardscan PPT 2016
Bollardscan PPT 2016Bollardscan PPT 2016
Bollardscan PPT 2016
Marc Cleophas
 
The BIG BOSS TURKEY
The BIG BOSS TURKEYThe BIG BOSS TURKEY
The BIG BOSS TURKEY
TAYFUN BIRAKOĞLU
 
Saku Tuna
Saku TunaSaku Tuna
Saku Tuna
Marie JS
 
Critical Thinking A Habit of Mind
Critical Thinking A Habit of MindCritical Thinking A Habit of Mind
Critical Thinking A Habit of Mind
Nancy Wozniak
 

Viewers also liked (10)

Nove polozhennya pro_navchalni_kabineti_pri_mat_disciplin_1
Nove polozhennya pro_navchalni_kabineti_pri_mat_disciplin_1Nove polozhennya pro_navchalni_kabineti_pri_mat_disciplin_1
Nove polozhennya pro_navchalni_kabineti_pri_mat_disciplin_1
 
Board
BoardBoard
Board
 
2014_09_21_ABOUT-SKY-SERVICES_V3
2014_09_21_ABOUT-SKY-SERVICES_V32014_09_21_ABOUT-SKY-SERVICES_V3
2014_09_21_ABOUT-SKY-SERVICES_V3
 
Azalea gardens
Azalea gardens Azalea gardens
Azalea gardens
 
ASCH-EN ESPERIMENTUA
ASCH-EN ESPERIMENTUAASCH-EN ESPERIMENTUA
ASCH-EN ESPERIMENTUA
 
Олішевський Микола
Олішевський МиколаОлішевський Микола
Олішевський Микола
 
Bollardscan PPT 2016
Bollardscan PPT 2016Bollardscan PPT 2016
Bollardscan PPT 2016
 
The BIG BOSS TURKEY
The BIG BOSS TURKEYThe BIG BOSS TURKEY
The BIG BOSS TURKEY
 
Saku Tuna
Saku TunaSaku Tuna
Saku Tuna
 
Critical Thinking A Habit of Mind
Critical Thinking A Habit of MindCritical Thinking A Habit of Mind
Critical Thinking A Habit of Mind
 

Recently uploaded

Infrastructure Challenges in Scaling RAG with Custom AI models
Infrastructure Challenges in Scaling RAG with Custom AI modelsInfrastructure Challenges in Scaling RAG with Custom AI models
Infrastructure Challenges in Scaling RAG with Custom AI models
Zilliz
 
Video Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the FutureVideo Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the Future
Alpen-Adria-Universität
 
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
Neo4j
 
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
Neo4j
 
GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024
GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024
GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024
Neo4j
 
Pushing the limits of ePRTC: 100ns holdover for 100 days
Pushing the limits of ePRTC: 100ns holdover for 100 daysPushing the limits of ePRTC: 100ns holdover for 100 days
Pushing the limits of ePRTC: 100ns holdover for 100 days
Adtran
 
AI 101: An Introduction to the Basics and Impact of Artificial Intelligence
AI 101: An Introduction to the Basics and Impact of Artificial IntelligenceAI 101: An Introduction to the Basics and Impact of Artificial Intelligence
AI 101: An Introduction to the Basics and Impact of Artificial Intelligence
IndexBug
 
Building Production Ready Search Pipelines with Spark and Milvus
Building Production Ready Search Pipelines with Spark and MilvusBuilding Production Ready Search Pipelines with Spark and Milvus
Building Production Ready Search Pipelines with Spark and Milvus
Zilliz
 
UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5
DianaGray10
 
National Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practicesNational Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practices
Quotidiano Piemontese
 
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
SOFTTECHHUB
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
Safe Software
 
“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...
“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...
“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...
Edge AI and Vision Alliance
 
Serial Arm Control in Real Time Presentation
Serial Arm Control in Real Time PresentationSerial Arm Control in Real Time Presentation
Serial Arm Control in Real Time Presentation
tolgahangng
 
How to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For FlutterHow to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For Flutter
Daiki Mogmet Ito
 
Full-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalizationFull-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalization
Zilliz
 
Driving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success StoryDriving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success Story
Safe Software
 
Mariano G Tinti - Decoding SpaceX
Mariano G Tinti - Decoding SpaceXMariano G Tinti - Decoding SpaceX
Mariano G Tinti - Decoding SpaceX
Mariano Tinti
 
20240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 202420240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 2024
Matthew Sinclair
 
“I’m still / I’m still / Chaining from the Block”
“I’m still / I’m still / Chaining from the Block”“I’m still / I’m still / Chaining from the Block”
“I’m still / I’m still / Chaining from the Block”
Claudio Di Ciccio
 

Recently uploaded (20)

Infrastructure Challenges in Scaling RAG with Custom AI models
Infrastructure Challenges in Scaling RAG with Custom AI modelsInfrastructure Challenges in Scaling RAG with Custom AI models
Infrastructure Challenges in Scaling RAG with Custom AI models
 
Video Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the FutureVideo Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the Future
 
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
 
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
 
GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024
GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024
GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024
 
Pushing the limits of ePRTC: 100ns holdover for 100 days
Pushing the limits of ePRTC: 100ns holdover for 100 daysPushing the limits of ePRTC: 100ns holdover for 100 days
Pushing the limits of ePRTC: 100ns holdover for 100 days
 
AI 101: An Introduction to the Basics and Impact of Artificial Intelligence
AI 101: An Introduction to the Basics and Impact of Artificial IntelligenceAI 101: An Introduction to the Basics and Impact of Artificial Intelligence
AI 101: An Introduction to the Basics and Impact of Artificial Intelligence
 
Building Production Ready Search Pipelines with Spark and Milvus
Building Production Ready Search Pipelines with Spark and MilvusBuilding Production Ready Search Pipelines with Spark and Milvus
Building Production Ready Search Pipelines with Spark and Milvus
 
UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5
 
National Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practicesNational Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practices
 
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
 
“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...
“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...
“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...
 
Serial Arm Control in Real Time Presentation
Serial Arm Control in Real Time PresentationSerial Arm Control in Real Time Presentation
Serial Arm Control in Real Time Presentation
 
How to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For FlutterHow to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For Flutter
 
Full-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalizationFull-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalization
 
Driving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success StoryDriving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success Story
 
Mariano G Tinti - Decoding SpaceX
Mariano G Tinti - Decoding SpaceXMariano G Tinti - Decoding SpaceX
Mariano G Tinti - Decoding SpaceX
 
20240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 202420240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 2024
 
“I’m still / I’m still / Chaining from the Block”
“I’m still / I’m still / Chaining from the Block”“I’m still / I’m still / Chaining from the Block”
“I’m still / I’m still / Chaining from the Block”
 

Reactive Frustrations

Editor's Notes

  1. Today I would like to talk about frustrations. We developers have those on daily basis, The API doesn’t work properly, somebody’s horrible code ended up in the repo, or just the application has some mysterious issues. We have then the need to talk about those frustration. Sometimes we talk to other developers, sometimes we talk to rubber animals. But this practice is not meaningless, either we figure out a solution to our problem or we prevent others from repeating ours mistakes. So what does Rx have to do with it. In recent year there we loads or articles and talks saying how great Rx is, but is not always rainbows and unicorns, it has some bad sides as well. Today I won’t focus on the Unicorns, but rather I would like to talk about some frustrating things about Rx.
  2. Still the frustrations are not always the same. As you discover Rx, things that annoy you, change. What I’ve experienced, there are three stages of using Rx But before I continue with the stages, could I ask you some questions? - people who read anything about Rx - people who wrote any code in Rx - who have written any production code in Rx - who have 1+ years of experience in Rx
  3. I remember the first day I've been introduced to Rx. A colleague mine, Olli, was playing with something called Reactive Extensions on his free time. He wanted to show us an example of auto-suggestion field. Autosuggestion field is not the most interesting thing in a world, but most of the Olli know what he was talking about, so we joined the presentation. I’ve expected the talk to be about an hour, and at the end we would have an overview how we should write autosuggestion field. The talk turned into a 15-minute presentation with a working code at the end. I’ve started to use Rx in my projects. It was amazing.
  4. As our project grew bigger - it started to behave in a more unpredictable way. Started to crash randomly, backpressure exceptions were occurring, it wasn't performing so well even though I thought I've put everything on background threads, or so we thought. The biggest issue was that I was not able to reason about the code. By reasoning about code, I mean just by looking at a block of code you exactly know how it will behave. Sometimes I even missed the good old, not reactive days. Developers know that when using library/framework/tool you not only need to know it's API, or interface. You need to know how it works under the hood. That’s what we did.
  5. So we’ve learned how Rx works. Next we’ve removed side-effects from observables, kept them clean, we’ve remembered to schedule tasks properly on background threads. We’ve made the application maintainable again. Not only that, adding new features started to be easier and faster. Code became more and more testable. All of this mainly because because we were able to write code that we could reason about. Still, there are moments when the code does not work like intended but most of the time they are either easy ways to solve or investigate it. So let’s go frustrations that we’ve encountered.
  6. We all know and love anonymous classes in java. This sentence is only half true. If you are writing normal java code, this is not such a big frustration. But in Rx you will need loads of those. And if you choose to still use them, it will be frustrating.
  7. Instead use lambdas. Doesn’t matter if you will be using retrolambda, jack or kotlin. Just pick one and enjoy!
  8. Sometimes when I write a really complex Observable, such as this one. When I am finished, I run the app or test to verify that it works – but nothing happens. Added logging in multiple places, changing schedulers – still noting. Then a single thought comes – where did I subscribed? Always subscribe!
  9. Why
  10. Again we have a complicated Observable. We combine here two last values from first and second, and then print the result. But again it does not print. First we check that we subscribed, from now on in every example lets assume we subscribed. So when I used to have this problem with combine latest – I didn’t know just by reading the code, how will the observable behave. I had to fallow creation path of those obs and check if they ever emit a value. I was not able to get it from this code.
  11. Similar thing goes with concat – which subsribes to first stream, emits its values and until complete event comes Then subscribes to the next one. But for some reason the events from the second one are never emitted. Again, we don’t know the reason just by looking at this code. Being forced to go up the stream of observables everythime you want to understand the issue, is really frustrating. There are two ways to handle this issue – with types or with naming. We went with nameing
  12. Let me tell you the approach we use in our project. getValue() - this is a normal way how you would expose an Observable. Same problem as before - we do not know how it will behave getValueOnce() - First of ours naming convention - this Observable will emit value as quickly as possible after subscription getValueStream() - this Observable can emit infinite amount of events. It does not give us guaranty that it will emit anything after subscription. The only thing it can guarantee us is that it will never complete - example mouse click events getValueOnceAndStream - will emit event as soon as possible after subscription and will continue on emitting events indefinitely. Example, checking if device is online/has internet access and then listening if the network status has changed. So let see how does it work with combineLatest.
  13. Now we see that the first observable will trigger only once and then complete. The second one will trigger and then continue with emitting events if any. Only by looking at it, we know that the combineLatest will emit at least one value. If the second Observable emits new items - it will combine them with the only value of the first Observable. With this approach, it is much easier to reason about your observables. You don't need to follow the creation path of the observable to know it will behave.
  14. Now I would like to talk about one of the most confusing and at the same time the most crucial operators in RxJava. There are a couple of operators that have this exact signature. As a parameter, they accept function with one argument T and result of Observable<R>, which is at the same time this is the same thing the entire thing returns. Can anyone make a wild guess? This signature is shared between 3 operators – flatMap, switchMap, and concatMap “Story about not knowing flatMap” “Explain announcer example” I cannot stress enough how important is to know the difference. If you are doing a Rx app and this difference is not clear yet, spend some time on playing around with them. It will save you plenty of problems!
  15. Next thing, how you should subscribe. You could subscribe in this way, when you do not care about errors or if the observable completes. But you shouldn't do it like that. The reason is that if for some reason the getCountStream emits an error, not implemented error will be thrown, and that might crash your application. Instead always implement the handler for the error case, even if you would just log the error.
  16. One of the selling points or Rx is that you can schedule your work with ease on any thread you’d like. Still, you need to think about it most of the time when you write the code. One common issue that I see is how people start Observables with heavy, blocking functions. Just is a really handy operator that starts Observable stream with a value. But people forget that it still accepts a value. If you call the method like that, it will be executed on the same thread on which entire Observable was created, and NOT subscribed. In those cases, you need to have a more lazy approach. FromCallable is a really useful operator that will call the passed function on subscription – so it will adhere to the subscribeOn operator.
  17. When you create an Observable that has a costly subscription, for example, Retrofit observables, you need to watch out how often you subscribe to it. In this example, for every subscribe, we would run the expensive function one more time. It's ok to do it if this is exactly what you want. But if you want to reuse the outcome of the expensive function, you either can cache it or share it.
  18. One super power Rx has is the ease of switching threads The key here is subscribeOn and observeOn. Similarly to what I said about maps, you have to know the difference between them. // Explain SubscribeOn does not work with Subjects - if you didn't know that, your team is not the first one wondering why there is so much stuff happening on UI thread.
  19. Retrofit – explain and say about heavy lifting
  20. Zip is an interesting operator. It is a good way to show to new people the power of combining observables. But in real life tasks, it could create more issues than it's worth. First of all, it can make your code hard to read and maintain. Most of the cases when people say that Rx code is hard to manage, they mention zip. Additionally, backpressure problems are quite frequent when using zip. I am not saying you should not use zip, just know how it works, and what are it's strengths and weaknesses. And in most of the cases, zip can be replaces by one of the map operators.
  21. Debounce operator was the first one I've seen. It was used for the autosuggestion example that I've told you about. But it is also one of the most misused operators. // Explain Whenever someone has an Observable that for some reason triggers too often, that person could use it to filter too much noise. But debounce introduces time-based side-effects that are hard to investigate. Also, it could unnecessarily slow down your application due to the debounce time window. It is always better to investigate why that other Observable triggers too often and fix the underlying cause.
  22. You should always subscribe if you want Observable to trigger, I hope that's clear now. But every time you subscribe, you create a subscription. If you don't unsubscribe that subscription, you might create a memory leak. There are cases when the subscription will be managed by itself, but it is always safer to do it by yourself.
  23. But your problem might not be one of those. The gut feeling will not always lead you to a solution of your problem. In those cases, you need to start debugging. Most common way to debug Observables is to use doOnNext. It will nicely tell you when events are happening. But in some cases it is not enough, the reason why the observable is not triggering might be that it emitted an error or it completed. I would strongly suggest to use doOnEach instead. That way you will be able to see all the events that might happen on the Observable. And if that is still not enough, use doOnSubscribe and doOnUnsubscribe to check it the problem was with subscribing or unsubscribing.
  24. Once someone asked me if I could sum up the benefits of Rx in 10 words? I've come up with an ok solution.
  25. But that question got stuck in my head. After a while came up with shorter and better answer.
  26. If you want your application to be really reactive, you can write the code without using Rx. But the code complexity easily can get to a stage that it will be unmaintainable. Rx is made to control the complexity and keep it in place.
  27. After 3 years with Rx, I am cautiously optimistic about writing reactive code. I know that it is a really nice tool, but still only a tool. Sometimes it's really useful, sometimes is only brings confusion. Knowing when to use it and when it will only make your work more difficult is the most important skill you can acquire in Rx.