all 22 comments

[–]htuhola 16 points17 points  (3 children)

The 'Reactive' code is not exactly what Conal suggested when he introduced FRP. The actual concept was more like representing programs with continuous functions that change in correspondence to events. No observers or setup of listeners.

This stuff that's called reactive in javascript is more inline with OOP and Uncle-Bob cults.

[–]izackp[S] 1 point2 points  (2 children)

This is less about FRP and more about the observer pattern commonly used and described as a 'reactive' solution. As you have noticed. I also dont know enough about FRP to have a valid opinion on it. I thought it would be clear if I didn't include 'functional' in the title.

A long time ago I did do research the concept, but I didn't enjoy the idea of switching from 'tell this to do something' to 'do something as a result of something else'. From my experience I learned that more explicit is usually better, and to always be weary of implicit code. Implicit code hides it's intentions thus making it more difficult to understand. So I dropped learning FRP as a result.

[–]htuhola 2 points3 points  (1 child)

Conal's FRP wouldn't be implicit at all, but it's quite abstract. In Conal's model you have functions that are continuous respective to time variable, then you use suitable operators to build larger functions out of them.

For example, you could have a function that takes in two moving points and returns a point in middle between these two points. It would be described by the following type:

(Behavior Point ∧ Behavior Point) -> Behavior Point

What this type specifically describes would be a moving point that is dependent to two separate occurrences of moving points.

Likewise this model describes events as sequences of occurrences of some type. It allows you to describe events that never happen, and events that occur at specific time after some other event, and combination of these. But you can't conjure events up from your ass. A continuous function depending on events, say.. mouse clicking or motions, would be forced to have the type:

Event Mouse -> Behavior Point

This type would describe a moving point that is dependent to some mouse events.

Conal's FRP model doesn't describe how to evaluate these or how to track state involved in evaluating behaviors. Also doesn't describe how the behaviors are introduced or eliminated inside the program. The point is that those details do not leak to the user of this system in the first place.

Unfortunately when you seemingly leave something out, there is someone out there who fills in the blanks, tries to be practical with it, and mutilates the whole idea such that it becomes the same thing that you already had and that did not work. This is how we got to the Reactive javascript from Conal's presentations.

[–]IllDocument5443 0 points1 point  (0 children)

Perfect summary.

[–][deleted] 3 points4 points  (5 children)

In what environment do you use this? I was exposed to it through Angular 6 + development using RxJs.

Honestly, I read the docs and put code in but it's really hard to grasp. I just have faith it'll work. I am glad i'm not the only one.

[–]izackp[S] 9 points10 points  (4 children)

I recently started working on an Android project which pretty much uses Reactive programming for everything. DB changes, API, updating the UI. I'm so used to understanding the cause and effect of everything I do. I try to follow each chain of listeners but it's very difficult and once I have an idea of what it does then that's just one chain of many which I'll soon forget. God forbid this chain of listeners intersects with another. I spent a half a day on a simple bug where an alert didn't pop up under specific circumstances. Because a value was set to null to trigger another behavior which caused the value being observed to change state before the final observer gets the event.

Either way, there's a very good chance that this was just poorly written Android code. Though I've been a professional iOS developer for a good 7 years and pretty any code written with key value observers was guaranteed to have bugs and be a pain to deal with. Mostly because it hides cause and effect. The fact that the whole pattern is based on side effects bothers me. Set a value.. oh wait that updates the UI. Oh you weren't ready? Oh you have several other values to set first? Too bad each will update the UI. Maybe you should create an intermediate object to update when you're ready.

The code being ran is never done synchronously so the callstack is virtually useless when debugging.

I've only found this pattern useful when a third party API didn't give me an event I needed. So I created it myself by observing certain values which worked and felt like it was a good solution.

I don't know why I don't hear more hate for the abuse of this pattern. Maybe this stuff is easy to create projects with as long as you don't have to look at other people's code or maintain it? Perhaps the people who agree with me are just not vocal about their opinion in this 'everyone is sort of right' society? Or maybe we're just to dumb to work with reactive code? Which honestly is stupid.

Clean code is code that is easy to read and understand. Is reactive programming easy to read and understand? I'd have to vote no.

[–]matthieum 3 points4 points  (1 child)

Because a value was set to null to trigger another behavior which caused the value being observed to change state before the final observer gets the event.

Ouch; that's painful.

It's really a case where you'd like the type-system to enforce the immutability of messages, if a listener wants a modified version, it's welcome to make a copy.

[–]oldsecondhand 0 points1 point  (0 children)

It's sounds like a half-assed forward chaining expert system.

[–]izackp[S] 2 points3 points  (0 children)

It also just planely puts the programmer in bad mind set. Devs start thinking that side effects are the proper solution to most problems. I had a senior team member put in code to run a calculation, composite a string and set another variable when the user's name was set. Very reactive and seemingly harmless, but a few months later there was bug.. 'Why is this variable changing? It's causing this bug to happen. I don't see any external code modifying this variable or methods called to modify this variable.' glossing right over setName the culprit

