Search code examples
javascaladesign-patternsreactive-programmingobserver-pattern

"Deprecating the Observer Pattern" -- code examples in some other language?


I'm trying to understand the paper Deprecating the Observer Pattern which seems to be somewhat influential in the development of "Reactive" programming.

However, all the examples are in Scala which is hindering my understanding. Has anyone translated these examples into a more commonly known language like Java or JavaScript? Or is there a comparable introduction with examples in a language used by more than like 7 people? :)

If this belongs in a different stackwhatever, please let me know.


Solution

  • The article argues that the observer pattern causes many bugs because it is hard to reason about(needs to use side-effects to maintain state, lack of uniformity, inversion of control, ...) and it is difficult to apply good practices(separation of concerns, encapsulation, ...) to it.

    It then goes on to show how, using Scala.React library, you can transition from an observable-based code base to a reactive one.

    In this answer I will use "scalenglish" and "javenglish" to try to explain the code as I understand it.

    The first step(Item 2) was to create the Event abstraction. With Event, you now have an uniform interface that can be used to encapsulate observables. Then it goes on and define the "merge" method, which allows then to compose different events.

    The second step(Item 3) was to solve the inversion of control problem. To do that, using Scala.React library, they define an DSL where it is possible to translate this:

    var state = null
    observe(event1).then{
        state = new StartState()
        remove_observer(event1)
        observe(event2).then {
            state = new AccumulateState(old_state+new_data)
        }
        observe(event3).then {
            do_something()
            state = null
            remove_observer(event2)
            remove_observer(event3)
        }
    }
    

    into:

    once {
       state = new StartState(when(event1))
       until(event3) {
          state = new AccumulateState(when(event2))
       }
       do_something()
    }
    

    The library transparently defines functions that will wait for the expected events but will NOT stop the execution of your program. In the code above, the methods "once" and "when" and "until" take care of waiting for the event and continuing the execution of the code when expected. You can see also that, in the second snippet, you don't need to associate/remove observers.

    The third step(Item 4) was then to create an Signal. Signal is a time-varying value that you can use to define how to evaluate the value of the signal at the moment( the "now" method) and to observe the signal changes(the "changes" method) by returning an Event associated with the Signal. (As a side note, trait in scala is the same as interface in java, but with the added possibility of implementing some of the needed behavior in the trait itself.)

    The fourth step(Item 5) is then to integrate Signal and Event into the Scala.Reactor. It makes the Signal and Event traits extend the Reactive trait, and explains how (in scala) is possible to define methods that convert events and signals into dataflows implicitly(user-defined implicit conversions is something I tried to find on other languages but it seems to be an scala-only feature).

    It then defines combinators(uniform methods that operate over any dataflow) and explain the problems found while doing so.

    The item 6 then goes on to explain how it all was implemented in scala.

    The item 7 lists related works on other languages/libraries(including Java)