5 ms·
Pure UI
- Aleman360 11y agoWhat's old is new. Silverlight had a big focus on declarative UI that continues to today with XAML: https://msdn.microsoft.com/en-us/expression/cc941385.aspx https://msdn.microsoft.com/en-us/expression/cc941385.aspx
- aggronn 11y agoMy first job was as a Silverlight developer. I used to complain all the time about XAML, and as a huge React fanboy, its been lurking in the back of my mind. Why would I like JSX but not XAML? Especially since early Silverlight projects used 'code-behind', which is essentially just a c# file that is paired with each component. How is this different than React? At all? I think the biggest difference is that XAML was really terrible to work with in part because of proprietary components and the massive tooling around it. I remember I'd have to use Blend whenever I wanted to change how something looked. And then there wasn't a great application structure that moved along with it. I pushed really hard for us to switch from code-behind to MVVM for our application architecture. It worked great, and made everything much easier, though it was really abstract and styling was difficult still. But that was my first job--maybe if I went back it would seem trivial. I don't know if this applies to XAML, but once you start thinking of React in a component architecture model (knowing JS helps too!), the declarative style makes so much sense.
- Jacob4u2 11y agoI also came from a XAML background to React and had the same feeling. This is a long shot, since most people have a love/hate relationship with the VisualStateManager, but I have been trying to build a declarative visual state thing over at https://github.com/jgable/react-vsm https://github.com/jgable/react-vsm. It's not done, only messed around over a couple weekends, but the gist is there.
- geetee 11y agoSimilar story here. I don't miss the mental context switching. I also always hated how many template languages/frameworks stuff DSLs into strings.
- lstamour 11y agoIt's also the lack of support of CSS in XAML. JSX didn't re-invent HTML with proprietary tag names and strange layout attributes... though this whole CSS in JS thing I can start to get behind if the tooling improves.
- hokkos 11y agoSame here, style in XAML is very verbose, and conditional rendering is not created from the code with ternary operator and conditions, but with templates in XAML that are very verbose and it is hard to remember how to use them. Also the use of 2 way databinding cause a lot of problems.
- skrebbel 11y agoSilverlight's UI system was MVVM, based on AngularJS-like two-way data binding (actually, KnockoutJS is inspired by it). Sure, the UI is pretty much pure, but it moves all the state who-did-what-in-what-order mess to the View Model, so the problem is just moved, not fixed.
- 21echoes 11y agoIt's also how Backbone has always worked.. Canonical Backbone has you `this.model.bind('change', this.render)` where `this.render` is a pure function (typically just passing `this.model` to a Handlebars template).
- austenallred 11y agoI just think that automatically-updating "views" counter is awesome. A little distracting, but cool to watch it update in real-time.
- sahat 11y agoThat was my initial reaction as well. Pretty interesting concept. Front page Hacker News web traffic to your website in real-time.
- stilldavid 11y agoI totally dig it too, but I wish it counted without highlighting yellow. Neat feature, but a bit distracting.
- bduerst 11y agoThis is an implementation of socket.io, right? Seems to hold up pretty well.
- deleted 11y ago[deleted]
- moron4hire 11y agoInteresting, as I had the complete opposite reaction. I found it distracting and had to scroll it off the screen to be able to focus on the content of the article. Putting blinking things in the periphery of vision is a very well known pattern when you explicitly want to draw people's attention. If this were email notifications, blink away. But it's actively drawing the reader away from the core purpose of the site--reading the damn article--without adding anything of value. "Oh, other people are coming here? Social validation! I'm reading the right things! Now what was I reading?" Complete malarky.
- ablation 11y agoFortunately though it's at the top of the article, so you've scrolled past it almost immediately, right?
- escherize 11y agoI've noticed the f(data) = view paradigm dominate the clojurescript landscape ever since om and reagent[1]. There's also a library that literally uses function calls and parameters for every piece of UI called re-frame[2] (which also has a badass readme). Using pure functions to compose a UI along with keeping all the data in one place have been a huge win for our project for a few reasons. 1. All it takes to debug what a handler is doing is what effect it has on the DB. Our handler functions are also mostly pure functions which take the current-db as a parameter. 2. We can serialize the state to local storage (or a string) and reload it from local storage (or a string). 3. Using the repl, we can investigate the state of the application while it's running. [1] http://reagent-project.github.io http://reagent-project.github.io [2] https://github.com/Day8/re-frame/ https://github.com/Day8/re-frame/
- ds_scalar 11y agoYes! Re-Frame is fantastic, and a core part of a major project I am working on. In this spirit I am also really looking forward to Om Next.
- KurtMueller 11y agoI agree that re-frame is awesome. I also love reagent and figwheel. Are you planning to incorporate datascript or datomic at all in your projects?
- smrtinsert 11y agoIt is virtually impossible to go back to a non unidirectional ui without feeling gross and disgusted. Working on a major angular project after doing some cljs with react feels like a decades step back - back to a horrible jsf like two way data binding disaster. Where is my state? Where is my api? Why did x put y here? If it doesn't take hold this generation, it will definitely cycle back decades from now as the dominant way to structure ui code. Between unidirectional flows and observables (or maybe some other async primitive) UI is getting very interesting these days. Personally I prefer rx to core.async. Core async just looks too awkward and low-level for me. RX I got immediately - a promise for a stream. Great stuff.
- deleted 11y ago[deleted]
- tomaskafka 11y agoThis. 1. Create pure UI component 2. Describe allowed state space as DSL/type - https://news.ycombinator.com/item?id=8963000 https://news.ycombinator.com/item?id=8963000 3. Plug in fuzzer 4. Watch till you catch an undesigned state 5. Fix & repeat
- brucehauman 11y agoExactly but keep pages of these ui components and review them before a push to production. In fact, work on the component in this setting to get maximum feedback.
- tomaskafka 11y agoYep - but the state space is usually huge, so it helps to: - expand it in physical space (as in article) to see main variants - fuzz it (= expand/project randomly onto time axis) to catch errors visually
- sergiotapia 11y agoReminds me heavily of React. Components that render 1 single thing based on the current state of the component. Building out my UI with Meteor and React was so cool, I found myself having fun again.
- ClayM 11y agoWhat does your meteor + react stack look like? Any reference material I should look at?
- fightingtheboss 11y agoIf you're curious about Meteor + React, this is a great place to start: http://info.meteor.com/blog/meteor-the-missing-infrastructure-for-building-great-react-apps http://info.meteor.com/blog/meteor-the-missing-infrastructur... The integration isn't totally settled yet, but a lot of work is being put into it at the moment and Meteor is a perfect companion to React, much simpler than implementing your own Flux or Relay backend. For further info, you can also look here: http://react-in-meteor.readthedocs.org/en/latest/ http://react-in-meteor.readthedocs.org/en/latest/
- Offler 11y agoIt reminds you of React because he's talking about React :)
- applecore 11y agoThe convergence of the designer and programmer roles feels, if you'll pardon the pun, like React's one-way data flow: moving from design to programming. Of course, the ecosystem will build better tooling to support less technical folks, but for now it's still heavily engineering-focused.
- deleted 11y ago[deleted]
- dhruvio 11y agoThanks for the essay, it was a great read. Maybe my understanding is wrong, but I am slightly perplexed by one idea. I really like the link you have created between the designer's and developer's workflow, and I think your essay touches on an ideal. But, from an applied perspective, this may be difficult to attain when creating components that need to visually transition between state within the original element. Using your video player example, if the video is loading (state 1), and once loaded, it starts playing (state 2), wouldn't a pure functional approach imply the entire <video> DOM element is replaced by a new one in the change from state 1 to state 2? What if I only wanted to animate the loading bar away and fade out the thumbnail when leaving the loading state, while maintaining the original HTML element? I'm curious to know if you've thought about this, and have any insight, because it's something I hope to understand. Thanks.
- woah 11y agoBefore I launch into an explanation- have you used React js?
- NathanCH 11y agoI would like to think this new designer/developer relationship transcends a single libraries implementation.
- HeyImAlex 11y agoThey're asking about an implementation detail.
- dhruvio 11y agoHey, sorry for the late reply. I have touched on React. But, I am familiar with Ember, Backbone, Vue and Riot. Nonetheless, could you please explain further?
- pests 11y agoReact (and others, I'd assume) does this by keeping a virtual DOM and then only applying the DOM manipulation necessary to get existing state to match desired state.
- mshenfield 11y ago>In general, comparing frameworks in terms of features seems inferior to examining the model it imposes on the programmer. The latter will inform you about how well the code will fare over time as the product matures and the team grows, but the former won’t. I feel like this is a much more semantic interpretation of frameworks than trying to compare the likes of Angular, React, or JsBlocks on speed, data-binding, and whether they support x,y,z use cases. Kudos rauchg.
- brucehauman 11y agoThis ability to concretely display a component in all of its different states is one of main reasons I created devcards (ClojureScript, Figwheel). One can use it to create storyboards live as you are programming. http://rigsomelight.com/2014/06/03/devcards-taking-interactivity-to-the-next-level.html http://rigsomelight.com/2014/06/03/devcards-taking-interacti... I have been putting a lot of work into devcards lately so forgive me for being so focused on it. :)
- brucehauman 11y agoYou don't need a library to do this stuff though. Just a functional approach and a willingness to work on a storyboard application, which iterates over all the states of your components, instead of just working on the main application.
- zkhalique 11y agoIndeed. You can roll your own without React. Simply indicate when something changed in your model, and update the DOM on the next frame using a PURE state -> DOM mapping function. What do you y'all think of something like this? http://platform.qbix.com/guide/tools#dom http://platform.qbix.com/guide/tools#dom
- grayrest 11y agoIt's Backbone. A pure state -> DOM function is also called a template. It works when the app is simple. The problem is that you do NOT want a pure state -> DOM function. It blows away state of things like mounted subcomponents and input fields. Look forward to lots of ad-hoc DOM coordination as your app grows. Giving up efficiency in the slow part (DOM updates) in exchange for efficiency in the fast part (determining what changed) is backwards.
- zkhalique 11y agoWait, what? Why would you ever want to read from the DOM in a well-architected app? Unless you are building a component that can be "dropped anywhere", you control what the DOM shows. If you need to read/write to the DOM, you can cause layout thrashing and seriously slow down your UI. You might have to resort to using a library like FastDOM to fix it. I think you are overstating the "dangers" of having the UI be a pure function of the state.
- grayrest 11y agoNot at all. I've written/cleaned-up a few dozen Backbone apps. They work great when they're small and are generally a mess once they scale. An example: how do you use a datepicker component in your pure state->DOM system and guarantee setup/cleanup of DOM event listeners? As for when you'd want to read from the DOM in a well architected app, the easy example is drag and drop. Unless your drop targets have fixed sizes or your needs are simple enough to purely get away with mouseenter/mouseleave events then you need to query the DOM for node sizes. Other situations I've run into are text breaking and rich text editing.
- ilyagr 11y agoThis is exactly the approach Elm takes. The recommended way to structure the application is so that the view is a pure function of the Model (application state). Moreover, the change to application state is also pure: there is a pure function that takes an event and an old model, and then returns the new model. http://elm-lang.org/guide/architecture http://elm-lang.org/guide/architecture
- jlu 11y agoRedux does exactly that with react, highly recommended. https://github.com/gaearon/redux https://github.com/gaearon/redux
- atrilumen 11y agoIt's taking me a lot longer than expected to get productive in Elm (because of personal issues (burnout/depression)), but I'm convinced that the speed limit is going to be very high at that altitude. I think that working at such a high level will enable an unparalleled dynamic between designer and developer. My dream job right now is to be able to sit down with a designer on one side, and a (client / domain expert / stakeholder) on the other, and iterate on an interface in a very tight feedback loop. I feel like Elm has really inspired me in a positive way, and is helping me to recover. I'm already feeling pretty endeared to it's community, and want to give back as much as possible, as soon as possible. If you haven't checked it out yet, I highly recommend it.
- amelius 11y agoHow would one code, e.g., a rich text editor using such an approach? And would it be able to handle texts, of say, hundreds of pages?
- grayrest 11y agoI've done a basic RTE in React for a client. I've done three now and RTEs are always annoying but the difficulty in this case is largely in how you model it. I chose to create a JS object per block element (usually a paragraph) consisting of the text as a string and a set of text ranges (start/end/type). Input was via hidden text field that's updated as you change blocks and the mapping from x+y screen coordinates (click, arrow up/down across block boundaries) to text field offset is doable by writing a shim for caretPositionFromPoint. I started with just using contentEditable but you have even more exciting cross browser issues, the output is both inconsistent between browsers and terrible, and you can't do controlled input because updating the editable content DOM at all breaks undo. With the virtual DOM model, updates are roughly O(n) where n is the size of the virtual DOM. The way to handle very large amounts of input is to window the input data and only vdom render/diff the subset of the data that's currently visible.
- mikegioia 11y agoHow did you capture and render text input, and how did you handle new lines when the text wrapped? How do you handle paragraphs, especially when a user would delete text? I only ask because I determined it impossible to use React for a RTE over the last year and instead opted to use Redactor/contenteditable. I just could not solve those problems easily/quickly enough to make it worth it :( I'd be extremely curious to see any at all type of implementation for a RTE in React if you have one you could share.
- grayrest 11y ago> How did you capture and render text input, and how did you handle new lines when the text wrapped? How do you handle paragraphs, especially when a user would delete text? For rendering, I had a component that rendered the block element by splitting the text string at the indicies specified by the text ranges, inserting the appropriate tags, and dangerouslySetInnerHTMLing the text. I'd probably just manually generate vDOM nodes if I were to revisit it. I didn't do line breaking, moving up/down was done using the caretPositionFromPoint code: create range, get it's bounding box to get initial x/y, getClientRects to get the position for the next line, caretPositionFromPoint, get block text index. In this case (I did mention it was basic) I wound up not having to do cross-block operations because the UI never had more than one. I had a plan but not having to do it makes me happy. In conclusion, you're probably better off just using an existing RTE.
- CuriousSkeptic 11y agoAnother take on the idea of finding the complete specification is Parnas Tables. https://cs.uwaterloo.ca/~jmatlee/talks/parnas01.pdf https://cs.uwaterloo.ca/~jmatlee/talks/parnas01.pdf I'm thinking it could be interesting to combine some agile technique like ATDD and user story mapping with such a disciplined formalism.
- AdieuToLogic 11y agoFor those cordial with CoffeeScript, there's Hamlet[1] (which is based on/inspired by HAML[2]). It's a pretty nice declarative-esque UI library. From their home page, here's a sample: %label Search: %input(value=@search type="text") %label Sort by: %select(value=@sortBy @options) %ul -each @sorted, -> %li.phone(@class) %img(@src) .name= @name .description= @snippet 1 - http://hamlet.coffee http://hamlet.coffee 2 - http://haml.info http://haml.info
- smt88 11y agoI wasn't able to read any of this because of the stupid fucking flashing view counter at the top of the page. View counters have been dead for a long time and need to stay that way. No one cares how many views you have and certainly no one wants to have a flashing box at the top of the page they're trying to read.
- KurtMueller 11y agoCalm down - you can simply scroll down to the content and hide the view counter.
- ridiculous_fish 11y agoHelp me understand some of this stuff: > the definition of an application’s UI as a pure function of application state I presume "application state" means the stuff that the app cares about, and not the stuff that it doesn't. But the app's actual, rendered UI incorporates state from multiple sources. For example, if you have a text field, it has "application state" like its positioning, "framework state" like where the text selection(s) are, "user state" like what size the user dragged it to, etc. And your "pure function of application state" necessarily discards this non-application state. So then how does this state ever get preserved? The answer must lie in the "diffing algorithm:" the thing that determines what has changed, and attempts to reuse as much of the old UI as possible. A good algorithm will reuse an element and preserve its state. A naive algorithm will drop state and result in bad UI. So in this model, aren't you taking a huge and hidden dependency on this diffing algorithm? What's the right way to ensure continuity of non-application state across updates?
- thewarrior 11y agoHi , Yeah I was wondering about some of this stuff as well. I don't understand how you could hack UIKit to work this way. Do you think this is really all that superior to using KVO and bindings (We don't have bindings on iOS but still .. ) ? Also animations aren't easy to do this way. I think we can follow some of the guidelines they have here : http://hackflow.com/blog/2015/03/08/boiling-react-down-to-few-lines-in-jquery/ http://hackflow.com/blog/2015/03/08/boiling-react-down-to-fe... And reap most of the advantages. As for optimizations , He mentions immutability , we already have that using Swift structs. Then there's the differ The diffing algorithm shouldn't be a one size fits all super algorithm but a collection of dumb components you can put together to get the perfect diffing behaviour for your particular use case. The differ should also animate the state transitions appropriately where necessary. Then we have this : http://componentkit.org/ http://componentkit.org/ Though I haven't had the time to look into it. It has to be good since FB claims they rewrote their whole app in it.
- WA 11y agoNow, it would be interesting to see how function pay() should be written with the new approach and how it evolves when the new states ("network went away error", "must be logged in", "certain role", "pre-existing data") are discovered.
- TeeWEE 11y agoI like the idea of having pure functions f(state)=view, however, wouldnt this be very slow for very big ui applications? Also the only reason todo this on web is to use some sort of double-buffering and prevent redraws before everything is updated. On mobile native you have control over these things. But thinking about it, doing purely functional UI for native apps would never work, right? You need todo a dif each and every time the ui updates. And this happens a lot for example for sliders, or animations. Is the approach inherently flawed for fast UI applications?
- zenware 11y agoNot that I'm terribly familiar with the functional approach, although after reading some of this I will definitely be examining it more thoroughly and exploring its use in personal projects, but would memoization appease you?