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
Jean-Jacques Dubray
@metapgmr_twitter
Who needs a new framework? https://remix.run/docs/en/v1/tutorials/blog
it doesn't seem to have state management built in (who needs that anyways?) https://remix.run/docs/en/v1/guides/data-writes#remix-mutation-start-to-finish
Jean-Jacques Dubray
@metapgmr_twitter
That's unrelated to SAM, but this project is near and dear to my heart, we have been busy in my engineering organization building a schema architecture that I designed 12 years ago. GraphQL has been a game changer to realize that design. I expect that this now FOSS project will solve a major pain point in microservices: https://github.com/nav-inc/nav-schema-architecture
Special credit to Michal Scienski, Daniel Zemichael, Jeff Warner, Jovon McCloud and Brent Tubbs. Michal has created a build pipeline that's out of this world. I expect that it will take a life of its own and make a durable impact on low code projects.
For reference, this is the article I wrote 12 years ago: https://www.infoq.com/news/2009/02/message-type-architecture/
GraphQL (as a syntax) and its metamodel deliver an unprecedented DevX.
Jean-Jacques Dubray
@metapgmr_twitter
Here is my post on if-then-else. It's a key aspect of keeping mutations ckearly defined. https://dzone.com/articles/revisiting-switch-and-if-then-else
Gaetano Miranda
@gaemir
Hello all, I am receiving a 404 when loading the dzone article. Is anyone able to load it? Thank you.
Pete Barnett
@petebarnett
@metapgmr_twitter do you have another copy of that article anywhere? i'm really interested in reading it
Jean-Jacques Dubray
@metapgmr_twitter
Sorry, I had made a mistake and the article went back in moderation when I corrected it (for the last couple of days)

In computer science, there is nothing more fundamental and intuitive than control structures. Every student learned about them in the first few weeks of any computer science program. We could not code without them, period. But they are not set in stone: we did get rid of the infamous GOTO in the 80s!

At the pre-ALGOL meeting held in 1959 Heinz Zemanek explicitly threw doubt on the necessity for GOTO statements; at the time no one paid attention to his remark, including Edsger W. Dijkstra, who later became the iconic opponent of GOTO.[3] The 1970s and 1980s saw a decline in the use of GOTO statements in favor of the "structured programming" paradigm, with goto criticized as leading to "unmaintainable spaghetti code"

And this paper is far from being the first call for using less conditional flows in programming. Even Uncle Bob has tackled the topic. In npm alone, countless packages have been published to provide an alternative. People tend to think that the catch with switch and if-then-else is that the more branches in your code, the more opportunities for untested and unexpected behavior. Every branch requires different use cases to be tested thoroughly, and even though, some tools, such as Istanbul, provide some indication as to how many branches have been executed, in addition to the traditional function coverages. But branches are part of the nature of programming, there is nothing we can do about it.

In this short opinion brief, I would like to give a new spin on when to use control structures and when to use some functional alternatives.

Ever since I discovered Dr. Lamport's Temporal Logic of Actions, my programming style has changed to become more explicit about assignments vs mutations of the application state, and more conscious about temporal logic. For me, there are three core patterns to programming: Object-Oriented Programming, Functional Programming, and Temporal Programming. A developer should master all three and use them accordingly, no one pattern wins over the other. We cannot write good programs with one pattern only.

One of the key notions of Temporal Programming is control state: when the light is off, and If the switch is in the off position, I can turn the light on otherwise check the circuit breaker (in bold we have the actions that are expected in a given control state). These are extremely familiar concepts we use every day, yet for some reason, we rarely make the control state explicit in the code we write. My take on it is that situation came about from a lack of alternative constructs, and the ease of use of switch and if-then-else, over the rigor needed to use temporal programming constructs, but that discussion is for another article. I'd like to focus here on something much simpler and actionable today.

First, we must absolutely stop using these control structures for (complex) assignments, it often leads to some pretty ugly code that is hard to read and debug. How many times have you written some code like this? come on, tell me in the comments...

How about a functional alternative?

My code is not new, it is actually heavily inspired by that article from Hajime Yamasaki Vukelic, which probably got inspired by many similar articles. I brushed up his code to make it a bit more developer-friendly and implement some automatic behavior.

We can now rewrite the code above in a functional way and do a proper assignment.

