Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
  • May 16 17:07

    dependabot[bot] on npm_and_yarn

    (compare)

  • May 16 17:07
    dependabot[bot] closed #51
  • May 16 17:07
    dependabot[bot] commented #51
  • May 16 17:07
    dependabot[bot] labeled #80
  • May 16 17:07
    dependabot[bot] opened #80
  • May 16 17:07

    dependabot[bot] on npm_and_yarn

    Bump nodemailer from 2.7.2 to 6… (compare)

  • Apr 09 05:31
    dependabot[bot] labeled #79
  • Apr 09 05:31
    dependabot[bot] opened #79
  • Apr 09 05:31

    dependabot[bot] on npm_and_yarn

    Bump moment from 2.24.0 to 2.29… (compare)

  • Apr 08 22:56
    dependabot[bot] labeled #78
  • Apr 08 22:56
    dependabot[bot] opened #78
  • Apr 08 22:56

    dependabot[bot] on npm_and_yarn

    Bump moment in /angular4-Bootst… (compare)

  • Mar 02 07:53

    dependabot[bot] on npm_and_yarn

    (compare)

  • Mar 02 07:53
    dependabot[bot] closed #69
  • Mar 02 07:53
    dependabot[bot] commented #69
  • Mar 02 07:53
    dependabot[bot] labeled #77
  • Mar 02 07:53
    dependabot[bot] opened #77
  • Mar 02 07:53

    dependabot[bot] on npm_and_yarn

    Bump karma from 4.0.1 to 6.3.16… (compare)

  • Mar 01 23:56

    dependabot[bot] on npm_and_yarn

    (compare)

  • Mar 01 23:56
    dependabot[bot] closed #67
Aaron W. Hsu
@arcfide
Additionally, let's say you have a push-style Representation wiring to the View, and the View does a "request" to the State with filter parameters like you suggest, the State is not permitted to cache or retain that state (it's a pure function over the model), so if an update to the Model occurs which changes that data, the filter will be lost and only the unfiltered data will be sent on the next update of the View.
Aaron W. Hsu
@arcfide
BTW, thank you for taking the time to help me clarify this pattern.
Daniel Neveux
@dagatsoin

The pattern is unidirectional

Indeed, and asking something to a Service maintained by a State function is not against this rule, as long as the Service will provide readonly endpoint.

The only thing the View can send "out" is an Action, no?

The View have a full read access to the Representation as it is how the SAM container want to be seen by the external world.
Think at a painting, which is the Representation of the mind of an artist (the Model). You can totally see in any angle you want through your own filter (through glasses, phone, you own reproduction...)
But you can't alter it without violate it. You can't paint on it without changing its identity. (yes, you can, but you will get into trouble)

It is the same for our app. You can either get the full file and do the filter on your computer. Or the SAM Container can expose an API (like in the blog example) to serve the Representation with or without predefined or customizable filters. No one will modify the model through this.

