Hacker News new | ask | show | jobs
by k__ 3298 days ago
I don't understand.

Why not simply observables?

3 comments

Author here.

Saying "why not simply observables" kinda glosses over a lot of details, but I'll try and answer as best as I can.

I've always found it a bit difficult to use Observables in application-style code, both in a conceptual sense (handling Redux actions as an observable stream) and in a practical sense (actually building and debugging streams and transformations over those streams). I do think they're excellent tools for dealing with cross-cutting concerns like logging, analytics, and debugging. But as I mentioned in the article, "business logic is inherently procedural, and expressing it as such makes our intent clearer." That's the major advantage, I think- being able to use simpler tools (e.g. loops and local variables) in a powerful new way.

And don't get me wrong, I'd love to learn RxJS properly one of these days. :) This article isn't about saying "well this approach is THE BEST APPROACH", it's more about saying "These tools turned out to be super helpful. Here's my thought process, maybe this approach will help you as well."

Yes, this article assumes (rightfully) that people are using redux saga and need help with it.

I just found the whole concept of redux and redux-saga a bit strange. It seemed like people don't want to use observables for whatever reasons and try to push Redux to solve these async problems.

Your article is good, I just had the feeling it wouldn't be needed if people would use better suited abstractions in the first place.

I'm still not sure exactly what you're trying to say there, particularly by "push Redux to solve these async problems".

Redux itself is about synchronous state updates, as inspired by the Flux Architecture. Because of that, async behavior and side effects are handled via middleware.

Most developers are not overly comfortable with FP concepts or code. Redux was intended as a lightweight intro to FP principles, and React also helps push people in that direction. Even fewer people are comfortable with observables, although Angular is maybe starting to change that somewhat. So, it's not just about "better suited abstractions", it's about what developers understand and can use well.

To be honest, your comments seem to be leaning towards the common stereotype of an FP enthusiast: "This approach is clearly superior and correct, why would people do anything else?"

> Because of that, async behavior and side effects are handled via middleware.

It shouldn't be though. The middleware pattern makes a lot of sense for transforming data (communication between mismatched APIs etc), or using it in some way before passing it on (logging, analytics etc). IMO it's totally wrong for this use case though.

All redux-thunk is doing is taking some "action", clobbering it, pretending it doesn't exist, and running some arbitrary function that it's passed.

dispatch(higherOrderFunctionThatCreatesAsyncFunction())

is identical to

asyncFunction()

What people are looking for is some way to get the data store dependencies into asyncFunction in a testable way. This can easily be done without middleware.

Yes, yes, we've had this argument about redux-thunk in prior threads :)

That said, it's worth noting that the explicit design goal for middleware _was_ for async behavior, per the comments from Dan and Andrew I've quoted in http://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao... . To pick out one specific quote from Andrew:

> [the] reason the middleware API exists in the first place is because we explicitly did not want to prescribe a particular solution for async." My previous Flux library, Flummox, had what was essentially a promise middleware built in. It was convenient for some, but because it was built in, you couldn't change or opt-out of its behavior. With Redux, we knew that the community would come up with a multitude of better async solutions that whatever we could have built in ourselves.

> Redux Thunk is promoted in the docs because it's the absolute bare minimum solution. We were confident that the community would come up with something different and/or better. We were right!

Yeah I'm under no illusions that me and Dan Abramov are operating under a vastly different model for how we think an application should be structured. The concept of a data store having a "solution for async" is, to me at least, absurd. It's like asking why my fridge doesn't have a solution for next day grocery delivery.

I don't see why my fridge needs to be concerned about whether my broccoli is sitting on the bench ready to be put in, or still being washed down at the green grocers.

From the fridge's point of view, a piece of broccoli is inserted into it at a specific point of time. The contents of the fridge can be defined as an ordered set of insertions and removals. The fridge's state depends on knowing whether a piece of broccoli was inserted at 12:58pm or 1:03pm, since that may change the order things were stacked in, but it doesn't need to know whether I placed an order for that broccoli this morning, yesterday, or a week ago; or how it arrived at my house. Making my fridge responsible for that process would seem to violate the concept of separation of concerns.

Because not everyone likes or uses observables? :)

redux-saga was one of the first major side effects middlewares to come out (besides redux-thunk). At this point, I would say that thunks and sagas are the two most popular approaches to side effects in Redux, with observables and various promise-based approaches also used but to a lesser extent.

The main selling points for sagas are things like testability, descriptive declaration of side effects (per Merrick Christen's "effects as data" gist the other day at https://gist.github.com/iammerrick/fc4a677cea11d9c896e8d3a29... ), and the ability to spawn background-thread-like sagas as needed.

Yes, I know.

I just found it strange that people try to bend Redux til it does their bidding and not simply use something that works out of the box.

Well, one of the primary design goals behind Redux was to make async behavior a pluggable approach (as detailed in my blog post "The Tao of Redux, Part 1 - Implementation and Intent" [0]).

So, I don't see how use of redux-saga, or redux-thunk, or any other async middleware, qualifies as "bending Redux until it does their bidding", given that it was explicitly intended to allow that.

On the other hand, there definitely _are_ lots of ways that people "bend Redux", especially things like trying to slap OOP layers on top of an FP-oriented library. Those are technically valid because the Redux core is very unopinionated, but they're definitely not idiomatic Redux usage. (I also discussed those in "The Tao of Redux, Part 2 - Practice and Philosophy" [1]).

[0] http://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao...

[1] http://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao...

I used Redux back in the days and async behavior felt rather clunky (action begin, action success, actionFailure) the other approaches felt like somehow getting rid of this clunky stuff.

Using observables instead of Redux doesn't even lead to these fixes.

As I describe in that "Tao of Redux Part 2" post, there's no _requirement_ that you dispatch START/SUCCESS/FAILURE actions as part of your async requests. You'd need SUCCESS at a minimum or an equivalent to handle the actual updates from the request, but the START/FAILURE actions are only needed if you want want to do things like showing spinners or have some kind of undo/redo behavior. It's a useful convention and a common pattern, but definitely not a requirement.
I find observables, rxjs and redux-observable code to be hard to read and step through debug.

Redux saga is very easy to read, works well with the chrome debugger, and plugs into a wide variety of use cases pretty seamlessly.

Ah, no I didn't mean using Redux with observables instead of Redux-Saga, but to drop Redux entirely and use observables.
I've been fascinated by approaches like the following: https://michalzalecki.com/use-rxjs-with-react/

Building on top of those ideas I built something a bit more powerful and feature complete than the example in that blog post, but the exact implementation doesn't matter: having RxJS driving the show is really, really cool.

Async issues? What async issues?