[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)