As a side note, my programming style uses named predicates such as exists, rather than writing inline condition functions. It makes the code a lot more readable, maintainable and testable for complex predicates (imagine a bug in a complex condition...).

The matchReduce function composes an array of functions conditionally. That may well be related to monads, but I have no idea since, to this day, I am still looking for a clear definition of what a monad is.

You can find some code examples on how to use match and matchReduce here.

Now we could stop here and say, alright, for all assignments I'll use this functional construct, and if you did that, that

const matched = (x) => ({
  on: () => matched(x),
  otherwise: () => x,
})

const match = (...x) => ({
  on: (pred, fn) => {
    const _pred = typeof pred !== 'function' ? (z) => z === pred : pred
    const _fn = typeof fn !== 'function' ? () => fn : fn
    return _pred(...x) ? matched(_fn(...x)) : match(...x)
  },
  otherwise: (fn) => (fn === undefined ? x[0] : typeof fn !== 'function' ? fn : fn(...x)),
})

const matchReduce = (...x) => ({
  on: (pred, fn) => {
    const _pred = typeof pred !== 'function' ? (z) => z === pred : pred
    const _fn = typeof fn !== 'function' ? () => fn : fn
    return _pred(...x) ? matchReduce(_fn(...x)) : matchReduce(...x)
  },
  end: () => (x.length > 1 ? x : R.head(x)),
})
It allows you to write assignments like this:
Jean-Jacques Dubray
@metapgmr_twitter
const a = match(someValue)
    .on(exists, 'foo')
    .otherwise(bar)
