[HN Gopher] UI = f(statesn)
       ___________________________________________________________________
        
       UI = f(statesn)
        
       Author : todsacerdoti
       Score  : 77 points
       Date   : 2024-02-16 16:35 UTC (6 hours ago)
        
 (HTM) web link (daverupert.com)
 (TXT) w3m dump (daverupert.com)
        
       | taeric wrote:
       | I am growing into the idea that everyone should try and build
       | some games. Just a "simple" card game like solitaire would
       | suffice for a lot of the lessons.
       | 
       | Biggest one being that anything you want to be able to do
       | visually has to be represented somewhere as state. Pretty much
       | period. And this state will be far more complicated than the
       | simplified state diagram that you will come up with if you are
       | only modeling the intended actions of a game.
       | 
       | If you are lucky with extra computing power, you can layer your
       | code so that the core rules of the game are able to be written
       | independently of how you represent the cards in play. But I
       | assert that you will often be surprised that accomplishing this
       | separation is more code than the alternatives.
        
         | cushpush wrote:
         | People who say the universe is a simulation never consider the
         | graphical overhead required. It'd be so annoying to make, I
         | don't believe even an alien species would have the patience for
         | it.
        
           | ikari_pl wrote:
           | AI had the patience, Mr Anderson
        
           | serial_dev wrote:
           | They (we?) could use AI for that, why would you write it by
           | hand?
        
           | p0w3n3d wrote:
           | It's simple. You just create set of rules that will
           | eventually end up in earth being created. Just requires you
           | to be God
        
           | 01HNNWZ0MV43FF wrote:
           | "Red shift is a feature, not a bug!"
        
         | solardev wrote:
         | I would love to try something like that, but I have no idea how
         | to model complex game logic like that in data, especially if
         | it's decoupled from the UI state =/
         | 
         | For example, to make even a "simple" game on something like
         | Boardgamearena, you're supposed to create a state machine:
         | https://www.slideshare.net/boardgamearena/bga-studio-focus-o...
         | 
         | I don't even know what that is, and it's a lot more complicated
         | than anything I'd ever seen on the frontend in the HTML/JS
         | world. (To be fair, that's probably because I never had proper
         | CS training. I'm just a self-taught web dev.)
         | 
         | But it seems to me that even simple games require creating
         | really complex engines that aren't really similar to the
         | businesses needs I've coded for in the past...
         | 
         | Not disagreeing with you at all, it all just seems so
         | overwhelming compared to simple stuff like HTML/CSS/JS.
        
           | matthewfcarlson wrote:
           | Even better, make a simple networked game. Socket.io makes it
           | quite trivial to send messages. What I found works really
           | well is keeping state as a series of mutations. Then a client
           | emits a mutation and its broadcast out, if the mutation can't
           | apply, then it gets discarded and the server sends its copy
           | of the state to the client that emitted the bad mutation.
           | Makes it really hard to cheat but only requires sending
           | mutations to the clients.
           | 
           | https://matthewc.dev/projects/vuex-sync-p1/
        
           | swatcoder wrote:
           | That's sort of the point.
           | 
           | A lot of people got drawn into the industry in its latest
           | boom and found themselves glueing together remote services
           | using an ever-changing collection of heavy frontend
           | frameworks and never experienced actually modeling an
           | application from top to bottom. It doesn't need to be a game,
           | but doing more of the dirty work that "[you] have no idea how
           | to model" andis "more complicated than anything [you]'ve ever
           | seen" can help induct you into a much richer and more
           | cognizant craft practice.
        
             | solardev wrote:
             | This isn't so much the old argument of (say) Next.js v
             | HTML(x), but of the different degrees of state complexity
             | required in a typical business app vs an actual game (at
             | least to my mind).
             | 
             | To me, it's a lot clearer how to deal with a traditional
             | ecommerce database setup like Northwind Traders (https://en
             | .wikiversity.org/wiki/Database_Examples/Northwind). I've
             | had to do that many times and know how to model such a
             | thing.
             | 
             | I have no idea how to start modeling the state for a game
             | like Wingspan
             | (https://boardgamearena.com/gamepanel?game=wingspan), much
             | less something more complicated, like Magic: The Gathering,
             | where any of several tens of thousands of cards can
             | interact with each other in novel ways, maybe even leading
             | to infinite loops and such. In my mind it's like a giant
             | if-then flowchart with a billion flows. I wish I could see
             | the source code for the rules engine of such a thing, but
             | with a step-by-step tutorial...
        
           | taeric wrote:
           | Honestly, feel free to do it in HTML/CSS/JS. The goal isn't
           | to go as hard as you possibly can, simply to start realizing
           | how much more "first class" knowledge of items on the screen
           | you probably want.
           | 
           | One thing I will caution is to not try and lean into making
           | DOM layout do what you want. Represent the different elements
           | as divs that are absolutely positioned, and you can go a long
           | way. You'll probably still want a lot of seemingly duplicated
           | data in places that you control directly, but that is part of
           | the point.
        
           | mathgladiator wrote:
           | I'm in the camp of f = ui(state), and the reason for this is
           | the extreme of streaming games where UI = frame buffer. I'm
           | inventing my own framework for radically simplifying
           | traditional Web apps via RxHTML which works great for crud
           | apps. However, games requires more insight into state
           | machines and what-not.
           | 
           | In terms of the logic, I wrote an entire platform to simplify
           | multi-player board games which I'm evolving to tackle various
           | businesses. https://www.adama-platform.com/
        
         | TacticalCoder wrote:
         | > Just a "simple" card game like solitaire would suffice for a
         | lot of the lessons.
         | 
         | I've written an actual game, a 2D platformer.
         | 
         | If there's a domain where it's easy to demonstrate that the
         | view is purely a function of the state it's precisely in
         | gaming. In many games you can toggle (in dev or even for some
         | during gameplay) between "the real view" and, say, wireframe
         | view of the game (with lots of debug infos added too for
         | example). Or you can toggle between a 3D view of your game or a
         | top-down 2D one. Or you can toggle between different types of
         | rendering (as in Diablo 2 where both a 2D and fake 3D view
         | where available and the modern Diablo 2 ressurected, where you
         | can you can show... The 25 year old view if you want to, at any
         | time).
         | 
         | Many games are 100% deterministic and the entire game user(s)
         | played can be recreated from only a record of the user(s)
         | inputs (which is why some save files for long games can be
         | tinier than tiny). And it'll replay the same on different
         | screen configurations / different platforms.
         | 
         | The view in a game at time _n_ is literally f(state n).
        
           | taeric wrote:
           | Certainly! That was indeed my intention here. The big
           | learning I'm intending is just how much state that people
           | take for granted is necessary to track.
        
           | ape_key wrote:
           | respectfully you haven't written enough games
           | 
           | > real game
           | 
           | turn-based and real-time games have different kinds of
           | complexity, so a platformer won't expose you to all of it.
           | 
           | turn-based games are roughly going to give you an easier time
           | separating the game code, but the UI code is going to feel
           | like a debilitating slog.
           | 
           | > Many games are 100% deterministic
           | 
           | Until you use floating points, networking, or different
           | platforms.
           | 
           | This is more likely to be true in turn-based games, and super
           | unlikely in anything real-time and multiplayer.
           | 
           | Most games like that periodically sync state instead of
           | relying on applying actions on each client
        
             | amelius wrote:
             | Are you saying that IEEE 754 floating point (which
             | everybody is using) is not deterministic?
        
               | politician wrote:
               | You have to be careful with comparisons. In JavaScript,
               | for instance, `(0.1 + 0.2) != (0.3)`.
        
               | amelius wrote:
               | Well that doesn't make it non-deterministic in behavior.
        
               | ape_key wrote:
               | go ahead and read about deterministic networking
               | 
               | instead of approaching in bad faith
        
       | bjnewman85 wrote:
       | UI=F((irreducibleComplexity + poorDesignChoices +
       | poorArchitectureChoices + techDebt + bad coding + states)^n). The
       | author mixes web and native UI development here to encompass a
       | partial range of possible UIs, there's obviously a lot more
       | complexity in UI development if we expand that list to include
       | AR/VR, CLIs, voice-based interfaces, etc.
       | 
       | But also most software UIs we are building today are overly
       | complicated. Because devs forget f() is supposed to narrow the
       | complexity space to match the users needs, by making illegal
       | states unrepresentable.
        
         | jimberlage wrote:
         | TBH - I find the opposite is true. Far more complaints have
         | been of the form "this isn't an illegal state, the dev
         | mistakenly thought so because they're not a domain expert - why
         | won't they let me do this?"
         | 
         | And some illegal states are useful. Letting a form exist with a
         | field the user can't fill out, along with disabled logic and a
         | helper message, is often the best way to onboard users to your
         | tool. Lots of proponents of making illegal states
         | unrepresentable take those fields away so they don't have to
         | muck with validation logic, which takes away your best way to
         | explain how to use your tool to a user.
        
           | bjnewman85 wrote:
           | i would argue that any state that is useful should not be
           | illegal, but i agree with you that people have often used
           | that phrase to mean what you said
        
           | hombre_fatal wrote:
           | That's not criticism of syncing possible states with expected
           | ones.
           | 
           | e.g. Not having a disabled={condition} on some input field
           | isn't going to change the fact that the client wasn't built
           | to handle that state. Either the client was written to expect
           | it or it was not.
           | 
           | All you're saying is just expect the states that make sense
           | which is (A) a trivial claim and (B) something you have to do
           | even if you don't make unexpected states impossible.
        
           | iamwil wrote:
           | This is the stance that https://acko.net/blog/i-is-for-
           | intent/ takes--that there needs to be some way of
           | representing a temporarily illegal state.
        
       | mathgladiator wrote:
       | So, I'm in the camp of UI = f(state) because I look at things
       | like stadia/app-streaming as an obviously better way to build
       | software faster. However, there are challenges, so I've got an
       | experiment with a new UI framework called RxHTML that basically
       | treats the browser as a function of a stream JSON document and
       | local view state with a tiny language to manipulate the view
       | state. It works shockingly well, and the goal isn't to be 100% of
       | all use-cases but to make 90% super easy for anyone to do.
        
       | qudat wrote:
       | I think `view = fn(state)` is mostly right but how it is
       | implemented is wrong. If we look at react, everything is nice and
       | declarative until you register event handlers, at which point you
       | enter imperative land to hand manipulate state.
       | 
       | I think what is more accurate is: `view = fn(event-stream)`.
       | Events include but not limited to:
       | 
       | - User events
       | 
       | - Prop change events
       | 
       | - Local state change events
       | 
       | - Global state change events
       | 
       | When we switch the paradigm to be about event streams, all of a
       | sudden there is no bifurcation between prop, local state, global
       | state, and user events -- it is all treated the exact same.
        
         | hombre_fatal wrote:
         | This sounds like `state = reduce(state, event)` and `view =
         | fn(state)` where the view has UI handlers that dispatch events
         | rather than mutating anything.
         | 
         | Elm is probably the simplest example of this paradigm top-to-
         | bottom, but you can wire up something pretty simple in vanilla
         | React with just useReducer and useContext.
        
         | esmevane wrote:
         | I like to think of it as `view, effects = fn(state, events)`,
         | where effects are any subsequent events or instructions that
         | come out of a state change. I think of it very close to how
         | you're outlining it here, though, and when I'm thinking of
         | effects I'm generally also thinking of it as a set of things
         | that can fit into an event stream like you're outlining.
        
         | fleabitdev wrote:
         | The purpose of `view = fn(state)` is to protect you from O(n*m)
         | complexity scaling if you handle each event in isolation.
         | 
         | For any given part of your UI, you'll have n events to handle
         | ("UI started up for the first time", "x changed", "y changed",
         | "checkbox toggled", "undo", "redo", "file loaded"), and m
         | invariants to uphold ("while the checkbox is checked, the user
         | cannot edit y", "while x is less than y, the UI should display
         | a warning", "this label displays the current value of y as a
         | localised string"). If you try to manually maintain each
         | invariant when handling each event, you'll find it works for
         | simple cases, but it falls apart for larger values of n and m.
        
       | parhamn wrote:
       | Somewhat unrelated but, I've been doing a ton of frontend coding
       | past few years (coming from a backend/infra background).
       | 
       | I think browser development is an underrated difficult problem.
       | With a lot of crappy half-assed solutions that don't have
       | solutions at depth that the backend ecosystem has.
       | 
       | Like if you get to the essence of it you're syncing two local
       | event loops -- the JavaScript and browser renderer, omitting the
       | JS async queue and webworkers. Then you have a distributed system
       | on top connecting to your backend. And sometimes you have a
       | distributed system across the same local instance of the app,
       | e.g. multiple tabs of the same app.
       | 
       | All this with neanderthal grade tools. At every layer of this
       | there are half-thought tools with inconsistent data models that
       | try to connect different layers of the problem (component
       | rendering, data fetching, event loops, background jobs, etc)
       | without any great way to do so. Straight glue.
       | 
       | Sure most people call some hook with refresh loop or something
       | and call it day, but the problem still hasn't been solved well
       | for building ultra-rich apps.
        
         | n2d4 wrote:
         | This is the problem that most JavaScript frontend frameworks
         | are trying to solve. Most of them just connect JS and renderer
         | event loops, but some are approaching data fetching and
         | background jobs as well (like React with the experimental `use`
         | hook, or Svelte Query).
         | 
         | They do however come with significant complexity for new users,
         | and if you write React code without understanding the
         | underlying event loops, you'll write code with weird edge cases
         | (eg. overreliance on useEffect). But I do think that they solve
         | the problem pretty well once you got past that initial burden
         | of learning them.
        
           | parhamn wrote:
           | > they solve the problem pretty well once you got past that
           | initial burden of learning them.
           | 
           | Please do share how the canary `use` hook solves: remote data
           | syncing, proper data sharing across the UI, real-time remote
           | syncing, incremental updates, optimistic updates, realtime
           | collaboration, offline only, etc
           | 
           | These are table stakes for good rich apps now. Now your
           | answer is probably going to be to 'use other tools for this'
           | and the lack of cohesion between those tools is what I'm
           | saying is crappy glue. The atoms aren't good.
        
             | aidos wrote:
             | That's... not react's job?
             | 
             | React is all about efficiently taking state and rendering
             | it.
             | 
             | We use mobx for managing state. We use Hasura for syncing.
             | We use react for display. That works well for us and our
             | requirements.
        
               | idbehold wrote:
               | > React is all about efficiently taking state and
               | rendering it.
               | 
               | You sure about that? https://github.com/facebook/react/bl
               | ob/main/packages/react/s...
        
               | aidos wrote:
               | I'm searching for ReactFetch and not finding anything. My
               | 10 years in React tell me that react isn't a library
               | focused on data fetching, maybe I'm missing something and
               | I would happily discuss it if you point me towards some
               | more information.
        
               | dumbo-octopus wrote:
               | packages/react/src/ReactServer.js imports it.
        
               | parhamn wrote:
               | I've never mentioned React, nor really alluded to it
               | (though it is one piece of the complicated problem).
        
               | aidos wrote:
               | I didn't quite understand what you meant by "canary `use`
               | hook solves" but you'll have to excuse me for assuming
               | you were talking about react.
        
               | parhamn wrote:
               | My mention of the use hook (which was first mentioned in
               | a reply to me) was to point out how silly a response it
               | is to offer a random react hook and as the solution to
               | the complex problem I initially discussed. Do read the
               | thread and my initial comment again.
        
               | elwell wrote:
               | Hasura + React is the dream. https://github.com/Vetd-
               | Inc/vetd-app
        
             | 88913527 wrote:
             | react-query's useQuery hook makes the proper data sharing
             | and optimistic updates a breeze.
        
               | idbehold wrote:
               | react-query (or @tanstack/query as its now called) has a
               | few things which make it a little awkward to use beyond
               | very basic fetches:
               | 
               | 1. No concept of normalization. Fetching a list of entity
               | type vs fetching a detail of one of those entities means
               | you end up fetching the same data twice since the cache
               | is only per query, not entity. And good luck trying to
               | mutate its cache yourself to force it to cache by entity.
               | 
               | 2. No good way to get the data out of react-query and
               | into, say, my mobx/redux store.
               | 
               | 3. Its query cache is global, but the `select` cache is
               | per component/subscriber.
        
       | michaelsbradley wrote:
       | For help in modeling the states and taming the complexity:
       | 
       | https://stately.ai/docs/xstate
        
       | scottcorgan wrote:
       | Sounds like Cycle.js
        
       | LAC-Tech wrote:
       | Shower thought I've had recently: would we not be better off
       | modelling a UI as Actions, rather than states? Each action
       | changes this part of the markup, makes these requests to app
       | state / client DB / remote server.
       | 
       | This also maps better to a user centric conception of the app.
        
       | jmount wrote:
       | It is getting to the point that I feel we need a rule of the
       | form: your UI is rejected unless you can tell a new user how to
       | succeed with it over the phone.
       | 
       | To my mind this means at least: fewer modalities, no hidden menus
       | (hamburger), and, many other things.
        
       ___________________________________________________________________
       (page generated 2024-02-16 23:00 UTC)