
Pure UI - brbcoding
http://rauchg.com/2015/pure-ui/
======
escherize
I'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/)

~~~
smrtinsert
It 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.

~~~
sehr
Have you messed with Cycle.js? They just hit 1.0 recently and use rx
extensively, it's an absolute blast to use

~~~
KurtMueller
Are you using this in production? Or for a side project? How and where are you
using it?

Thanks for any info.

~~~
sehr
Just on a couple of rinky dink side projects with babel & webpack! Nothing
major

------
austenallred
I just think that automatically-updating "views" counter is awesome. A little
distracting, but cool to watch it update in real-time.

~~~
sahat
That was my initial reaction as well. Pretty interesting concept. Front page
Hacker News web traffic to your website in real-time.

~~~
bduerst
This is an implementation of socket.io, right?

Seems to hold up pretty well.

------
Aleman360
What'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
My 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
I 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.

------
ilyagr
This 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
Redux does exactly that with react, highly recommended.

[https://github.com/gaearon/redux](https://github.com/gaearon/redux)

~~~
skrebbel
except with multiple little models (stores) instead of one big one.

~~~
baddox
Which is a fairly minuscule implementation detail. The top level state is
essentially a map.

------
brucehauman
This 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-
interacti...](http://rigsomelight.com/2014/06/03/devcards-taking-
interactivity-to-the-next-level.html)

I have been putting a lot of work into devcards lately so forgive me for being
so focused on it.

:)

~~~
brucehauman
You 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.

------
tomaskafka
This.

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
Exactly 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
Yep - 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

------
ridiculous_fish
Help 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
Hi ,

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-
fe...](http://hackflow.com/blog/2015/03/08/boiling-react-down-to-few-lines-in-
jquery/) 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.

------
dhruvio
Thanks 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
Before I launch into an explanation- have you used React js?

~~~
NathanCH
I would like to think this new designer/developer relationship transcends a
single libraries implementation.

~~~
HeyImAlex
They're asking about an implementation detail.

------
TeeWEE
I 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
Not 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?

------
mshenfield
>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.

------
sergiotapia
Reminds 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
What does your meteor + react stack look like? Any reference material I should
look at?

~~~
fightingtheboss
If you're curious about Meteor + React, this is a great place to start:

[http://info.meteor.com/blog/meteor-the-missing-
infrastructur...](http://info.meteor.com/blog/meteor-the-missing-
infrastructure-for-building-great-react-apps)

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

------
CuriousSkeptic
Another 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.

------
amelius
How 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
I'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
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?

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
> 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.

------
zkhalique
Indeed. 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
It'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
Wait, 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
Not 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.

~~~
zkhalique
Yes, if you need to add a behavior to the UI which "can be dropped anywhere",
such as drag-drop, or rich text editing, then as I said, you're going to have
to read from the DOM and otherwise try to adapt "to any reasonable
environment" with varying degrees of success.

So what? This is orthogonal to the problem of rendering the basic UI as a pure
function of the state.

You can store the state of of components inside components, there are many
ways you can do it. React does it. We've implemented it in our framework:
[http://platform.qbix.com/guide/tools](http://platform.qbix.com/guide/tools)

As for how you would remove event listeners when a component is removed, that
needs be coded of course. It would be nice for the developer not to have to
write all that repetitive code. Of course, that also means you'll have to know
when a node is removed from the DOM, and in browsers that don't support
mutation listeners you'd be hard pressed to know that unless the user uses
YOUR standard methods to control the DOM. All around it's a better solution
(if you control the development of the app) to architect the app so that the
model goes through YOUR framework to update the view.

------
AdieuToLogic
For 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)

------
applecore
The 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.

------
WA
Now, 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.

------
smt88
I 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
Calm down - you can simply scroll down to the content and hide the view
counter.