Jean-Jacques Dubray
@metapgmr_twitter
You can use this lib to replace things like
if (xyz === 2) a = 5  
// a = match(xyz).on(2, 5)
or more complex conditions and assignments
if (x == 2 && y > 5) a = x + y
// a = match(x, y)       
//       .on( (u,v) => u == 2 && v > 5, (u, v) => u + v)
//       .otherwise( (u, v) => u - v)  // a = x - y
As I mention in the article, I prefer a style nowadays where all the predicates are named functions:
const p = (x,y) => x == 2 && y > 5
Jean-Jacques Dubray
@metapgmr_twitter
the assignment looks like (you can also use values instead of functions in the assignments:
const a = match(x,y)
                .on(p, x + y)
                .otherwise(x - y)
Jean-Jacques Dubray
@metapgmr_twitter
Jean-Jacques Dubray
@metapgmr_twitter
Best wishes for the new year. 2021 was a special year for me, I had brain surgery exactly 3 weeks ago to fix a pinched nerve and the surgery was successful. Science is just amazing, just a hundred years ago I would have been dead as my condition is part of the suicide disease family because of the level of pain it creates. I am like new! It was also a great year professionally and for SAM in particular with the development of sam-fsm. I hope 2022 brings you health, happiness, and success.
JohnGurin
@JohnGurin
:wave: Happy New Year!
Jean-Jacques Dubray
@metapgmr_twitter
My company is hiring for pretty much any position (US remote or in-office UT, CA, PA). We are in a good place and a happy bunch of people. https://www.nav.com/company/careers/current-openings/
Daniel Neveux
@dagatsoin
happy new year everyone, great to read that your operation was a success. It is a relief, sincerely. You made my day !
Pete Barnett
@petebarnett
@metapgmr_twitter happy new year and congrats on the good outcome. I cant imagine how that must have affected your life to date. Huge respect for coming through that. Best wishes for the year to come!
Jean-Jacques Dubray
@metapgmr_twitter
@dagatsoin @petebarnett Thank you! Truly a miracle of science and talent from the OR team.
Aaron W. Hsu
@arcfide
I'm getting back into some web development projects, and I've been reading about SAM rather curiously (especially the links with TLA+). I'm trying to understand how the Svelte and SAM philosophies may or may not overlap, conflict, or compare. I didn't see much in this respect. Does anyone have any opinions on this? I'm tempted to just explore using SAM directly in Vanilla JS (maybe with Web Components), but I'm a little out of touch with the state of the art these days.
Jean-Jacques Dubray
@jdubray
Welcome @arcfide ! I had tried to use SAM with Svelte several years back unsuccessfully, I am not sure where things are at right now and if it would be easier/possible. In general, the closest to SAM's philosophy is Vue with Vuex (Action-Mutation-State). Do you have a pointer to current practices for state management in Svelte?
Aaron W. Hsu
@arcfide
@jdubray I'm afraid the best that I have is the introduction article to Svelte 3 in 2019, in particular, the philosophical platform for reactivity in the section "Moving reactivity into the language." From what I can see, the V = S(M) equation is fulfilled mostly by the S() function taking the model and then updating the appropriate state variables (there are things like contexts and the like for managing and coalescing state into global, cross-component "contexts"), whereupon the View just gets updated automatically. Assuming you don't go the other way and make use of Svelte's update mechanisms within components to update those same variables from components, I think you could call that the SAM pattern. I'm not sure if that's a good fit or not, though, as I'm not super experienced with web-side implementations of the SAM pattern.
When I mean state variables, I mean variables that were used as parameters into Svelte components and that a Svelte component is reactive to, not the Model or State in the TLA+ sense.
I think I'm probably not going to use Svelte for other reasons on this next project, but I'm still curious as to the compatibility and philosophical differences, since I remember Svelte being much nicer to use than the other systems for me when I used it a few years ago.
Aaron W. Hsu
@arcfide
I have a question about the SAM pattern wiring example. In the model, it runs state(model) first and then model.persist() after that. This means that potentially the View could be updated with a state that might be incorrect or inconsistent with the persistent model if the persist() fails for some reason. This would mean that the view could temporarily show an incorrect data to the user, yes?
I would have expected the persistence to be done first and only after successful persistence assuring that the data is faithfully retained for the View to render.
Jean-Jacques Dubray
@jdubray
@arcfide what example are you looking at?
There is definitely a choice to be made on when the state representation is computed and shared with the view. The reason for that is NAP (next-action-predicate). My interpretation of how this should be done is that the predicate that is firing based on the current control state (by returning true/false) decides whether the view can be shared or not. If not, this is equivalent to a synchronous reaction to the proposal. The model is in a state where an action needs to happen and depending on the result, (say assuming no next-action fires) then the state representation can be computed and released.
Jean-Jacques Dubray
@jdubray
Theoretically the model is synchronized (and really must be for SAM to work correctly), however it is your choice if your application can handle synchronized persistence or if you need to rely on the next-action to persist the model. In theory it should always be done in the next-action, in practice, if you are nor expecting any event while you persist your model state, then you can do it in the model. Does that make sense?
Aaron W. Hsu
@arcfide
@jdubray I'm looking at this: https://sam.js.org/#wiring
Aaron W. Hsu
@arcfide
The way I'm seeing the reading of that code, say, where you to one action that will then trigger another action is a sequence of operations in time as: action1 → present → state → NAP → action2 → present → state → NAP → Render → persist → persist → ⊥. So, in this case, it seems that the rendering will occur before persistence and that the persist functions will get called twice on the same state, with the first state before the second action triggering never being persisted.
Is that a correct interpretation?
I understand the idea of not rendering until there are no next actions to perform. This could result in a long chain of actions that need to occur before the view is updated again. The question I'm wondering about is the double persist calls as well as the call to render before the calls to persist happen. In my head, it seems like we should never render data to the user that we haven't verified has succeeded in persisting on the backend. No?
Jean-Jacques Dubray
@jdubray
@arcfide The wiring will depend on your architecture. SAM is highly isomorphic and you can run parts or all of the pattern on the client and/or the server. I have shown it with SAM-SAFE https://github.com/jdubray/sam-safe
Jean-Jacques Dubray
@jdubray
There is no one way to wire the pattern and will depend on optimizations/trade-offs you want to make. My general assumption for classical UIs is that the user is only interested in a UI change once the persistence of the state has been completed (with or without errors), that's why I generally recommend invoking any persistence API directly from the model, though it is incorrect, it's just an approximation. In the case where you want to continue processing events -> action -> proposals you have to adopt a different strategy. The strategy that always work is the one I described above where the next-action predicate controls the rendering, though you will quickly run into some hard questions depending on the events you want to process while persisting the state. I would not be too concerned about too many NAP loops, in practice that does not happen. That's why I created SAM-FSM because NAP usually maps well to automatic actions in a finite state machine. What SAM brings to that picture is that it positions your code precisely with respect to the FSM. I don't know if you tried to "code" with an FSM paradigm in the past but in general you quickly hit a wall because FSMs don't align well with structured programming, it's one or the other. SAM makes them coexist nicely. Dr. Lamport doesn't like to talk about FSM, he talks about this PC (program counter) variable, but in essence, that's the control state of an FSM weaved into a TLA+ specification.

So I would not be concerned by that, in practice I have not seen it happening:

This could result in a long chain of actions that need to occur before the view is updated again

And not every proposal would result in a persistence call, there are parts of the application state that you do not persist. But again it depends on your architecture (client/server) and which parts of the pattern run where. When the model is on the server, you need to persist its entire state regardless, so that it can be retrieved to process every proposal in a synchronized fashion. When the model runs in the browser, there is no need to persist its entire state. You would only persist user entries (either directly in the model when the UX allows it) or via next-actions.
Aaron W. Hsu
@arcfide
@jdubray Thanks for taking the time to try to explain this, but I think the core issue is still being lost. The core issue isn't about how many action chains or the like occur between rendering, it's the inconsistency I'm seeing between the example wiring logic and the claim you made above and elsewhere in the sam.js.org page that the rendering would only happen once the persistence operation was completed. In the example wiring, the persistence will only ever happen after rendering, not before if I read the code correctly. That's my core misunderstanding, because everything else says that it should be the other way around.
Aaron W. Hsu
@arcfide
Secondary to the above, is a separate issue I have, which is trying to understand the statement you made about persisting in the model not being "correct" (from a theoretical standpoint). I believe from this and reading above in your previous responses that you are saying, "in theory it should always be done in the next-action," but that's ambiguous to me because the term next-action isn't precisely constrained enough for me yet. Did you mean there that there should be dedicated code in the Next Action Predicate (NAP) that handles persistence, or that persisting the model should be considered a separate Action that is triggered automatically from the NAP due to changes in the model state? Or, another way of interpreting the above might be that you have persistence occurring in the State(M) function before or after calling the NAP(SR).
Thirdly, as a separate issue, it's not clear to me why persistence in the model is theoretically approximate versus the other (currently ambiguous) alternative. I could accept that it is, simply because the pattern says so, but you seem to indicate that there's something deeper there.
I should say that I've used FSMs in the past and found them quite helpful, and I didn't find them particularly difficult to use, though I used Powell's Cleanroom SWE approach to sequence-based enumeration to design and work with FSMs, as I found it the most helpful there.
Aaron W. Hsu
@arcfide
My comment about long chains wasn't a value judgment one way or the other, just an attempt to verify that I correctly understand the semantics of the pattern, which is that the triggering of an action can occur via NAP theoretically for a long time. However, actions do not have a guaranteed order of arrival (because many could be submitted at a single time, and the actions are theoretically asynchronous), so the NAP triggered action would just be going onto a "queue" of actions for the model to continue to process. So, the view could trigger two actions A1 and A2, and when A1 is processed (each action is process synchronously by the model, though their arrival order is non-determinate, yes?) it could trigger the NAP to launch A3, which may or may not arrive to the model before A2 is queued and acted on, yes? So the order of action processing in such a situation could be A1 → A2 → A3 or it could be A1 → A3 → A2, yes? I just want to make sure that I understand the relationship and where the synchronization boundaries really are, and such.
Aaron W. Hsu
@arcfide
Finally, it seems that if one were designing a GUI, there are GUI level states that need to be retained in the model that might not be totally related to your semantic model, but rather are necessary for updating visual rendering of the GUI, which in the SAM pattern would ultimately be retained either in the model or derived from the model via the State function, yes? So, for instance, I'm thinking here of a waiting/loading bar or spinner. If you click a button that need to fetch new data in the model and populate some fields, then you would want the loading UI to show up to show that the request is in progress, but you couldn't have the View update itself to change to the loading bar, nor the Action that is triggered, because neither are supposed to mutate the View/SR, but rather, the action needs to run through the model, and the model might respond with a new state property Updating: True or the like, and then the View would render based on that new property, and then when the model was fully updated, a new state representation would be triggered, yes? However, in this case, I wonder how this two phase rendering would be appropriately (theoretically correctly) handled in the pattern. Would the model just initialize the update first to trigger the waiting UI and then wait for a second action to retrieve the data (since the model has to be synchronous) or would the model somehow send two updated states at different times from that single action request?