A foreword

A foreword
===
Hello everybody, the two major things that were recently introduced into my software architecture which led to significantly better maintainability and modularity, are *Dependency Inversion* (via https://bitbucket.org/sglienke/spring4d) and *Eventbus* (via https://github.com/spinettaro/delphi-event-bus).

And most recently, what caught my attention is the idea behind Redux - one of the most popular idea and framework in the JavaScript front-end development world lately.

The problem
===
The *problem* Redux trying to solve can be described in short as:
"...At some point, you no longer understand what happens in your app as you have lost control over the when, why, and how of its state (model)...".

For example, assume in an application we have a model called TOrder, the issue is that, although the functionalities to manipulate TOrder can be encapsulated in TOrderManager, it's often that we might call TOrderManagr in Module A, B, C and D.

Redux's solution
====
Redux's solution to the problem mentioned above can be consolidated into 3 priciples (linked below), but *practically*, I think the second priciple is most useful in our Delphi world:
"...The only way to change the state is to emit an action, an object describing what happened...".
To have a feel as to how this works in Redux, please see the example code in the page linked below.

The benefits:
===
"...Because all changes are *centralized* (note this word, my fellow Delphi developers) and happen one by one in a strict order, there are no subtle race conditions to watch out for. As actions are just plain objects, they can be logged, serialized, stored, and later replayed for debugging or testing purposes...".

Although such approach not might fit in all applications , but it's really beneficial in many places as I can see.

My initial thoughts
===
- We have https://github.com/pierrejean-coudert/ReduxDelphi, but I think it's too strictly followed the original Redux implementation.
- The channel to send "model manipulation commands" can be implemented via Delphi Event Bus.
- To have a centralized module to receive commands and perform the actually manipulation via, for example, TOrderManager.

Question
===
Any comments, thoughts and input are welcomed. if you allow me, I'd like to invite Stefan Glienke, Daniele Spinetti, A. Bouchez, Daniele Teti, Nick Hodges and Pierre-Jean COUDERT into this discussion.
http://redux.js.org/docs/introduction/ThreePrinciples.html#state-is-read-only

Comments

  1. Taking a simple look at these three principles I would say that Redux is inspired by functional programming where you don't have mutable state and thus only pure functions. There are several benefits to this like the possibility to version and easily update data. Also immutability solves many multi-threading issues.

    I did not look closer into what redux is and does but understanding the benefit of less (I am not even saying complete stateless) state inside of objects and making methods pure can be a big benefit and consider rather returning things than changing states inside your object (not talking about data objects whose purpose is carrying around state).

    ReplyDelete
  2. Stefan Glienke That's why I'm *mostly* looking at the second principle - to have a *centralized* place to do the *actual* changes of the model objects, instead of having codes that change the model objects scattered around the entire app, thus causing the "...At some point, you no longer understand what happens in your app as you have lost control over the when, why, and how of its state (model)..." problem Redux trying to solve. In terms of a practical Delphi implementation, I guess we can omit redux's first and third principle at the moment.

    ReplyDelete
  3. Edwin Yip I disagree. You presented kind of an anti pattern to argue: TOrderManager - that thing can possibly do all or nothing with orders. This probably violates the SRP. But still there is one place that mutates your orders. The fact that you call it from different modules does not change that. Rather the fact that possibly not everyone is using that but doing its own thing.

    If you are losing control over the when, why and how then you are facing a design problem - one that redux might not solve like a silver bullet - or not only redux.

    Your example order sounds like a typical podo so I would certainly never made those immutable and return new instances when I change anything (and totally not in Delphi where I don't have a mechanism that properly cleans up unreferenced states - at least not without ARC)

    I am no expert on typical problems in JS code but this sounds more like an approach to get control over the global state mutation which is what really hurts.

    ReplyDelete
  4. Edwin Yip Redux with JS faces a different environment, as JS apps are typically far more focused, and they are modularized by default (thanks to running in a browser or a node environment).

    Many JS apps and workers are short-lived: they need to come up fast, do something, then go back to sleep or are destroyed. So the startup/shutdown portions are quite critical, and redux actual value lies primarily with that aspect IMHO.

    But there is usually no such short-livedness in Delphi apps...

    ReplyDelete
  5. Redux is a good idea but JS doesn’t support immutable data structures. Immutable.js is not the same thing. I’ve been tinkering with clojurescript + reframe which seems like a much more sane way to implement react / redux. Once you have immutability , writing multi threaded code becomes natural. Clojure is also homoiconic and supports macros so you can build DSL like hiccup where when you are writing http, you are actually writing clojure code.

    ReplyDelete
  6. Mike Margerum the leading JS environments being node and browsers, multithreading issues are somewhat different to those we have in Delphi f.i..

    And the most problematic aspects of multithreading are atomicity, consistency and isolation, and immutability does little to nothing to help solve these.

    ReplyDelete
  7. Thats true Eric Grange. Immutability alone doesnt provide those.
    Clojure provides atoms, refs, and transactions. I don't know if ill ever actually use Clojure in production, but its very interesting to study.

    ReplyDelete
  8. "...The only way to change the state is to emit an action, an object describing what happened...".

    There is some similarity here with CQRS which is an architectural pattern that goes out of its way to isolate all commands that can change state into separate classes/components in you system.
    Using commands that resemble the ubiquitous language of the problem domain it has the advantage of closely describing the intention of the domain expert in code.
    The pattern often goes hand in hand with event sourcing which hooks into the state change events issuing from these commands.
    The events are then persisted as an event stream from which the system state can be analysed, replayed and reconstructed.

    ReplyDelete
  9. David Champion Thanks for your comment. Interestingly, after further reading on this topic, I kinda conclude that "Event Source" is actually the most wanted part.

    ReplyDelete

Post a Comment