Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
    Peter Morris
    @mrpmorris
    It's not a programmable workflow. It's coded workflow
    Action = message sent to service bus
    State = object from DB
    Reducers = Strategies invoked by the subscriber to the SB queue
    Brett
    @brettwinters
    Yeah I see the distinction. Your concept is good. Basically the reducer is like a decision engine that if your case is coded but in my case needs some kind of a DSL to do the same thing….
    At it’s fundamental level it’s quite similar to redux which made me think …
    Peter Morris
    @mrpmorris
    Yeah, i didn't need DSL
    Peter Morris
    @mrpmorris
    This now works
        [Feature(name: "Counter", getInitialStateMethodName: nameof(GetInitialState))]
        public class CounterState
        {
            public int ClickCount { get; }
    
            private static CounterState GetInitialState() => new CounterState(0);
    
            public CounterState(int clickCount)
            {
                ClickCount = clickCount;
            }
        }
    Peter Morris
    @mrpmorris
    Could you all please take 30 seconds to answer this 1 question (two choices) survey?
    https://freeonlinesurveys.com/s/2L2pYIod#/0
    Please keep your answer to yourself, so as not to influence others
    Egil Hansen
    @egilhansen:matrix.org
    [m]
    sorry, didnt see this before.
    You are missing the option of not specifying configureawait
    Peter Morris
    @mrpmorris
    It was deliberate, on account that the compiler often gives a warning if you don't
    Erwin Kuhn
    @erwinkn
    Has anyone used Fluxor with a central mutable state? Are there any potential pitfalls, aside from Redux DevTools?
    (mutability is required for performance reasons, but I find I'm reimplementing the same flux pattern of action -> dispatch -> update)
    Peter Morris
    @mrpmorris
    What is it you want to achieve?
    Erwin Kuhn
    @erwinkn
    Basically relying on Fluxor to ease up the boilerplate of having most interactions sent to a central state, then rederiving the UI from that central state
    Fluxor was perfect for that use case, I mostly moved away from it after introducing mutability
    I'd expect it should work fine, since the library doesn't do any magic to my knowledge
    Peter Morris
    @mrpmorris
    If it's mutable then don't put it into state
    If you get something mutable from the server that you want to edit, use an action subscriber https://github.com/mrpmorris/Fluxor/tree/master/Tutorials/01-BasicConcepts/01E-ActionSubscriber
    Erwin Kuhn
    @erwinkn
    Are there specific assumptions within Fluxor that would break with mutable state?
    Intuitively, I don't see anything that would make Fluxor incompatible with mutable state, as long as it's used as a dispatcher + component notifier - but I may be missing something
    Otherwise, I agree with you that mutable state makes things harder to reason about, this is purely a performance concern
    Peter Morris
    @mrpmorris
    If you change state without an action then other parts of your state won't reflect new changes
    Which is the whole point of the Flux pattern
    In my app, I request an editable DTO from the server. The effect that calls the server dispatches that mutable DTO in an action, but that's okay because I never store the mutable object itself in state
    Any immutable state that holds information for CustomerX (for example) can update its own state based on the latest known truth from the server
    And a component using an action subscriber can also get notified of that action with the mutable object in it, and just edit its EditModel Model=ThatAction.EditCustomerDto
    You can use standard input controls etc on a mutable object that isn't "state", and then when you want to send to the server you just dispatch an action that has a reference to that object.
    The effect sends to the server, and then dispatches an action notifying the store that the state for CustomerX has been updated
    (i.e. "saved")
    Erwin Kuhn
    @erwinkn
    So if the state is never mutated outside an action, it should work fine? That's basically what I'm doing already
    Peter Morris
    @mrpmorris
    If it is mutable, I wouldn't store it in state at all, because it CAN mutate
    I don't let my mutable object get into state, the component intercepts it and uses it directly
    Erwin Kuhn
    @erwinkn
    My use case is that of an in-memory simulation, the mutable part of the state is the computation engine that needs to go fast - so it lives there for basically the whole time the app is open
    But understanding the caveats and dangers, if only actions affect that mutable state, I don't see any reason Fluxor could break?
    Peter Morris
    @mrpmorris
    If only actions mutate it, why does it need to be mutable?
    Erwin Kuhn
    @erwinkn
    Not using large immutable collections that are mutated many times in a short amount of time
    (we've tried it, it's too slow)
    Otherwise everything else, including metadata etc.. is immutable, I'm with you on that
    The workflow matches the Flux architecture perfectly as well: user input -> dispatch action -> update simulation -> notify UI
    Peter Morris
    @mrpmorris
    How big is the collection?
    image.png
    the collection should only change if it has been modified, or an item within it has been modified. If that is slow then you might be assigning too often (when state has not changed), or you have a LOT of items
    Erwin Kuhn
    @erwinkn
    Basically ~30 arrays of a few thousand elements . To be fair, if you could process them all in a single pass, that would be totally fine. But certain actions require dozens of passes that modify only a few items in each affected array, so you have three options:
    • Immutable data structures all the way (trees, immutable dicts etc...) -> very nice to reason about, but too slow
    • Using intermediate mutable data structures and only rebuilding the immutable collections at the end of a full action. That may be fast enough, but it adds complexity to the algorithmically hard part of the code, which kinda ruins the purpose of immutability in this case
    • Mutable arrays for the hot path, which make the code much smaller and easier to understand
    Also Blazor WASM makes performance constraints a bit tighter :)
    I can go into more detail, but I don't think that's the point
    Peter Morris
    @mrpmorris
    Why dozens of passes?
    I would think it would only need one
    Erwin Kuhn
    @erwinkn

    This is a bit more technical but: the app is basically a high-powered spreadsheet for numerical models - except that users are working with actual variables in their formulas, instead of individual cells. Variables are nodes in a computation graph, determined by the formulas.

    Each variable can contain many values (they're small N-dimensional arrays, largest ones are ~200-2000 values). Common workflows also get higher level abstractions, that take care of creating multiple variables in the model for the user.

    Which means some actions can result in a few dozen variables being created, each requiring graph maintenance, flagging of observers + other conditional stuff like recompiling a chain of nodes (for dimension propagation). At the end, there is a final linear pass that sorts the graph, performs cycle detection, flags invalid nodes and evaluates out-of-date nodes

    Peter Morris
    @mrpmorris
    Sounds like mixing computation and state. Should you do the computations first in an effect, and then post the result as state?
    Peter Morris
    @mrpmorris
    Reducing into state should be like saving to a DB, calculating is the stuff you do before you save
    Erwin Kuhn
    @erwinkn

    I agree. We could copy the whole graph state into a mutable form, perform all the computations and then copy it again into immutable state.

    The tradeoff is against a memory allocation cost of roughly 2x the graph state size + additional cost of copying + additional code complexity, since you have two versions of the same data structure (one mutable, one immutable) that you have to convert between.

    Overall, that's a tradeoff we decided not to take, accepting localized mutation and strict conventions regarding how that state is changed instead

    Peter Morris
    @mrpmorris
    Would RX be a better solution for this?
    Salvo
    @reklats:jasondove.me
    [m]

    I have a similar use case to @erwinkn, and although my data set is much smaller it still didn't feel correct to keep recreating a set of nested collections every time something changed. I ended up creating a service which warps my mutable state, exposing methods to modify and read only properties for access. Calls to the service to modify the mutable state originate from Fluxor, which also include dispatching an action that describes the change. Components have a dependency on the service (only using the read-only properties) and Fluxor (subscribe to action if needed). So far it works ok, but I havn't really tried to push it to the limits.

    I have a love/hate relationship with Rx, but honestly, had not even considered using it for this.