These are chat archives for jdubray/sam

15th
May 2016
Fred Daoud
@foxdonut
May 15 2016 20:37
@jdubray I've seen that presentation about the Elm architecture. Could you elaborate on why you think that, Redux wanting to aim for something similar, means they don't want to hear anything about SAM?
Jean-Jacques Dubray
@jdubray
May 15 2016 20:40
My understanding is that they are looking for a way to have "declarative effects" (i.e. effects as data) and the main issue with SAM is "it's not easily testable"
I am surprised they would not consider things like "virtualization" e.g. mountbank http://www.mbtest.org/docs/gettingStarted
you can create "record" API calls and replay them in a build/test scenario. I understand that mocks are not a viable option, but it looks like a lot of effort to make "effects as data" (sounds like you write the mocks anyways...) when in reality you can create a "virtual" back-end with little effort and run your test on them. You theoretically have no side effect since the API call returns a constant string.
Anyone has some experience with Mountbank? You can write your own too using express-http-proxy, it's about 30 lines of JavaScript.
Fred Daoud
@foxdonut
May 15 2016 20:46
I don't really have a strong preference either way with "effects as data". I mean, at the end of the day, your side effects have to run one way or another. You can easily abstract them out if you want to minimize their influence on unit tests; and if you want to test the side effects themselves, again it's the same either way -- you'll need to write integration tests.
When you said ' the main issue with SAM is "it's not easily testable" ' -- how do you mean? Declarative effects are not a good fit with SAM because declarative effects and not easily testable? Or, people have a problem with how side effects work in SAM because side effects are not easily testable (according to them)?
Jean-Jacques Dubray
@jdubray
May 15 2016 20:50
Well, it seems that their main issue (compared to "actions" as data and the Reducer as function) is that SAM is by default "sloppy", actions are functions which allow side effects and the model is not a pure function.
Everytime I talk to them the "testability" question always comes back as the major drawback in SAM
Fred Daoud
@foxdonut
May 15 2016 20:54
I see. I think they are misguided in making that assessment.
Jean-Jacques Dubray
@jdubray
May 15 2016 20:55
Even if it was true, I would consider that "testability" cannot be the main architecture driver, it is important for sure, but no more than an efficient factoring of your code that would minimize issues.
Fred Daoud
@foxdonut
May 15 2016 20:57
Besides, if you return a promise from an action in redux, and that gets acted upon by middleware, just because it's not in the action function itself, it still causes a side effect down the line.
Jean-Jacques Dubray
@jdubray
May 15 2016 21:00
yes, that's why IMHO you'll have difficulty isolating the effects from the logic. It's truly a question of "isolation/critical section". You need a place in your code when you are safe to modify the application state and you know nothing will happen (process a new action or display a state representation) until that has happened.
The React model is a bit too "reactive", that that's the issue in general with Reactive programming, they do not provide that "critical section" when things can happen in isolation. They use a function for that, but IMHO, it's too isolated for real-world applications.
The problem with their approach is that the function (e.g. reducer) will create an "effect as data" asking for something to happen, but in reality the application state (i.e. what the reducer is supposed to produce) could be dependent on the result of that effect (success, failure). Looping back that information in the application state can be very hard.
The same kind of things would happen in Cycle.js as well, there the application state is even more encapsulated in the streams.
Jean-Jacques Dubray
@jdubray
May 15 2016 21:05
I am not quite sure where this "purity" is coming from in the sense that even Erik Meijer seems to say that's not a good idea.
Fred Daoud
@foxdonut
May 15 2016 21:07
I'm not sure either, but perhaps it may have been caused in part by the popularity of jQuery a few years ago, and you had large amounts of disorganized imperative code that quickly became difficult to follow and maintain. You change a light bulb in your bedroom, and that causes the radio in the basement to stop working.
It is understandable to want more predictable behaviour in your code, but perhaps they have gone a bit too far and lost sight of some issues just for the sake of this absolute "purity".
Jean-Jacques Dubray
@jdubray
May 15 2016 21:10
yes, that's the problem of wiring events to effects without proper propose/accept/learn phases
The "accept" code should make sure that does not happen and you can test easily because in SAM (and other patterns) V = f(M)
blob
I view this kind of code as highly suspicious:
Unfortunately observables/stream based architectures tend to drive that kind of implementation as well because they do not foster the use of a critical section.
weepy
@weepy
May 15 2016 21:21
When you say learn
Do you mean "wait for external input"
Because it sounds like "do some magic AI"
Jean-Jacques Dubray
@jdubray
May 15 2016 21:22
No, learn means everyone that is interested in the new application state would "learn" about it
no magic at all
weepy
@weepy
May 15 2016 21:23
Right I see
So the view "learns" about the new state of play
Jean-Jacques Dubray
@jdubray
May 15 2016 21:23
yes, that's kind of the idea
weepy
@weepy
May 15 2016 21:24
I never really understood why reactive streams is good anyway
It seems kinda clever
But it doesn't really allow anything more than just dealing with the events directly
Jean-Jacques Dubray
@jdubray
May 15 2016 21:25
That's the role of the State function in SAM, again, you could use pub/sub wiring if you'd like, nothing says you have to use SAM's default wiring
yes, streams as a wiring technology, that's why I warn against using it as a "programming model"
If you look at the view in the TODO sample
The State function decides which "state" of the view to activate
Fred Daoud
@foxdonut
May 15 2016 21:26
@weepy to me SAM is quite the opposite of "magic", everything is quite straightforward. Angular is "magic". Not in a good way.
Jean-Jacques Dubray
@jdubray
May 15 2016 21:27
Then, in a given state, the view decides which components to updates and returns them to the "display"
weepy
@weepy
May 15 2016 21:27
Sorry I wasn't suggesting it was
Jean-Jacques Dubray
@jdubray
May 15 2016 21:28
Here is the part of the code that does that