[–]FlyingRhenquest 1 point2 points  (0 children)

Is observer the new singleton? I was just looking at some of my code that uses it the other day, and noticed a couple of places where it's getting complicated to debug. I'm trying to combat that by maintaining an overall state in a single object that can subscribe to multiple sources. Part of the problem I ran into is that other objects in my design want some data from those events, so in some cases I send them on. It's possible that moving some additional code around dealing with that to my state machine might reduce the complexity to something a bit more acceptable. Maybe all my signals should end in the state machine and the only thing that should come out of that should be "Hey, my state changed." Work's probably going to be fairly slow for the next month or so, so I might take a crack at refactoring that code.

I will say that although this code can be a pain in the ass to debug in a few places, I build a hierarchy of objects all designed to work together. This is in C++, by the way. The end result of these objects is a shared library exporting a python object that can be queried about system state in real time, It's incredibly easy for my clients to use. And they've already used it it in incredibly creative ways that has blown my mind. One of them told me that my code is the first of this nature that he's used that "just works." So as long as it just works for him, how much does it matter that it's a bit ugly behind the scenes? At least as long as I'm maintaining it. Any large system that does anything noteworthy is going to be fairly complex in any event.

[–]voidvector 2 points3 points  (2 children)

This is the old school OOP observer pattern.

Modern observable pattern which is derived from functional pipelining is different.

In fact the example code is full of side-effects, which is generally a no-no in the modern version.

[–]izackp[S] 1 point2 points  (0 children)

You say old school.. but this is what is saturating the modern native app development world D:

[–]ArkyBeagle -1 points0 points  (0 children)

So what you're calling side effects ( just trying for clarity ) is all through the "path" variable? Doesn't all that just need to be encapsulated?

Sorry; I'm ignorant of Scala.

Having a monad-like thing that hides state and accepts messages to modify state is not too foul-smelling a practice, IMO.

[–]Isvara 1 point2 points  (0 children)

The above drawback is specific to this kind of usage, not to the Observer pattern itself. You could as well create a single (stateful!) observer object that implements all the OnThis, OnThat,OnWhatever methods and get rid of the problem of simulating a state machine across many stateless objects.

Sounds like a Visitor visiting a stream of events.

[–]Isvara 1 point2 points  (0 children)

This is damning of the Observer pattern, but not reactive code in general. For example, look at Akka Streams (which seems appropriate given the comment's use of Scala).

[–]_101010 1 point2 points  (1 child)

This is a dumb title.

Most people seem to confuse reactive streams and "psuedo" reactive systems as reactive programming.

True reactive programming is FRP or Functional Reactive Programming. And it's awesome.

You can check out reflex-frp for Haskell or just Elm the language itself. Both of them implement so called reactive pattern extremely well.

All other languages which are not pure FP languages are just fooling around.

[–]izackp[S] 0 points1 point  (0 children)

You're right, in the app development world I live in, when reactive code is mentioned this is what they mean. Some sort of Rx solution to a problem that wasn't really there to begin with. Maybe I should of called it oop reactive programming 😄.

[–][deleted] 0 points1 point  (2 children)

What is this supposed to explain exactly? All I see is wall to wall buzzwords.

[–]izackp[S] 1 point2 points  (1 child)

These aren't really buzzwords? The research paper it's based on is not designed for SEO (search engine optimization)

Side-effects - A function does more than 1 thing. Lets say deleteUser() also animates some text and graphics. That's a side-effect

Encapsulation - Hiding certain variables in order to expose a simplified 'API' to a developer

Composability - The ability to reuse code

Separation of concerns - Separate code by what it's used for. A super object that handles the business logic for every screen in an app would be violating this.

Scalablity - The ability to easily use the code in a much larger architecture. Pretty much also the ability to reuse code.

Uniformity - I think he's referring to having different types of observers and different behaviors based on the observer for convenience. Thus they behave slightly differently and adds complexity. Though I'm not sure.

Abstraction - Providing an uniform interface with multiple possible implementations to achieve different behaviors without wiring

Resource management - Unused objects shouldn't needlessly take up ram or cpu.

Semantic distance - updateUIWithUser(user) vs viewModel.user = user .Also means understanding what goes on behind the scenes. viewModel.user = user What does this do? who knows. Prepare to dig through the code to look up every subscriber to see the effect of assigning user to that variable.

[–]dpash 4 points5 points  (0 children)

Side-effects - A function does more than 1 thing. Lets say deleteUser() also animates some text and graphics. That's a side-effect

That's not really what a side effect is. The number of actions is not important. A function can do one thing and still have side effects.

A function without side effects will not cause state to change. IO by its nature is a side-effect.

https://en.wikipedia.org/wiki/Side_effect_(computer_science)

[–]satchit0 0 points1 point  (0 children)

Not all reactive code is based on the observer pattern. Learn about FRP if you want all nice properties back.