CHARLES LOWELL: All right everybody.
Thank you so much for coming. I'm really,
I'm really honored. This morning we're gonna
be talking about client-side UI. These are,
this, your client that's, that's running inside
the browser. Not in the server. And some of you
might already be doing this a lot. Some of you
maybe a little. But wherever you fall along that
spectrum, you're going to be doing more of it,
chances are, as time, as time goes on, and not
less of it. And so I want, my goal here is to
share with you some of the ways that I've come
to think about clients, UIs, that can help you
build user interfaces that reactive, that are
educational and ultimately satisfying to your users.
What I want to share with you is the power of m.
My name is Charles. I'm cowboyd on GitHub and
Twitter, and I work at the Front Side, where
we've been doing UI for almost ten years, exclusively.
And when I talk about m, of course I'm
talking about m as in MVC. We're all familiar,
we've probably heard about the MVC pattern, model-view-controller. It's
what underpins all UIs. At least ostensibly.
But it can actually be pretty notoriously difficult to
pin down what, exactly, is MVC. It's a difficult
question, and if you ask two people, you're likely
to get a very different answer. And my, what
I'm. I don't want to, to, to go in
too much to try and define, give you one
particular version of MVC. I think there are many.
And, in fact, you find people asking the question,
is Rails MVC?
And some people are really, really stodgy about this.
They're, Rails MVC - pshaw. I'm more relaxed about
it. I say yes. Rails is MVC. It's server-side
MVC. It's a flavor of, of MVC. But what
I've come to realize is that MVC is, it's
kind of like Kung-Fu. There's lots of different schools.
There's lots of different ways to, to practition. Each
with its own strengths, each with its own weaknesses,
and, you know, which one you choose, you need
to, is, is, needs to be appropriate for the
context.
But today we're gonna be talking about client-side UI,
which is different than, different than the, than the
server-side MVC, and one of the things that, that
really sets it apart is, when you're working on
the client, you constantly have to manage state. The
client's always on. It's not like a Rails application
where you're basically setting up the world and then
throwing it away with every request. On the client,
you're always on. And so you have values that
relate to each other, and when one of those
values changes, you have to update the, the, the
other values to reflect that.
So, when we're thinking about MVC, I've come to,
to realize that really what you want to do
is you want to focus on the model. When
you first come to the, to the acronym, MVC,
model-view-controller, you tend to, to give equal billing to
the letters, because they're, they're, there's, no one is
set apart from, in, in the acronym. But I've
come to find that while the view and the
controller are important, they orbit the model.
So, I actually draw inspiration from, from this guy.
This is Plato. He's one of the ancient software
developers. You can actually tell. He's got a ChromeBook
Pixel there in his, in his hand.
And I think that he made an analogy, long
time ago, that I think really, cleanly captures this
concept. He had this allegory of a cave, and
the idea is that living in this world is,
is like being inside a cave, and back up
at the entrance of the cave, where you can't
see, there's this fire burning. And shapes pass in
front of the fire, and they cast shadows on
the wall. And we, inside the world, the only
thing that we can actually see is the shadows.
The shapes and the fire are hidden from us.
But if we look at the, the, the shadows,
we can extrapolate those shapes, and the shapes that
we see on the wall take their form purely
as a function of the shape in front of
the fire. They are as they are and are
no other way because, because of those true forms
and then the way that they interact.
And so this is all, this is all very,
very abstract. We've covered, you know, who I am.
We've covered the, the, an ancient philosopher, which I
guess is obligatory. But, I really want to give
a demonstration of this principle in action so that
you can see a little bit more concretely what
it is that I'm talking about. And so, to
do this, we're going to explore the concept of
a color. It's a, a, a very simple concept.
It's something that most of us can perceive very
easily. We, we, we know what it is, but
can be surprisingly difficult to, to pin down.
There's many, many, many different ways to represent it.
But we're gonna have, we're gonna have a color,
and this is gonna serve as the basic value
in our system. You can think of it as
like, an integer value or a string value, or,
or something like that, and we're going to see
how this when, when we have this color, what
kind of, what kind of reflections we can make
on that wall.
So, the first example is we're just going to,
we're just going to project this color onto a
single div. We're going to list this color value
on the right. We're going to be able to
set a color, remove a color, set a color,
and as we do that, the, the, the swatch,
the color swatch will, will update itself. And I
actually have a little demo here. And I've got
it hard-coded, just statically, so that when I check
this checkbox, the, the swatch will turn green. And
I can uncheck it and check it.
It's not, not too much. It's simple but it's
surprisingly satisfying. When I was putting this talk together
I actually would just sit there and click on,
off. It's great.
And you can do the same thing. We can
actually connect one color to two swatches. So we've
got, there's no reason we can't, can't duplicate that.
We'll take two of these swatches and, and bind
them to the, the, the same color. The, there's,
there's, so there's only one color in the system,
but the effect is the same.
Again, I could do that forever.
And this is what data binding is. You might
hear about data binding, and most people kind of
equate data binding with templates, because that's usually where
we come to it first, right. We change this
one value and the string value updates, right. But
templates are really just a special case of data
binding. In the abstract, it's really just about taking
two values and putting, putting them together so that
they occupy the same space in your application. There
really is no difference, conceptually, between them.
Some, this is, this is different than observation, which
is kind of another pillar on which client-side UIs
are built, where you can observe for value changes
in a model, and when that value changes you
get a callback. But. With data binding, you really
need to think of it taking two separate properties
and really just making them overlap and becoming the,
the absolute, the, the same thing.
Now, it is built on observation. So, when we
have a model and it's got some property. I've
got one named a and one named b. We
can use observers to, to, to implement the data
binding, so if a value appears at a, we
observe that and we immediately copy it onto b.
And if a value appears on b, then we
immediately copy it over into a. But I'm showing
this, the mechanics of it, so that you can
forget about them. Because you, when, when we're talking
about sound traveling, you don't really want to think
about the particles knocking together. What you really want
to think about is the data flowing through, just
like it's a pipe.
And this is good, because it, it, it decouples
that data flow from your computation, so you can
compose your different models together just by making them
overlap at well-known points. So to, to, to show
this in action, I've got a model here called
the desaturator. And on the left, it takes a
color and on the bottom, there's a, a, a
value, a real number between zero and one, and
then the color on the right is a desaturated
version of the color on the left.
So and, and that relationship is, it's, it's a,
it's, it's, it's pure. The, the value of that
color on the right, no matter what the color
on the left, is always going to be a
desaturated version of that color. So if we see
this, we can now plug it into our swatch
assembly, just using data binding. So, let's see that
in action.
Here's our desaturater. I've got the green turned on.
And as we up the desaturation, you can see
that it literally just sucks the color right out
until, if you're fully desaturated, you're at gray. If
you ever, never heard the term of desaturation before,
that's, that's, that's what it is.
And, of course, if I change it to a
different color, in this case black, which is the
absence of color, then they're, they're both black, because
a desaturated nothing is still nothing. But if I
shine the color through again, then the, the desaturation
remains.
And this is all well and good when it
comes to binding colors to colors. But when you've
got two separate data types, because remember, you know,
bindings can only work on the same data type.
When you've got two separate data types, what are
you gonna do? Well, you just need another model.
And in this case, what I've implemented here is
what I call a color syntax. And it's a
model that's got a color on one end and
a string on the other. And I'm, you know,
there's a little bit of hand-waving here, because this
model is a little bit complex on the inside,
but from a composability standpoint, it's very simple. It
just relates a color and a string.
And it goes both ways. So that if a
color appears on the top, that implies a string
value on the bottom. And if a new string
value appears on the bottom, that implies a different
color value on the top. And so I can
plug this in to our assembly, and I'm gonna
go ahead and plug it in twice, to kind
of fast forward and show you a little bit
more the power of data binding here.
So we've got two text inputs which produce strings.
But they're bound to our color syntaxes, but both
color syntaxes are bound to the same color, which
is that swatch on the right.
So we can see this in, in action here.
So I've got my two, two text fields, and
I can change the color of one, where probably
most, we're used to dealing with hex values, and
you can see that the, the colors update. Both
in the swatch, the, the desaturated value of the
swatch. And also in the other text field. So
I can set it to cyan and then I
get a desaturated cyan. Cause all I'm really doing
is changing that one color value.
Incidentally, these, these text fields, there's nothing special about
the format, because the way I implemented it is
a, a color syntax, I actually can take this
here and, and copy it up here, and it'll
still update the color because the, the syntax is
format agnostic. So it doesn't really matter. And I
can also use a RGB constructor here to make
this red again.
So. And that's good. You know, we can, we
can play around with the colors. We can enter
in RGB values here, one at a time, and
see the kind of the affect they have on
the mixed color. But that doesn't give us real
insight about the, the, the individual components. So what
we can do is we can actually add another
model to decompose this color into its RBG value.
So we've got, again, we're relating over here on
the left a color value, and over on the
right, three different, three different coordinates, red, green, and
blue. And we can see how those things relate
to each other just by binding it into, binding
it into our application.
Now I've gotten rid of the, the desaturator and
put this RGB selector in here. So let's see
what this ends up looking like. You can see
I've got these sliders bound to those RGB values,
and I can do things like bring in red
so that I've got, now, a pure yellow, and
I can fade out the green until I've got
my pure red. And so I can see how
each individual color affects the, the final value.
Which is, you know, this is, this is, this
is pretty neat. We're starting to, to get something
of a, of a more non-trivial application. But we
still, we're still not seeing how the color is
actually constructed by the computer. And to do that,
we can use, we can, we can visualize not
just the, the final output in that swatch, but
we can actually visualize each value for red, green,
and blue, and how that relates to the original
color.
So, what I did was I made an RGB
visualization component, and bound it to the color, so
that when the color updated, we visualize not the
whole color, like the swatch, but the actual different
red, green, and blue values. And that's what this
looks like. You can see we've got, right here
a pure green. But we can bring red in,
slowly. And you can see how you get that,
that yellow there, and then if we bring in
blue, how it goes to white. But what we're
seeing, now, is we're actually seeing how the color
is added by the, the, the actual hardware. RGC
is an additive model. We're taking a red value,
a green value, and a blue value and we're
adding them together so that the part where all
the circles overlap, that's all three colors added together.
And then where only two of the circles overlap,
those are where the other two circles are, are
together. So you can see that if I've got
a pure yellow or I've got a pure cyan.
Oops. If I've got a pure cyan, you know,
I have no, I have no red component, and
so the, the, the swatch or the part in
the middle is the exact same as the overlap
for green and blue. And so you can kind
of play around with this and see how the
individual colors mix and not be, not be distracted
by the, the, the overall sum.
And RGB is a great. RGB is great, if
you happen to be a pixel. It can be
difficult for us to understand RGB. The reason that
we use RGB coordinates is because it's very easy
for a monitor to take three values, add them
together, and like, that's the frequency of light that
I need to emit. But that's not how we,
as humans, actually perceive it. And so there are,
there are other coordinate systems that are more in
tune with the way that we perceive color, which
unfortunately we don't actually use. You know, RGB is
kind of like the assembly language of, of color.
It's what the machine understand.
So, probably the most, the other most popular format,
the most popular coordinate system for describing color is
called HSL. And it, it stands for hue, saturation,
and lightness. To read briefly what these, these mean
or what they're defined as.
So, hue is the degree to which a stimulus
can be described as similar to or different from
stimuli that are described as red, green, blue, and
yellow. Saturation. The colorfulness of a color relative to
its own brightness. Lightness. The subjective brightness, perception of
a color for humans along a lightness/darkness axis.
Now, if you're like me, that really, even though
it's aimed at me, it's completely and totally incomprehensible.
The, the, the vocabulary definitely is about humans and
human perception, but it's still a black box. It's
still completely opaque. But, what we can do is
we can add another model, and we can decompose
that to unpack those individual coordinates and see how
they effect our, the, effect the different color values.
So let's go ahead and plug that in. I've
got an HSL selector, just like I had the
RGB selector, and we can see the, the, the
hue, saturation, and lightness coordinates over there on the
left. So, right now we have a pure green.
I can take it down to a pure red.
We can move the h. We're gonna keep s
and l, and you can see as I go
to green, the red fades out til I've got
a pure green, and then the blue fades in
till we've got a pure cyan. Then the green
fades out so that we've got a pure blue,
and then red fades back in to purple, and
then blue fades back out to red.
I particularly, I love as I, as you watch
the hue, seeing where the RGB sliders are going.
So you can see that the hue is going
around that color circle. It's going around the color
circle. And then as you adjust the saturation, you
can see, OK. The red's coming down and the
green and the blue are coming up in unison,
and when I fully have zero saturation, then we're
at a gray. And if I bring the saturation
up, the, the green and blue go down in
unison, and we're back to that pure color, that
pure hue.
So I think that this gives a, a much
better view on, on these different coordinates. Same thing
with lightness. You can see as we go from
point five to one, it's almost like we're just
mixing in white unless you've got nothing but white,
and as we decrease the lightness, you can see
those, the green and the blue come down together.
And then as we go from point five lightness
to zero, we're just fading that hue to black.
And so I think, even though the terminology that
you might read on Wikipedia about what HSL is
is very opaque, it actually becomes pretty clear about
what it is when you, when you can play
with the individual coordinates and see how it relates
to both the color at large, the, the, and,
and also the, the additive color model that the
computer's using.
And we can also, and we can, we can
visualize the HSL by making another visualizer, just like
we did with RGB. And we can bind it
into our color model. I think we've got what,
one, two, three, four, five different things. Six different
things. Let's see. One, two, three, four, five, six,
seven different things bound to this color.
So, we've got quite a robot we're building here.
And so this is, this is actually HSL space,
and you might already be familiar with the color
selectors that use HSL. You can see that as
I adjust the hue here, I'm going around that
color wheel. And those, you can see where the
color wheel fits on those, along the points. And
the color that's selected is, is right down there.
This, so what we're seeing here is the hue
goes around in a circle. It's an actually a
radial component. So, which is why it's from, you
know, zero to three-sixty. And then the saturation, or
the intensity of the hue, is the radius of
that circle. And then if we look at the
lightness here, you can see that the lightness, we
fade up to white at the top and then
fade down to black. There, so as we adjust
the, the lightness, we can go, we go up
to white at the top and down to black
at the bottom.
So, that's, that's pretty neat. I think, I think
there's a lot of power in that. By taking,
you know, just, just, just by binding to a
single value. But values, values are actually not just
on the client. You can actually treat a server,
for example, as a simple model. And so here,
I'm, we're going to have a server component. And
a server's a black box, but from the perspective
of the rest of the client, it behaves just
like any other model.
If a color appears at that point, it's sent
into the black box. It can be sent to
the server, serialized, whatever. And by the same token,
something can happen on the server and it can
make a color value appear right there.
So, we can use this concept to develop color
book, which is the first social network for color
values, which I'm about to show you. And we
can do this just by plugging in our server
into our robot. I was actually kind of running
out of room, so same basic concept. It's a
little bit of a snakey cable there.
And so now we'll do an actual live demo
in here. So I've got, I wrote a little
Rails app that uses web sockets to implement those
servers. Or implement that, the, the, the endpoints on
the servers. So, we can now open up that
example that you saw in two separate tabs.
And then we can see them acting in unison
here. And so what's actually happening here is I
got two different client-side applications, but they're all bound
together.
So, one of the things I hope to demonstrate
is that there is actual power in simplicity, with
keeping your models simple and keeping them composable. I
think that, you know, this is probably, in terms
of API, this was probably the, the most complex
model that we had in the system. It's got,
you know, four points that you can, you can
bind to.
But because, you know, because we understand the relationship
between them, we can use each one of these
individual models, which are very, very simple, to link
together in simple ways to make a very complex
and, and interesting application. And so I shied away
from, from actually defining a model, because like I
said, I don't want to get into nomenclature wars.
But I think it's fair to define a model
as just a group of values with well understood
relationships. Values with well understood relationships.
And if we understand those relationships than we can
compose them in very simple and easy ways. But
it's actually understanding the relationships that's the hard part.
The is where the, the bulk of the work
is.
And I think that, that Plato got that, you
know, when he original made this allegory of the
cave, one of his goals was to explain to
people what exactly a philosopher does. What his job
is. The philosopher's job is to look at those
pictures, which is the only thing that we can
conceive, and from it, infer and construct that model
or form that's standing in front of the fire.
And so when it comes to UI and, and
software in general, the philosophy part falls to you.
That's your job. It can be very satisfying and,
and rewarding and I hope you have fun with
it.
Thank you.