RxJava, once the hottest framework in Android development, is dying. It’s dying quietly, without drawing much attention to itself. RxJava’s former fans and advocates moved on to new shiny things, so there is no one left to say a proper eulogy over this, once very popular, framework. It leaves your most humble servant, me, who never believed in RxJava to begin with, to say a few words and pay a tribute to this monumental effort by many talented engineers.
Now let’s get serious. RxJava is indeed in a free fall and, most probably, will soon become problematic legacy dependency in Android codebases. It’s worth taking a moment to reflect on what the hell happened with this framework in Android ecosystem and what lessons we can learn from it.
RxJava Popularity Over Time
I guess that many readers will be outraged by my claim that RxJava is dying, so let’s get straight to the point: how do I know that? Well, I just look at the numbers and draw conclusions.
Search stats for RxJava keywords from Google Trends:
Searches for RxJava peaked in May 2017 (not coincidentally, it was the month when Google announced official support for Kotlin in Android), plateaued for about a year, and then started their gradual, but consistent decline. As of today, RxJava have already lost more than 50% of its “search interest” compared to the peak value.
Let’s also examine the stats from StackOverflow Trends:
As you see, the overall picture is very similar.
At this point, I resist the urge to speculate about the sources of differences between Google Trends and StackOverflow Trends stats. Most notably, StackOverflow questions rate for rx-java2 peaked at the beginning of 2018, it never plateaued, and it have already lost more than 75% of its peak value. In my opinion, StackOverflow Trends stats reflect the popularity of RxJava much better, but since the details aren’t that important, I’ll skip this discussion and spare your time.
I’ve already brought up these stats in the past, so I can predict some of the incoming counter-arguments. The central one is that, maybe, these graphs reflect maturity and widespread adoption, not demise. Well, sorry to disappoint you, but they aren’t. To demonstrate why, let’s compare RxJava’s, Retrofit’s and AsyncTask’s stats from StackOverflow Trends.
First, let’s compare RxJava to Retrofit:
Retrofit is one of the most popular and mature frameworks for native Android development and StackOverflow Trends reflect this fact. The rate of new questions is relatively stable. That’s especially impressive if we take into account the fact that the overall rate of Android-related questions is on decline. RxJava’s stats are strikingly different from Retrofit’s.
Now let’s see how RxJava stacks against AsyncTask, which was officially deprecated several months ago:
I rest my case.
RxJava is dying and it’s time for Android community to come to terms with this fact.
Fundamental Problems With RxJava
One very interesting question we can ask is whether the demise of RxJava was predictable. In my totally subjective opinion, the answer to this question is “yes”. I can’t say that making such a prediction was trivially simple, but the writing had always been on the wall. So, let’s discuss the fundamental problems that destined RxJava to its sad fate.
The biggest issue with this framework is its complexity. It results in enormous learning curve that pretty much negates any potential benefit RxJava could theoretically have. In addition, this framework is completely unintuitive to “classically trained” software developer, so you can’t pick it up on the fly and infer the functionality of RxJava code from the surrounding context. Therefore, every developer who will read the code that uses this framework in the future will need to learn it.
Fundamentally, RxJava’s complexity is a direct consequence of a violation of the Single Responsibility Principle. You want to create a framework for glorified observers? Be my guest. Now you want to throw multithreading into the mix? Well, you step onto a shaky ground, but it can work, I guess. What, you also added an insane amount of cryptic operators?! Oops, you’ve just created Frankenstein’s monster. Good luck controlling this thing.
The second issue is that RxJava is very intrusive framework and it spreads in codebases like cancer. Even if you’d like to limit its impact to just handful of classes, it’s tricky to convert a component that exposes RxJava-based API into “standard” Observer design pattern. Therefore, the moment you add a bit of RxJava “magic” into your app, you most probably plant a seed of a much bigger tree. This process becomes pretty much irreversible if you also unit test your code. Then, RxJava contaminates both your production code and tests, so there is no going back.
Lastly, RxJava never received either official endorsement or support, which is problematic for such complex and intrusive framework. If official guidelines and tutorials would promote and use RxJava, then it would become “the standard”. That wouldn’t make its fundamental flaws go away, but, at least, it would make an average developer familiar with this technology. Without official adoption in the ecosystem, any project that used RxJava basically became strongly coupled to the fate of a questionable third-party dependency. It’s a nightmare from architectural point of view.
Why RxJava Was Relatively Popular at One Point
Taking into account RxJava’s flaws and associated risks, it’s surprising that it did get any traction in Android ecosystem at all. How comes? In my opinion, there were just two main factors that fueled RxJava’s adoption.
The main selling point of RxJava has always been that it’s better than AsyncTask. What does “better” mean here? To be honest, I’m not sure. However, countless developers, advocates and conference speakers contrasted these two frameworks. I’ve just googled “rxjava Android”, and the first three results also mention AsyncTask. Marketing-wise, this comparison was a good move. AsyncTask had already had a very bad reputation, so it made a perfect straw man for RxJava. However, this comparison was also flawed on many different levels.
Most importantly, presenting RxJava and AsyncTask as the only alternatives was a false dichotomy. As I wrote in my article about concurrency frameworks, bare Thread class and thread pools have always been very good options as well. It’s not a coincidence that after they deprecated AsyncTask, today Google recommend thread pools as a replacement in Java codebases.
But even forgetting about the false dichotomy, I’m really not sure that RxJava is any better than AsyncTask. It’s more reliable, sure, but it’s also much more complex and invasive. Today, when both AsyncTask and RxJava are legacy technologies, I’d rather refactor a codebase that contains AsyncTask’s than a codebase that contains RxJava.
Interestingly, RxJava never got any considerable traction among backend developers, even though it came from the backend world originally. In my opinion, the fact that they didn’t have AsyncTask to construct the straw man is one of the main reasons for this discrepancy.
The second factor that contributed to RxJava adoption was heavy marketing by its fans, some of whom were among the most prominent figures in Android community. At some point, you just couldn’t read a weekly newsletter or attend a conference without being preached about RxJava’s greatness. Now, that’s not something exceptional. We, developers, like our toys, so we naturally talk about them. What was very off is the personal aggression with which any criticism towards RxJava was met.
“You don’t know what you’re talking about”, “you hate everything new”, “you just don’t want to learn”, “according to you, we should code in Assembler”, etc. These were the standard responses to criticism. However, my favorite response is this:
This comment stuck with me because it’s so beautifully articulated. Really, it’s very funny and even poetic. I can appreciate that. However, it’s also fundamentally wrong.
First of all, today we know that my criticism was spot on and the “onset of automobiles” was very short. But the bigger problem here is the second part which concerns “building something large with this approach”. That’s a very common argument invoked by fans of pretty much anything, not even tech-related. We’ll get to this point a bit later.
So, straw man in the form of AsyncTask and high-profile promotion campaign, these were the main reasons which fueled community’s interest in RxJava.
The Future of RxJava
As far as I can see, the glorious days of RxJava are in the past and its future is grim. Since it didn’t get traction outside of Android, loss of popularity in Android ecosystem means loss of popularity in general. Therefore, unless something unexpected happens, RxJava will spiral down into complete irrelevance in 1-2 years.
Now, don’t get me wrong. RxJava will stick around for much longer. After all, developers will need to maintain all that code which has been hastily written during RxJava hype season (though these will probably be different developers from the ones who wrote it originally). However, the framework itself will become legacy and it will become more and more difficult to attract developers into projects that rely on RxJava extensively.
Some developers believe that RxJava died only for Kotlin projects, so if you have Java codebase then it won’t become a problem there. I think that, on the contrary, RxJava will become much bigger problem in Java codebases. Especially if those projects will need to migrate to Kotlin in the future. In general, in my opinion, using RxJava in Android world today is much riskier than using Java.
Many Other Frameworks Disappeared Before, So RxJava isn’t Special
Some RxJava fans found peace in claiming that RxJava is no different from any other framework which lost its popularity, so let’s move on, nothing to see here. While this thought can be comforting for those who invested tremendous effort into RxJava (either as users, or as maintainers), I think it’s not exactly correct and steers us away from learning hard, but important lessons. So, let’s discuss why RxJava is special.
The crucial difference between RxJava and most other frameworks is the scale of the loss.
For example, similarly to RxJava, we never really needed AsyncTask and it died too. However, compared to RxJava, AsyncTask consumed almost negligible effort on developers’ ramp-up and wasted much less attention span of the wider community. It’s also much, much simpler to maintain or refactor out of the existing codebases. So, compared to RxJava, even AsyncTask looks like a very successful framework.
The only fiasco of a comparable magnitude in Android world which I can think of is Loaders framework. It was even worse than RxJava in pretty much any dimension, wasn’t needed to begin with, consumed huge amount of community attention and then became irrelevant, quickly. However, Loaders was an official framework from Google, so you couldn’t really ignore it. Therefore, even the case of Loaders is very different from RxJava.
All in all, I think that RxJava’s story in Android is unique and presents an opportunity to learn some important lessons.
So, what can we learn from the meteoric rise of RxJava and its even more meteoric fall?
Well, the first lesson is that complexity and steep learning curve are red flags. If an average developer can’t figure out what a piece of code does by just reading it, it’s a big problem. Now, in some cases, complexity is essential. For example, advanced image processing algorithms will be complex no matter what. But if you need these algorithms in your app, there is no way around that complexity. In contrast, no one ever really needed RxJava. Therefore, all this excessive complexity could easily be avoided.
Then there is this simple, but so often overlooked fact that not every hot and new technology which becomes popular at conferences is worth an investment of your time. This point alone deserves an entire article on its own, so I won’t dive into it here. However, realize that many frameworks that are dead today were the topics of many conference talks in the past. And most of these talks were given by enthusiastic, honest and capable developers, who praised that tech. Examples from the top of my head: SyncAdapter, AsyncTask, Loaders, Realm, Volley, Xamarin, Cordova, etc. So, the fact that a tech is discussed at conferences is meaningless when it comes to evaluating its merits. In fact, I will even go as far as saying that if some tech is discussed at conferences a lot, that’s a sign that this tech is not your best bet.
Lastly, let’s get back to the argument that you can’t evaluate some piece of tech before “you’ve built something large with it”. This is a standard trick in many propaganda campaigns. It’s basically an attempt to deflect the conversation from the voiced criticism and picture the critic as not having enough knowledge and/or experience to have any say in the discussion. Now, let me be absolutely clear: I’m not saying that prominent Android developers consciously planned a full-blown propaganda campaign. What I say is that this is one of these dirty tricks that we, humans, employ subconsciously to protect our beliefs. It’s a part of our natural response.
I don’t mean to say that “you’ll see benefits only at scale” is an invalid argument. In some cases, it’s a fact. However, “scale” benefits should be stated explicitly and subjected to external criticism as well. If they are real, it shouldn’t be that difficult to describe the conditions in which these benefits become relevant.
So, the last lesson we can learn from RxJava is that if advocates of some tech can’t keep the discussion professional and attempt to either discredit, or flat-out offend the critics, chances are that what they “sell” isn’t that good.
In this section I want to put everything I discussed above into more practical terms using two examples.
The first example is AirBnb’s MvRx framework. They announced it in August 2018 and I immediately realized that they had made at least two mistakes related to RxJava.
The first mistake was to use RxJava in this framework at all. They had probably started working on MvRx long before the official announcement, so, maybe, back then RxJava was still “hot”. However, the decision to couple their entire codebase to RxJava in 2018 was questionable because, by then, it was already clear that Android community loses interest in this framework. Given the fact that AirBnb employs tens of Android developers, extra-strong coupling to a legacy framework will probably come to bite them in the future.
Then there is the name, MvRx. As you know, naming is one of the most difficult things in software, but AirBnb’s choice is still very odd. And I’m not talking about the fact that inventing new variants of MVx abbreviation is a questionable practice. What I consider a real mistake here is the fact that they basically tied the public perception of their new framework to a third-party dependency. RxJava is in free fall now and MvRx, due to its name, is tied to it with a rope.
I don’t know what’s going on within AirBnb, but I suspect that, in light of the loss of business due to pandemic, they aren’t concerned with unfortunate tech choices at the moment. But there is no doubt in my mind that MvRx will become a problem for them both in terms of attracting new developers and in terms of ramp-up and maintenance costs. Therefore, I fully expect them to either refactor RxJava out of MvRx, or ditch it completely. Both paths involve a major investment into refactor of their codebase. I also won’t be surprised if they decide to change the name of this framework.
The second example is one of the best libraries for Android, ReactiveNetwork by Piotr Wittchen.
Most Android apps need to know whether they have internet connectivity or not. However, even though relatively simple API has been available since the very early days, it wasn’t reliable. For example, you couldn’t detect so-called “captive portals” on public Wi-Fi networks and other types of restricting proxies. ReactiveNetwork is a highly configurable library which allows you to handle the whole range of network states, with relative simplicity.
In my opinion, the only reason ReactiveNetwork isn’t as popular as, say, Glide, is it’s RxJava-based API. Most developers wouldn’t like to take this dependency and learn how to use RxJava to just monitor network state. Therefore, the potential audience of this library is limited to projects which already use RxJava and projects where reliable handling of network state is critical. That’s really unfortunate.
Now, open-source maintainers don’t owe me anything and are free to choose whatever technologies they want. However, I believe that most people who put their work in public domain do want to see their baby being widely adopted. RxJava interferes with this goal and severely limits the potential audience of any open source library. In case of MvRx, I don’t mind that because I wouldn’t recommend this framework in any case. In case of ReactiveNetwork, I’m really sorry for that because I constantly recommend this library, but also have to add a disclaimer that it uses RxJava.
All in all, in my opinion, RxJava in Android was a fiasco. It consumed enormous amount of community effort and attention, contaminated many codebases, didn’t bring any value and, as of today, I can say that it pretty much died. It’s my hope that we will be able to extract at least some lessons from this story and, maybe, avoid another cycle of churn in the future.
I know that this article will be hard to read for many developers who learned, used or maintained RxJava. Some will even argue that since they already use this framework and it makes them productive, the best path forward for them is to just keep using it. However, if you care about long-term maintainability of the code you write today, RxJava doesn’t make a cut.
I totally understand how you feel if you’ve been RxJava user or fan because I myself used SyncAdapter, ContentProvider and Loaders in the past. However, the sooner you’ll realize that it’s a classical sunk-cost fallacy, the better for you.
As usual, thanks for reading. You can write your comments and criticism below, but please keep the discussion civil.