view.ready = (model, intents) => { 

    // generate the representation of each component
    return ({ 
        todoList: theme.list(model.items, model.displayActive, model.displayCompleted, intents), 
        filters: theme.filters(model.displayActive,model.displayCompleted,model.count,model.completedCount, intents) 
    });
} ;


//display the state representation
view.display = (representation) => {

    // mount each component in the corresponding div
    Object.keys(representation).forEach(function(el) {
        const component = document.getElementById(el);
        component.innerHTML = representation[el];
    }) ;

    // clean up edited field
    const inputField = document.getElementById('new-todo') ;
    inputField.value = '' ;
} ;
Fred Daoud
@foxdonut
May 15 2016 21:29
be back later, but as always @jdubray thank you for the interesting discussion. appreciated.
Jean-Jacques Dubray
@jdubray
May 15 2016 21:29
thank you!
The representation elements map directly to the HTML:
<header class="header">

                <div id="todoHeader"></div>

            </header>
            <!-- This section should be hidden by default and shown when there are todos -->
            <section class="main">

                <div id="todoList"></div>

             </section>
            <!-- This footer should hidden by default and shown when there are todos -->
            <footer class="footer">
                <!-- Remove this if you don't implement routing -->
                <div id="filters"></div>

            </footer>
In general you don't need virtual-dom, it's easy to know which component is changing in a given state
Jean-Jacques Dubray
@jdubray
May 15 2016 22:51
I have connected to Erik Meijer and asked him the question about isolating effects.

I need a bit of help on ES6, I am almost done converting the TODO MVC sample to EC6. I use Traceur and added that code to my index.html file:

<script type="module">
          import {state}      from './mods/state.js' ;
          import {model}      from './mods/model.js' ;
          import {actions as a}    from './mods/actions.js' ;
          import {view}       from './mods/view.js' ;

          // wire the elements of the pattern
          state.init(view) ;
          model.init(state) ;
          actions.init(model.present) ;

          // init
          state.representation(model) ;
        </script>

The UI displays properly from the init statement

but... I get an error when the user click on an action: actions is not defined

Does anyone knows how to "export" from such module?

Jean-Jacques Dubray
@jdubray
May 15 2016 23:02
I checked in the code in the github repository: https://github.com/jdubray/sam-samples/blob/master/todomvc-app/index.html
Fred Daoud
@foxdonut
May 15 2016 23:12
@jdubray : try instead:
This message was deleted
// top of actions.js
var actions = {};
// rest of code... then at the bottom:
export {actions};
Jean-Jacques Dubray
@jdubray
May 15 2016 23:17
I tried but it did not work, I think I figured it out, you need to explicitly define and assign actions
<script type="text/javascript">

            var actions = {} ;

        </script>
        <script type="module">

          import {state}      from './mods/state.js' ;
          import {model}      from './mods/model.js' ;
          import {actions as a}    from './mods/actions.js' ;
          import {view}       from './mods/view.js' ;

          // wire the elements of the pattern
          state.init(view) ;
          model.init(state) ;
          a.init(model.present) ;

          // init
          state.representation(model) ;

          actions = a ;
        </script>
that worked
Fred Daoud
@foxdonut
May 15 2016 23:22
@jdubray oh, I see. this hasn't anything to do with ES6, really. It's because your views use HTML code such as: <label ondblclick="JavaScript:return actions... so actions has to be defined globally.