the State is not permitted to cache or retain that state (it's a pure function over the model)

The purity of the State fn is not mandatory as long as its guarantee one thing: the Representation is in sync with the Model. The purity is just an easy way to achieve this.

Daniel Neveux
@dagatsoin
(plus I don't think you need to retain the filters, as long as the client can send it each times it needs)
I will go to sleep. I would be glad to continue tomorrow if you want.
Aaron W. Hsu
@arcfide
@dagatsoin I think I have some more clarity after studying some more SAM examples, including the TODO example. The TODO example includes a filter feature, and the filtering is done in the State Representation but the filter itself is defined and stored in the Model and updated via Action. I think combined with the use of Next Actions this provides an adequate solution that maximizes purity and retains simplicity in the Model itself while letting me handle caching, spinners, and the like. I'm going to try implementing something and see how it plays with the model. I think the primary thing I wanted to make sure I properly understood was where the actual filtering logic fits in, and if you're not querying a 3rd party backend for the data, the only place where it makes sense to put the filters is in the State funciton.
That is, the way I'm looking at it, is if I were implementing a SAM pattern on top of some datastore for a backend API that I was writing (ignoring any frontend stuff), what would that Headless SAM pattern look like, and where would the results of an API query go? I think the answer is that it would have to go into the State Representation code to send back the result. This is at least what is modeled in the Todo demo.
Daniel Neveux
@dagatsoin

(ill baby, 4am...)
What putting in the model is just a design decision.
My SOC mindset for a project like the bank example is to think as business/functional first. I will never mix UI concern like loading state or filtering with business concern like user financial data.

But SAM being just a pattern, it will work all the same if you put any domain together in the model. No doubt on that.

To push the example further. If I need to persist some UI state between screens (loading state, recent keyword search, etc.), I would use a second SAM container to handle this.
This container may be on the View, so completely separated from the Server SAM container.

Daniel Neveux
@dagatsoin

what would that Headless SAM pattern look like, and where would the results of an API query go?

For a REST API :

  • I would handle GET queries as actual Representation getters.
  • I would handle PUT/POST/DELETE as Actions given the fact they will mutate the model.

For a GraphQL end point, I would do the same but with queries and mutations.

Daniel Neveux
@dagatsoin

You have a good example of this in the SAM SAFE example. https://github.com/jdubray/sam-safe/blob/master/server-model.js

  • Look at the init endpoint. It is just a getter on the current View (let's say View = Representation). Here it is empty but we can imagine sending a authorId in params or other filters to retrieve a subset of blog posts.
  • The second endpoint is just the Present function (actions are on clients)

This is a good exemple of SOC, the filtering is done on the Representation and the only available mutable interface is the Present endpoint.

Daniel Neveux
@dagatsoin

For a GraphQL end point, I would do the same but with queries and mutations.

note that GraphQL is a very elegant facade for SAM pattern when you have Client[View, Actions], Server[State,Model] because they provide a clear semantic which perfectly feats with SAM interface.

  • the client actions will send their proposal as GraphQL mutations.
  • the client view will query the Representation with only what it needs with the destructuring magic of gql.
Aaron W. Hsu
@arcfide
@dagatsoin I think I've figured out the design that you've laid out, thanks! I'm not sure I agree with the value of having a GET API to a Representation, but I appreciate the design at this point at least.
Jean-Jacques Dubray
@jdubray
Someone unrelated to SAM but still relevant to the overall full-stack architecture, a presentation of Nav's Schema Architecture at GraphQL Sydney Meetup https://www.youtube.com/watch?v=NoZ9cjob0aI
Daniel Neveux
@dagatsoin
👀
Daniel Neveux
@dagatsoin
@jdubray I watched the NAV presentation. It is very interesting. I think it solves a real problem for teams and client integration: minimize boiler plate and consolidate dev quality across team.
Very nice job :clap:
Jean-Jacques Dubray
@jdubray
thanks, yes, it's an area of microservices architectures that is underserved if not ignored. Thank you for the feedback!
Aaron W. Hsu
@arcfide
I think one of the main things here I have to recognize is that my org is taking a fundamentally alternative/different approach to the way that most people architect their systems today because our human structure and competencies are intentionally different than your typical layout, so the traditional architectures introduce significant pain points for us.
Edward de Jong
@CodingFiend_twitter
@arcfide perhaps your application could use the SAM style that Beads language facilitates. In Beads you have a server, presumably a RAM database of some sort, that clients subscribe to some subset of the mutable state. And then invisibly and atomically, the state is replicated on the client machine. To make changes to the mutable state, the client issues remote function calls. These calls don't return query values, but instead make changes to the mutable state which then come back to the client via the subscription channel. In this way you can avoid the common REST type of interfaces. Yes you can also go into web sockets and package messages, but then you don't have any advantages any more. The real magic happens when you utilize the ability of the client to redraw only that part of the GUI that was affected by most recent state changes, so as to minimize refresh.
Aaron W. Hsu
@arcfide
@CodingFiend_twitter I'm using an architecture that is pretty similar to that now, and it's working well. I think I've also adequately addressed the issue of minimal client redraw, and have a workable architecture in place. Thanks everyone for the help.
Jean-Jacques Dubray
@metapgmr_twitter
Fascinating presentation in the context of the work of Dr. Lamport (specification/proof) https://youtu.be/HeQX2HjkcNo
Jean-Jacques Dubray
@jdubray
MikeJMontgomery
@MikeJMontgomery
Hey @jdubray I'd love to get your initial thoughts on how modeling can be used in real world small to mid-size projects using the SAM pattern. I'm thinking maybe the SAM pattern can be incorporated into future low-code platforms as a way to handle different modeling and programming paradigms. This might be a partial solution to the fragmentation of modeling that's prevented MDE from taking off, as you summarized in one of your previous articles in Infoq. In this scenario, incorporating SAM wouldnt solve all this problems with current modeling and emerging approaches for code generation. But it might get us closer to generating at least some code from static models in small to mid-size projects, without using MDE approaches that haven't taken off, or building DSLs. Again, much to be said here, so I'm just looking for your initial thoughts. Thanks
Jean-Jacques Dubray
@jdubray
@MikeJMontgomery actually made me less a believer in no code/low code MDSE approaches. A lot of model-based programming solutions were designed to deal with hard to write code, such as application state management and long running activities (say BPEL). But SAM makes reasoning, writing and maintaining that code a lot easier. Now the other side, since writing that code is easier, it should also be easier to create a low code layer on top of it. Maybe, I am no longer a big fan of MDSE. I spent 15+ years of my career trying to push that boundary, I would argue unsuccessfully. I understand that it's not because I failed, that everyone would fail, but I have not seen something that I would call success, say other than spreadsheets or on the magnitude of spreadsheets. Even something like Interface Builder that I used to love in the 90s and that inspired most of my career has not aged well. If UI, application state management and long running state management are easier to write in code, I am not sure what's left for MDSE.
2 replies
I would look at STAR (State, Type, Action, Relationship) as a way to explain the lack of success of MDSE. As I explained, programming languages tend to be biased towards the physical view of semantics (Types and Actions) and rely on developers to code the conceptual view (State and Relationship). MDSE has tried to address that imbalance, as I said, without much success. IMHO, the industry should spend its time building a STAR-based programming language (including temporal semantics).
littleone
@happy-little-one
result.innerHTML = state.render(model.present(data)), little confused about this, no view ? state return the html code directly?
Daniel Neveux
@dagatsoin
@happy-little-one yes, simplest code in SAM can be very confusing .
  • the view is the thing that uses the whole container. In this case it is the DOM element behind result
  • state can return what ever you want. A full HTML page, a file, a string, an entire app...
Daniel Neveux
@dagatsoin

(late edit)

the view is the thing that uses the whole container.

In the sense that the view is the client of the SAM container, like a App in the browser is the client of a REST API service. It is conceptually totally decoupled.

Jean-Jacques Dubray
@jdubray

@happy-little-one that was an attempt at explaining how the pattern works (and some of its parts). It also dates from the time where "functional HTML" was new. Way back in 2016, even the React team was confused about that concept.

V = f(M)

If you want to learn about SAM these days, it's best to start here: https://www.npmjs.com/package/sam-pattern
Jean-Jacques Dubray
@jdubray
Otherwise, state.render(model.present(data)) means: render the state representation as a function of the model after an action presents a proposal to the model (and the model updates).
littleone
@happy-little-one
@dagatsoin so state is the consumer of model ,in that way, it is more like a view, SAM became VAM...what's the difference between state and traditional view?
9 replies
littleone
@happy-little-one
@jdubray thanks, I'm now a little tired of the frameworks too, trying to do everything manually, sam-pattern is a good starting point. but not enough, I also wander how to implement a component, how to structure a whole app, any tutorial about this?
Jean-Jacques Dubray
@jdubray
I am not the best person to design a whole app. I have implemented a commercial analytics app for a startup and an order management system for Intel in 2017 with SAM, but that's my last major front-end work.
All I have is the samples from the sam-pattern library.
tommwu
@TWCM
Hi @jdubray , i'm trying to use the getIntents() in sam-pattern but always get the empty array in getIntens().intents from the global instance, i already added the component to the global instance, and use api() to get the global instance. Any example of using getIntents() function, Thanks.
Jean-Jacques Dubray
@jdubray
@TWCM do you have a code sample to share? The best is to look at the unit tests, there should be all the functions of the library. https://github.com/jdubray/sam-lib/blob/master/test/sam.test.js
That's how you get intents from a set of actions:
const intents = SAMtest({
      component: {
        actions: [
          () => ({ test: true }),
          { label: 'LABELED_ACTION', action: () => ({ labeledAction: true }) },
          ['ANOTHER_LABELED_ACTION', () => ({anotherLabel: true })]
        ]
      }
    }).intents
    tick = intents[0]
    labeledTick = intents[1]
    anotherLabeledTick = intents[2]
  })
getIntents is just a convenience wrapper to that initialization using SAM's global instance:
getIntents: actions => SAM({ component: { actions } }),
My expectation is that if you pass this array:
const actions = [
          () => ({ test: true }),
          { label: 'LABELED_ACTION', action: () => ({ labeledAction: true }) },
          ['ANOTHER_LABELED_ACTION', () => ({anotherLabel: true })]
        ]
It should work getIntents(actions).intents.
tommwu
@TWCM
@jdubray I want to reuse the existing actions in the global instance "SAM" , so which function can achieve this? here is my code, seems like the getIntents is not what i want.
    const test = api();
    test.addComponent({
        actions: [
            async (username, password) => {
                let user = null;
                const response = await fetch("http://127.0.0.1:8000/api/auth/token", {
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json"
                    },
                    body: JSON.stringify({
                        username,
                        password
                    })
                });
                const data = await response.json();

                if (response.status === 200) {
                    user = data;
                }
                return { user: user };

            }
        ],
        acceptors: [

            model => ({ user }) => {

                console.log(user);
                model.user = user;
            }
        ],
        options: {
            ignoreOutdatedProposals: true
        }

    });
    test.setRender(state => {
        if (state.hasError()) {
            console.log(state.errorMessage())
            state.clearError()
        }

        console.log(state);
    });

    console.log(test.getIntents());
Jean-Jacques Dubray
@jdubray
this is not how it works (though your code is logical and I could/should have implemented that way).
you just get the intents as SAM.intents
SAM being the global SAM instance. You can create as many SAM instances as needed.
The best is to look at the vanilla.js sample: https://github.com/jdubray/sam-samples/tree/master/todomvc-app
Jean-Jacques Dubray
@jdubray
As you can see the intents are returned by addComponent. The reason why I chose to do it that way is because you always need them to wire them to your view. There is never a case where the intents are not used in SAM since they are the entry points to the pattern.
            const { addInitialState, addComponent, setRender } = tp

            // your application implementation
            import initialState from './sam/initialState.js'
            import todo from './sam/todoComponent.js'
            import createFrom from './sam/theme.js'
            import { display } from './sam/display.js'

            // wire it up
            addInitialState(initialState)
            const { intents } = addComponent(todo)
            setRender([display, createFrom(intents).representation])

            // start your application
            displayAll()
tp is the singleton representing the pattern in the browser. The equivalent of api()