Comment by nfw2

4 years ago

I have worked as an engineer on products in a lot of different domains in my career including:

- edtech

- real estate

- HR/payroll software

and every single project I've worked on had enough complex state to benefit from using a SPA.

I've also worked on one complex web project run by someone dogmatically against client-logic, and it was absolute hell. The codebase was full of janky hacks to approximate the same complex session state and full interactivity that a SPA provides trivially.

This whole thread seems like a huge echo chamber of people who seem annoyed that FE development is getting too complex.

But do you all really think that the entire industry is so disconnected from its needs, and the entire community of FE engineers just have their heads in the sand about the requirements of working in their domain of expertise?

And to everyone saying SPAs are sometimes useful in very rare occasions, what web apps do you use regularly? Gmail? Jira? Slack? LinkedIn? Figma? Notion? Docs? Dropbox? Airbnb? Netflix? Airtable? ...

How many of these use javascript to do the heavy lifting on the client?

In your experience how often did the complex state have to be modelled on the backend as well as the frontend, to provide validation of submitted data?

And for personal interest, how did you handle streaming in updates and edits from multiple people, and stopping people from editing eg the same real estate listing at the same time? I know it can be done but I find it easier with server round trips for every request.

  • As for your question about persisted data, yeah it definitely needs to be modeled on the backend, right? How much modeling should be done on the FE is a good question. This question is sort of why GraphQL exists. GraphQL provides a contract between the backend and the frontend about what the data sent between the two needs to look like. Apollo provides a pretty good and easy-to-use GraphQL implementation in my experience.

    As for real-time updates, this hasn't been a real concern in most of my professional work. If I needed to support this, I think what I would do is:

    1.) Define a clear set of actions for everything that needs to be streamed to users real-time (IE, I wouldn't try to stream the full state tree itself, this is where conflicts would arise)

    2.) Determine how each action mutates the graphql tree

    3.) Add a process that watches for these actions at the top of the React tree and manipulate the GraphQL cache as necessary in response to the incoming actions, (coming from a WebSocket connection, for example).

    If you stream the actions, you may be able to resolve simultaneous edits naturally. Or, if you really want to block simultaneous edits, I think you should 1.) definitely ensure the edit is really blocked on the backend, and 2.) stream on "disable" action to the user via webso

  • State is a pretty loaded word, but what I meant more specifically is complex application state, and by that I mean the ephemeral state that manages a user's usage of the application.

    For example, in the real estate use case, there may be, all on the same page:

    - a table of listings and grid of listings that can be toggled between

    - a map that can be displayed alongside the table with all the listings plotted

    - dynamic updates on the map that highlight listing when it is hovered on the table

    - a detail modal that displays whenever any listing on the table or map is clicked

    - pagination that can controlled from either the modal or the table

    - selection state for each row on the table and a bulk action bar that conditionally appears when the row is selected.

    - filters and search that need to work quickly and not disrupt the user experience

    None of these things are particularly unusual or groundbreaking, but trying to control all these stuff via server-rendering or jquery would be a huge mess and potentially a jarring UX.

  • These are good concerns. IME it's important to be able to share code and schemas & domain data manipulation code between BE and FE like you can do eg with Clojure + ClojureScript.