7 ms·
I find the Elm language quite fun and I think it has potential. However, I'm absolutely not convinced about "the Elm architecture" for anything but the simples
by boubiyeah 11y ago
I find the Elm language quite fun and I think it has potential.
However, I'm absolutely not convinced about "the Elm architecture" for anything but the simplest UIs. Is pure functional reactive programming suitable for ambitious UIs ? I do not think so.
React has its own set of flaws but at least I believe it nailed the state problem: Encourage the minimization of local state but still make it easy to have some when necessary. I like functional programming a lot but I think this is a case where good old object oriented encapsulation provides a more pragmatic solution.
There are all sorts of transient states that a parent's component shouldn't have to care about (Whether I currently have focus, a transient list of changes not yet committed that should be thrown away should I navigate away, is the calendar drop-down opened?, etc, etc) Elm makes it hard to have truly rich and reusable components for that reason as all that transient state must leak to the parent components.
But that's still doable at least, if cumbersome; some other things simply appear impossible, like coding a ReactTransitionGroup equivalent. This React component encapsulates the concept of a changing-over-time list of children and animate in/out the children that changed across two redraws. It needs to know about the previous list of children to diff it with the new. It needs to manipulate the actual Virtual nodes passed to it so that it temporarily leaves the exiting nodes till their animation finished, etc. This thing has tons of state and it needs it to do its job; and it's fine. How would you do this in Elm without leaking the abstraction at every call site ? (I'm looking for a pragmatic, easy-to reuse by everybody solution, not some convoluted sliding Signal of component lists ;-) )
I'm wondering whether performance tweaks should be the focus right now; Elm already had good performances. The issue is adoption, and if it's too convoluted to write (non trivial) reusable components, I don't see how it can succeed. Right now I would never start a complex project with it in fear of getting stuck with a medium-complexity task because the architecture didn't foresee my problem.
Maybe the architecture provide some escape hatches I didn't see, and I would love to be proven wrong.
- spuz 11y agoI have been contemplating the same issue. Unfortunately I haven't yet had enough of a chance to write a large complex application to verify whether or not the Elm Architecture works in practice. In particular the potential for actions and effects of subcomponents to pollute the code of parent components concerns me. If you have some further insight I would love to see a blog post comparing React and Elm that demonstrates where the issues are. Also, the Elm community could potentially make suggestions or take those issues into account for the future.
- jmite 11y agoIt seems to work for NoRedInk and CircuitHub...
- boubiyeah 11y agoIt is also possible to write the most complex app ever using just vanilla Javascript/JQuery too, but it's not viable or fun to maintain. The elm language brings a lot of value compared to the very unsafe javascript; I'm only questioning the validity (or immaturity) of the component architecture.
- rtfeldman 11y agoMy thoughts on this based on experiences using Elm at scale at NoRedInk: https://twitter.com/rtfeldman/status/667419654370033664 https://twitter.com/rtfeldman/status/667419654370033664
- Apanatshka 11y agoI think there simply needs to be more exploration in the area. I only know of one person who tried something truly different than the Elm Architecture who wrote about it on the mailing list. Anyone interested and with time to spend should just try different things, be critical of their attempt's ease of use and ease of abuse and see what works. I think eventually there might be a performance problem with scaling, and yes each components seems to have a bit of boilerplate. But overall the pattern is very reusable and predictable, so if it really becomes the standard (instead of the experiment that it is now!) there could be compiler support for less boilerplate/ better performance. For now I haven't seen enough people with actual experience using this architecture to really buy any complaints. I've seen more unintuitive things come around in Elm that seem weird (perhaps even wrong) at first, but by really trying it out, I've found that more of those things work really well!
- jdudek 11y agoDo you happen to remember what was the idea of that approach alternative to Elm Architecture?
- Apanatshka 11y agoI'm not sure if it was [0] or [1].. [0]: https://groups.google.com/d/topic/elm-discuss/NJCZFIYxshE/discussion https://groups.google.com/d/topic/elm-discuss/NJCZFIYxshE/di... [1]: https://groups.google.com/d/topic/elm-discuss/ZJ6lkfPimW8/discussion https://groups.google.com/d/topic/elm-discuss/ZJ6lkfPimW8/di...
- tlarkworthy 11y agoI have been studying this, Elm explicitly forbids "signals of signals". This basically bans dynamic mutation of the dataflow graph and makes dynamic Gui's very difficult. The solution is not to enable signals of signals, because they are a source of problems. The solution would be to hoist all the functions up one level and operate on a dataflow graph comprised of transformations of signal transforms. This will kill many of the nice properties of Elm (hot code replacement), but the cost of the current system is that its unusable for application context switches and dynamic GUIs. In the literature the high level style of FRP is called AFRP (arrowized FRP). I am currently prototyping AFRP ideas in Typescript and RxJS, although its very early days and basically not usable ATM. https://github.com/tomlarkworthy/animaxe https://github.com/tomlarkworthy/animaxe (a better typed version is in a branch and not compiling ATM)
- rtfeldman 11y agoWhat do you mean by "dynamic GUI"? As opposed to what other kind of GUI?
- tlarkworthy 11y agoA GUI with n buttons and a button to add and remove additional buttons
- brodo 11y agoLike this: http://evancz.github.io/elm-architecture-tutorial/examples/7.html http://evancz.github.io/elm-architecture-tutorial/examples/7... ?
- tlarkworthy 11y agoYes ... but with a more natural implemention. That style won't scale up to real dynamic programs though without significant routing infrastructure outside of Elm's typical constructs.
- 11y ago
- rtfeldman 11y agoLocal component state is the new two-way data binding. Three years ago, two-way data binding was the gold standard for niceness. Then React came out, and there was buzz around unidirectional data flow, and a lot of (understandable!) skepticism came with it. If you listen to people who have spent a lot of time with two-way data binding and unidirectional data flow, what you hear are a lot of unidirectional data flow converts and not a lot of people saying "yeah it wasn't awesome so I went back to two-way data binding." We're watching the same thing play out with local component state versus a single state atom architectures like The Elm Architecture, Redux, etc. As with the React transition, there is understandable skepticism around new things claiming to be nice, but the writing is on the wall. If you listen to people who have spent a lot of time with both systems, what you hear are a lot of single state atom converts and not a lot of people saying "yeah it wasn't awesome so I went back to local component state."
- boubiyeah 11y agoDon't know, I never liked two-way bindings :) <MuseumTech>Adobe Flex added those at some point but it was a complete downgrade from the simpler one way bindings + events.</MuseumTech> A central state atom has pros (debug tooling and the fabled undo for free being the main ones?) and cons. The cons affects me more than the pros. Clojure's Om and React+redux maintain a central atom but still allow for local state in a pinch. I appreciate your comment but I wish it was a bit more constructive; Why do you think a central state atom is so much better ? How can one write ready-to-use smart components with central state ? (e.g ReactTransitionGroup)
- rtfeldman 11y agoHere's a long-form answer to both questions. :) https://www.safaribooksonline.com/blog/2015/10/29/react-local-component-state/ https://www.safaribooksonline.com/blog/2015/10/29/react-loca...
- boubiyeah 11y agoFine article... But all that it tells me from my experience is that it's a good thing to put 80-90% of the app state in a central atom :p A good practice or rule of thumb is just that, it shouldn't always be the only way to do things.
- jwmerrill 11y ago> There are all sorts of transient states that a parent's component shouldn't have to care about. The problem with this way of thinking is that there are invariably things that you initially believe will be of no concern to the parent that later become concerns of the parent. It's tempting at that point to graft on some event system so the parent can watch the things that it now cares about, and then maybe you add some hooks to allow the parent to preempt or change certain behaviors. This evolution requires careful thinking every time, and it's easy to make mistakes. The great thing about the elm architecture is that from the very beginning, it gives the parent all the hooks it will ever need to observe and modify the behavior of children. In the beginning, when the parent doesn't care, it just passes the actions up and passes the model back down without having to look at them. That might feel a little bit boilerplate-y at the beginning when you don't need it, but it's the same everywhere, so it isn't difficult at all. And once you've done this, evolution of the components requires much less thinking about architecture, and leaves much less room for mistakes.
- boubiyeah 11y agoI think that's a fair point. To be honest, I'm more concerned about the real limitations of the paradigm (the nice-to-have features I will have to pass because the architecture is a bit too closed)
- skybrian 11y agoIf you make all events public, you end up sending all scroll events and mouse move events to the app's top-level signal just because some component needs them. The larger your app is, the more likely it is that some component somewhere will need an event sooner or later. Traditional UI frameworks try to avoid sending events unnecessarily for performance reasons; they're designed so that each component can declare which events it's listening to and can start and stop listening as needed. Perhaps Elm can make this work, so that unwanted events get filtered out so quickly that it's not a concern. Also, these days everything gets animated anyway based on things like scroll events, so apps are perhaps a bit more like video games that run at 60 frames/second regardless of what's going on, at least while they're in the foreground. And the browsers themselves perform a lot better. But it shouldn't be hard to see why people who have experience building UI frameworks might be concerned about unnecessary event traffic, particularly on mobile where battery life is an issue.
- deleted 11y ago[deleted]
- randomNerd 11y agoRegarding global state and React, this looks relevant: https://www.youtube.com/watch?v=Uu4Yz2HmCgE&t=11m37s https://www.youtube.com/watch?v=Uu4Yz2HmCgE&t=11m37s
- brodo 11y agoYou can have component local state in the Elm architecture. If you work through the Elm architecture tutorial (https://github.com/evancz/elm-architecture-tutorial/ https://github.com/evancz/elm-architecture-tutorial/), section 6 describes how to do it. You can also have both local and global state if you want. Just follow the tutorial and in your "model" type add a record called "global". Than let each component take and return both the local and the global model. I personally use global actions instead of a global model. In this approach each update function for a component returns a new model and a global action. Each component has a "updateGlobal" function which is than called with all the actions returned by the update functions of all the components. This way, components can talk to each other, but may keep completely different models. Here is the relevant code in my main elm file: https://gist.github.com/brodo/6495e486648d235e10a5 https://gist.github.com/brodo/6495e486648d235e10a5 This allows you to react differently to actions in each component if you want. You can check out the whole project here: https://github.com/brodo/MushroomCup/tree/master/elm https://github.com/brodo/MushroomCup/tree/master/elm
- ablesearcher 11y agoYour solution redefines the word "local" to mean "global." Yes, you can store a component's intrinsically local state as field in your global model and then use a specialized update function that is reached by a switch from your global update function. The question we are addressing is: Is that a good idea?
- brodo 11y agoYou realize that each component can not see the other components local state in both solutions i suggested?
- chenglou 11y agoFwiw React-motion solves TransitionGroup in a purely functional manner. https://github.com/chenglou/react-motion https://github.com/chenglou/react-motion