DEV Community

Cover image for Don't Drink Too Much Reactive Cool Aid

Don't Drink Too Much Reactive Cool Aid

Jan Wedel on June 23, 2018

Cross-posting of my blog article. In the last years, the idea of "reactive server applications" was being promoted heavily, especially by new f...
Collapse
 
alainvanhout profile image
Alain Van Hout

Apart from this being a great write-up, the very final paragraph caught my eye:

And, for unexperienced developers, it might seem cool because it's so hard to understand. As if only the best developers will understand it. But trust me, this is not the case. The best language and API designs are those, that are easy to understand, write and read.

Possible the most important yet undervalued insight to be (or become) an excellent software developer.

Collapse
 
leob profile image
leob

Good write-up, however if you use a language like Javascript which doesn't have threads, you will obviously have to do 'reactive', whether you like it or not.

Promises and async/await make it much more manageable, but some of the drawbacks are still there (ever tried to decipher an error stacktrace in a node/express program? it ain't easy ...)

Collapse
 
stealthmusic profile image
Jan Wedel

Jup. That’s why I explicitly mentioned backend programming. ;)

Collapse
 
leob profile image
leob

Yup ... but Javascript gets used on the backend too, obviously ... Node/Express ;)

Thread Thread
 
stealthmusic profile image
Jan Wedel

True :) trying to erase that from my brain whenever I can 😜

Thread Thread
 
leob profile image
leob

Haha, you're not a "JS backend" fan I see ... I can sympathize with that, I'm using node/express on a few projects but quite often I ask myself "WHY ... ?"

Thread Thread
 
stealthmusic profile image
Jan Wedel

Yup, I'm not a "JavaScript for anything" fan Β πŸ˜‡
We're using TypeScript for UI Code, Java in the backend.

Thread Thread
 
leob profile image
leob

Wise decision, saving yourself a lot of trouble ... yes and classical threads are fine for the majority of purposes

Collapse
 
hazer profile image
Vithorio Polten

Great write-up, sharing with my team :)

For the JVM now there's Kotlin Coroutines. They also have the concept of suspension.
One nice thing about Kotlin Coroutines, there are libraries with basic implementations, but actually it is an language API to design suspending operations, you can use any execution model behind it, heavy threads, lightweight threads, reuse your engine loop system, it doesn't matter, it all will look like sync procedural code if you want. Or Actors, Channels, Generators.

Often people ask me why I like Kotlin Coroutines so much and dropped RxJava totally, instead of using them together, and my answer it's mostly that Rx is hard to read and reason, there's cognitive overload every time you need to read it. Doesn't matter if you know it well, you will always be thinking about the execution, while with suspending async model, I will just read the business logic line by line, as usual. I found it reeeally easier for juniors to get into, even when mixing some little reactive, overall they were faster solving problems with less async bugs.

When I meet the suspending paradigm, I learnt how much I was missing sync "old style code" and didn't know.

I agree with you, too much reactiveness may be hurtful. But I still love it for UI bindings, better yet for bidirectional bindings. I guess it's all about balance Β―_(ツ)_/Β―

Collapse
 
samolenkov profile image
Stanislav Samolenkov • Edited
  1. The cost of thread is hugely eggxagerated.

  2. The modern server frameworks have graceful solutions to limit thread number and to use one thread for several parallel tasks.

ReactiveX cons:

  1. There are no methodologies to develop complex information systems based purely on Rx.

  2. The code is diveded by numerous lambdas and business logic is scattered across source files by small chunks. It's practically impossible to track particular use-case implementation across the sources.

  3. Given two above the eventual outcome of Rx development is chaotic development metaphor (see Steve McConnel).

  4. Thus it's not new or progressive but travelling in past times before OOAD of Booch, before GOF patterns, before RUP by Rational Rose and Three Friends. It's back to early 1990th.

Collapse
 
stealthmusic profile image
Jan Wedel

The cost of thread is hugely eggxagerated.

I admit, I did not do any testing on Desktop VMs recently. But, I was developing a platform for embedded clients running HotSpot VMs. We had around 200kB of memory available (not joking). So we needed to be very carful with any kind of memory usage. We actually removed all Strings in log messages and replaced them by constant numbers. Long story short, I measured the memory consumption of creating a thread (which we needed) and it was around 4kB. I did not dig deep into what it exactly consisted of but at that time it didn't matter.

So, do you have any solid figures for recent Desktop JVMs?

Collapse
 
samolenkov profile image
Stanislav Samolenkov

I worked on CORBA framework in the beginning of 2000th and then 1000 threads on server was no issue. All pros for reactivex are artificial. There are a lot of solutions how to reschedule the thread waiting on asychronous call for the other task. The task is made async and called from scheduler. The idea is the same as OS schedules processes and threads on the same CPU.

Collapse
 
siy profile image
Sergiy Yevtushenko • Edited

First of all I see in comments great confusion between Rx* style of reactive programming and reactive programming in general. In fact there are two styles of reactive programming: one based on concept of stream (Rx*) and one based on concept of callback (in Java it's implemented in Vert.x). These are different styles and each has it's own properties and issues.

As correctly mentioned, Rx* style is not always convenient and enforcing "everything is stream, even single element" causes even more confusion.

The modified callback based approach - Promises, are much more convenient to use. While it still different from traditional synchronous code, it much closer and follows the same logical pattern - "when information is available do something".

As for why many threads are bad: the CPU is still limited in number of things it can do concurrently. Threads need to be scheduled and every context switch is expensive since it stops CPU pipeline. Traditional synchronous application is still asynchronous under the hood. Once thread is blocked, OS adds context to the group of waiting and switches to another task. Once operation is done, thread is added to pool of ready to run. All these switching is the root of poor performance and even worse scalability of synchronous code. By writing application in reactive way, we shift all these switching to user space, avoid unnecessary context changes and get far better performance and scalability.

Collapse
 
starodubtsevss profile image
Sergey • Edited

I worked with rxjava and vert.x for one year (before with scala and futures for 2 y.) before not much reactive, and may say: the futures case is middle ground if one wants to find a silver bullet.

So I agree with Jan. We got quite a lot of troubles with RX: learning curve is one thing.

As long as you play with it on workbench all is beautiful and shiny, in reality when whole team working with it, with intensive code reviews one year is not enough, assuming that rx part is one of several parts / microservice (other parts are not rx) - the mental effort to keep all parts by one team on track is not worth it.

I do not talk about vert.x cluster yet and rx part on ui It's different topic.

I belive in 95% cases the rx style is overkill.

Even it one definitely needs one: make sure only one team works on it : they would think only in the nail concepts and be happy with it.

Collapse
 
stealthmusic profile image
Jan Wedel

When you’re working with requests and responses, reactive call chains like map eg are just the wrong level of abstraction at that point. It exposes too much technology where you actually need a functional domain abstraction.

Collapse
 
yuriykulikov profile image
Yuriy Kulikov

As any other technology, reactive has to be taken with a grain of salt. I am currently working on a project where reactive was a great fit (a lot of persistent data streams, e.g. sensor data). However, I would consider other choices for a less "stream"-heavy application (like Kotlin koroutines).

Collapse
 
stealthmusic profile image
Jan Wedel

Getting loads of sensor data is definitively a good fit for reactive applications, but make sure you decouple persisting and enriching with master data to another service of possible.

Collapse
 
jaymeedwards profile image
Jayme Edwards πŸƒπŸ’»

Great take. It’s definitely the wrong tool for many products.