ArticlesBlog

Ryan Grove: When Not to Use YUI

Ryan Grove: When Not to Use YUI


[applause] Ryan Grove: Thank you. I’m only a critic
because I love YUI. Jenny Han Donnelly: We know. Ryan: My name’s Ryan Grove. You can tell
because it says so on that slide. How many of you are morning people? Audience member: Woo! Ryan: All right, so everybody else, beat up
those people after my talk. [laughter] Because this is an unreasonable hour for anybody
to give a talk. Anyway, so that’s me. I know a lot of you,
but some of you I’ve never met so I’ll introduce myself. I work at a company called
SmugMug. If you haven’t heard of us, SmugMug is an awesome photo sharing website for amateur
and professional photographers. I joined SmugMug back in May, but they’ve actually been using
YUI for years, since long before I joined. Since the YUI 2 days. Before I joined SmugMug I worked at Yahoo!
for five years, two of which were on the YUI team. I worked on YUI components like AutoComplete,
History Model, ModelList, Router, View. Lots of stuff. I helped build the YUI website.
I gave as few talks as possible because I hate giving talks. But yeah. Before that I was a model for a Japanese clothing
catalog. [laughter] Believe it or not, that’s actually me. I
was a little bit younger back then. So here are some things that I like. Unfortunately
I don’t have time to talk about everything that I like today. I would love to, because
this is the stuff that I really care about. But today we’re going to talk about YUI,
and YUI is a pretty big topic too so specifically I’m going to focus on when not to use YUI.
I know that I just said that I really like YUI, so why would I tell you not to use it? Well, I think we should take a step back and
talk a little bit about what libraries are for. A library is something that saves you
time. It might save you time by ensuring that you don’t have to write frequently used
code over and over again, it might save you time by doing something that would be a real
headache for you to do yourself, it might save you time by just doing something that
you would rather not have to implement on your own. Maybe it’s not that hard but maybe
you’d just rather not have to do it. Whatever the reason for using a library, the point
of a library is to do certain things for you so that you can concentrate on other things. That’s a really good thing because when
a library does that stuff for you, you can concentrate on that other stuff that’s more
meaningful to your app instead of worrying about the foundational stuff, instead of worrying
about the stuff that you always have to do every single time. You can worry about the
specific things that make your application, whatever it is that you’re building, interesting
and useful. In short, libraries are powerful tools that can help you do your job faster
and better and more efficiently. Now, a library has to be generic enough so
that it’s useful to a lot of people, because everybody’s doing different things with
it. But if a library’s too generic then it’s not really useful to anybody. It’s
sort of about finding that sweet spot where it’s going to do the most good for the most
people and the least bad for the most people, but it’s never quite going to be perfect
for everybody. The best libraries, like the best tools, do
one thing well so that they can focus on that one thing and get it right. But we’re talking
about YUI, which does a lot of things, so where does that fit in? Pedantic people have
been pointing out for years that the YUI library is not actually a library, it’s a framework.
In fact, if you want to break it down further, it’s not really about UI so really the only
part of that name that makes sense is the Y for Yahoo!, although they just changed that
so it’s now more kind of an open governance model, which is really cool. So really the
entire name is just a lie. [laughter] But I don’t think it’s going to change
any time soon, and we’re here at YUIConf so we might as well stick with it. Anyway, YUI’s a framework, and a framework,
at least for the purposes of this talk, is a collection of like-minded libraries that
work together to accomplish a variety of tasks. In YUI you’ve got tools for working with
the DOM, you’ve got tools for managing classes and creating class hierarchies, you’ve got
low-level language abstractions and high-level widgets and tools for working on the server
and on mobile, on desktop. Basically, you’ve got this big fat toolbox full of tools. That’s
really great because it means that chances are, if you’re doing something with JavaScript,
YUI can probably help you do it; there’s probably something in the library that you
can use that’ll be useful to you. But just like a toolbox, you’re never going
to want to use every tool just because you have every tool. Just because YUI can do all
of these wonderful useful things doesn’t mean that you should always use all of YUI,
or that just because a tool exists you should always use that tool. You know when you’re unscrewing a screw
and you’re using a screwdriver and you get to that point where you stop using the screwdriver
and you switch to your fingers? You kind of do that naturally, you sort of have this inherent
knowledge of oh, the screw’s loose enough now, I can just use my fingers to get it the
rest of the way. You switch because… It’s not because your fingers are a better tool
for removing a screw, it’s because at a certain point the screwdriver, which is purposely
designed for that one task, actually becomes a little bit less efficient than your own
hand, which is a much more generic tool but there’s a point where it’s a better one. It’s really easy to start depending on YUI
for a lot of stuff just because it’s there. That’s your brain leading you into a trap.
You shouldn’t just depend on YUI, you should take advantage of it when it makes sense.
But there’s a situation that evolves when you’re using YUI in your app and you’ve
already loaded it on the page and you spend a bunch of time learning how to use it and
you’ve built out a bunch of code that uses YUI. You sort of fall into this trap of just
using YUI for everything just because it’s comfortable and it’s there and you like
it and you’ve grown accustomed to it. But if you think of YUI the same way you think
of your toolbox, your physical toolbox, you wouldn’t use a screwdriver when it doesn’t
make sense to use a screwdriver, right? You wouldn’t use a hammer when it doesn’t
make sense to use a hammer. You don’t really think twice about that. You look at your toolbox
and you think what’s the right tool for pounding in this nail, or what’s the right
tool for removing this screw. You’re not attached to those tools in a way that makes
you want to use them all the time for everything, and you really shouldn’t be attached to
YUI that way either. So understanding the tradeoffs that you’re
making when you use YUI or any other library, or any tool, that’s really the key to being
efficient with those tools. Understanding the tradeoffs means that you need to understand
at least a little bit about what’s going on under the hood, so you can’t just be
lazy and you can’t just sit back and expect a library to be magical. You can’t treat
it like a black box. You need to do some research occasionally. And you need to be curious. You need to open
up the source and peek under the hood and look at what the library’s doing. You’ll
find that sometimes it does a lot of great stuff for you, sometimes you’ll look under
the hood and you’ll realize you’re totally happy with it, everything that it’s doing
is awesome, everything it’s doing is something you need. Sometimes you’ll look under the
hood and you’ll be horrified and you’ll be like wait, this is not doing at all what
I expected. This is doing a bunch of stuff that I don’t need it to do, or what it’s
doing is not what I thought it was doing, it’s actually doing something a little different.
That’s what being curious can give you, it can give you that insight into what this
tool that you’re using is actually doing. Ultimately it comes down to one thing: if
you’re able to do something with plain old JavaScript, without using YUI or without using
another library, and it’s not going to waste development time and it’s not going to create
duplicate code and you’re not going to be reinventing the wheel – if it’s easy – just
use JavaScript. Don’t use a library just because you’ve got a library. So that’s your philosophy lesson. But I
want to get into some real practical examples of when not to use YUI. I want to stress that
when I or anybody else says don’t do this, it’s an opinion, it’s advice, so by all
means disobey me. I’m just sharing what I think, so people who have different opinions
are certainly going to think differently, and that’s fine. I think we should encourage
that. We’ll start simple. YUI has a Y.Lang namespace
that has a lot of really helpful utility methods for doing things like checking the type of
a variable. It’s got some other stuff, too, like Lang.sub can do string substitution and
things like that. That’s pretty useful. Most of the type checking methods are actually
pretty useless. If you look under the hood you’ll see this. I want to show you some of them. Here’s
isBoolean. This tells you whether or not a value is true or false. That’s all it does.
You incur performance costs for calling isBoolean, but if you look under the hood you’ll see
all it’s doing is typeof value===boolean. You could do this yourself in your own code.
It’s only in YUI for completeness, it’s only in YUI to complete an API. It’s easy
to say, well, it’s there so I’ll use it because it must be there for a reason, but
there’s a cost for using it, and you need to be aware of that. IsFunction has a pretty big cost actually.
It’s also doing a typeof check and then it does some other stuff. It does some logic
that really is only necessary in some edge cases that you’re probably never going to
encounter. It makes things a lot slower. IsNull, for checking whether something is null, just
does value===null. You can do this yourself without calling a function. IsString just
does typeof value===string. There’s nothing special there, YUI’s not saving
you from anything. It’s just completing an API. IsUndefined, typeof value===undefined.
You can do this yourself. The performance difference that you see here
is essentially, in most cases, the overhead of calling a function. It’s just function
call overhead to do something that you could have done inline. In some browsers that’s
not a big deal, like you can see Chrome is almost always whatever. In other browsers
it is kind of a big deal. iOS 6 it becomes a big deal. IE9 actually, I should point out
here, IE you probably shouldn’t compare too heavily with the other browsers on this
slide because I tested it in a VM, so it’s okay to compare its numbers with itself but
I wouldn’t use this slide as evidence of IE as super, super slow. I mean it is slow,
but it’s not quite as slow as it looks like it is. The point is, these things seem like
they’re doing something useful but they’re actually not. There are a few methods that do useful things
but you probably don’t need them. They’re useful in only certain circumstances. IsNumber
does a typeof check and then it also checks whether the number is finite, so unless you
know that you’re working with infinity or that you might get a value that equals infinity,
you probably don’t need to use isNumber. IsObject returns true for both objects and
functions, so if you don’t care about that, you can just do typeof value=object or typeof
value=function. Then there are some that actually do some
useful stuff: isArray, isDate, isValue. These do things like cross-browser consistency issues.
isValue does a number of checks that it would be pointless to duplicate in your own code.
So these are pretty useful, and it probably makes sense to use these if you need to do
what it is they’re doing. There’s another method on YUI, on the core
object, that I see people use a lot, and there is never a case where you need to use this.
This method actually exists for one reason, there’s one place in YUI when it sets up
the global YUI instance where it needs to pass in a value that could end up being the
global object, the window. It turns out there’s apparently a memory leak in older versions
of IE if you do an instanceof check on the window or the document. YUI has this method
that accounts for that memory leak in that one specific circumstance, but you’re never
going to encounter this. You are never going to do an instance of check that’s going
to pass in the window or the document. There’s no reason to do that, so there’s no reason
to use this. It incurs a big cost and it covers a very, very narrow edge case that almost
certainly does not apply to you. But people see it on the API and they think
it’s there for a reason, it must be safer than the native instanceof operator so I’ll
go ahead and use it, and that’s not your fault. This is something that I think can
be… It’s a situation that can be avoided with documentation, that’s clear, and the
documentation, to its credit, does tell you what the edge case is. But I think it could
be more explicit about how rarely you should need to use this. So those are some small examples, but I do
want to go after some big fish. There’s one really big fish in YUI and that’s
Y.Base. Y.Base is one of the most useful foundation classes in the library. You can tell that
that’s the case because everything uses it. If you haven’t used it before, Y.Base
is just a foundational class that gives you a lot of functionality. It gives you initializer
and destructor functions so you can manage the life cycle of your class, it automatically
gives you built in support for attributes, built in support for custom events, and when
you create a subclass hierarchy it aggregates the attributes up that hierarchy. If you saw
Luke Smith’s talk yesterday where he was talking about attribute he kind of touched
on some of this, specifically the attribute aggregation. This is all really useful stuff, and there’s
also some sugar if you use Base.create. It helps you create your classes. It takes care
of creating your constructor function for you and chaining the constructor to its superclass.
It gives you some nice sugar for mixing in extension classes. So it’s really handy
and it’s really easy to use, and it’s really tempting to use, but there ain’t
no such thing as a free lunch. All that awesome functionality is really useful and it’s
really awesome, but it has a cost and you need to be aware of that cost. I benchmarked creating an instance of base
versus just creating an instance of a vanilla JavaScript function. This looks really scary
because the difference is so huge that if I use percentages to try to explain it, base
is virtually 100 per cent slower all the time, so if I use absolute numbers it’s easier
to talk about it. If you look at Chrome, for example, 1,100 instantiations per second for
base is actually a pretty good number. If you can do something 1,100 times a second
that’s not what I would call slow in absolute terms, until you compare it to a vanilla JavaScript
constructor and you get 4 million instantiations per second. I wouldn’t freak out about this
because this comparison is literally doing nothing. My JavaScript constructor is doing
nothing at all, my base class is doing nothing at all except what base is doing under the
hood. But the interesting thing is that this is
the cost that you incur as a baseline, before any of your own code runs, before your implementation,
whatever it is that you’re building on top of this, before that even enters into the
picture, this is the cost that you’ve incurred. But execution speed isn’t the only thing
that you need to worry about. Despite what Doug Crockford said yesterday, you do need
to think about memory usage. This does come up. Base clocks in at about 2 kilobytes per
instance, so if you can think of creating 1,000 instances of base, that’s going to
end up being about 2 megabytes of RAM. That doesn’t seem like a lot, but that’s before
you’ve built any of your own stuff on top of it. You compare that to a vanilla JavaScript function,
12 bytes per instance. That’s bytes, not kilobytes. That’s because this vanilla instance,
this JavaScript instance, doesn’t have to recreate everything for each instance. It
just has one prototype on the constructor and that’s where everything lives, that’s
where all of your methods and your properties, everything that lives on the prototype lives
there. So each instance is just a tiny, tiny little thing that in most cases just chains
back to the prototype object. You can get 1,000 vanilla JavaScript instances
for the cost of about 6 base instances, and that’s not a trivial difference, especially
for mobile devices with limited memory, for older machines. Since Y.Base is a foundational
component, even if you yourself have never knowingly used base, you’re probably using
it even if you don’t realize because so many things use it under the hood. These are some of the components in YUI that
extend base. I’m not saying that these classes shouldn’t extend base, and I’m not saying
that you shouldn’t use these classes, and I’m not saying that you shouldn’t use
base. The reason I’m showing you this list is because I want to stress the point that
you need to understand the costs of what you’re using and you need to understand the context
in which you’re using these things. Sometimes the benefits outweigh the costs. If I’m
going to create one instance of a widget that uses base, no big deal, that’s a cost that
it totally makes sense to pay. If I’m going to create 1,000 instances of something, that’s
a cost that I would need to think more carefully about. So when is it worth it to use base? When you
need attributes, when you need events, when you need life cycle management, and when you
need extensions or are likely to need extensions. If your answer to any one of these things
is I don’t need that, or I’m not sure if I need that, then you should probably think
pretty critically about whether or not you should use base. If you only need attributes
you can just use Y.Attribute. If you only need custom events you can just use eventTarget.
If you only need life cycle management you can do that yourself without too much code
if it’s a performance critical situation. So think carefully about what you need and
what parts of base you’re using before you extend the entire thing and incur all that
cost. But the most important thing to consider is
how many instances of this thing you’ll be creating, how many of these things will
live side-by-side on the same page. If you only need a few instances, probably not a
big deal to use base. If you need thousands, like I said, performance is at some point
going to become a problem for you. But who really needs a thousand instances of something?
I think Doug mentioned this yesterday in his talk as well. Nobody ever creates thousands
of instances of something in JavaScript, that’s silly. Yeah, actually, if you use model and view
you could easily end up with thousands of instances of something. If you’re using
model to represent database rows or if you’re using view to render those models, if you’re
not careful you can easily end up with thousands of instances, and these use base under the
hood. They were on that list that I showed you earlier. So why do model and view use base? I would
like to point at one of you and blame it on you, but actually it’s my fault. When I
wrote them, even though I was aware of the cost, even though I had benchmarked base and
it was something that I was thinking about as I was writing these things, I banked too
much on the value that I thought I was getting out of it and I banked too much on promises
of future performance improvements, which you may also have heard some of yesterday. But I would caution you: don’t believe anybody
who promises you that something is going to get faster without you doing anything. They
might be telling the truth, but you can’t trust that. Things rarely just get faster
magically. That’s not something that you can bank on. Because I was too focused on doing things
the YUI way, and because I’d gotten my benefit versus cost balance out of whack when I designed
these things, I don’t think I made the right decision. That’s my fault, and hindsight
is 20/20, so I’m sorry about that. But if it makes you feel any better, I’m actually
dealing with the consequences of this myself now. I’m on the other side and now I have
to use the code I created. Back in May, as I said, I left Yahoo! and
I joined SmugMug. SmugMug is probably the single heaviest user of model and view that
I know of in the world. They were using them right out of the gate, before these things
were even officially released. To their credit they’ve built a wonderfully usable developer
API so that developers can be really efficient with the things that we built on top of these
foundation classes. But the problem is performance starts to suffer. When you do a search on SmugMug you get this
gorgeous search result page. It’s just wall-to-wall images, and as you scroll down more results
are loaded automatically. It’s just infinitely more and more results. You can click on an
image after you’ve scrolled, it’ll remember where you were, you click the back button,
it brings you back where you were without having to re-scroll through all those images.
It’s a really… It’s a nice experience. When you’re hunting for a beautiful image,
you don’t want to have to deal with a bunch of UI chrome and pagination crap. So it’s
a fantastic experience, in theory. Shortly after this launched, users started
complaining. They started saying that it was bogging down their computers, and as they
scrolled down through a few hundred images things would get slower and slower. In some
cases their browsers would become unresponsive; some of them even had their browsers crash.
So it wasn’t as good as we thought it was. When SmugMug hired me one of the first things
they did was show me this, and they told me about the feedback that they’d been hearing.
Obviously the first thing I thought was oh crap, there’s probably a bunch of models
and views in there. This is probably my fault. [laughter] Look at this mess I’ve gotten myself into.
I wanted to get to the bottom of the problem. Sure enough, it was right. [laughter] There were tons of models and views. Each
image on this page is represented by a model and rendered by a view. If you have 100 images
on the page you have 100 models and 100 views. Since the page scrolls infinitely, as you
scroll down more and more you get more and more models and more and more views. This
particular page has an interaction where users are very likely to scroll down to potentially
thousands of images because they’re searching for that one image that they want to find. Needless to say, this eats up tons of CPU,
it eats up tons of memory. Not only were those model and view instances consuming RAM but
you also have to think about the DOM elements that are actually rendering these things on
the page, the image data that has to sit in memory for each image on the page. This is
all taking up memory. This worked okay in Google Chrome on our Mac Pro desktops with
16 GBs of RAM, but not everybody has a Mac Pro desktop with 16 GBs of RAM and not everybody
uses Google Chrome, so when our users running IE8 on their ancient crappy Window laptops
were searching for photos, it was unusable and they were miserable and they hated it. To make matters worse, it turns out even when
we tried to clean up after ourselves, even when we tried to say as you scroll down we’ll
remove unused models and views, we’ll destroy them, we’ll clean up the memory, it turns
out YUI was leaking memory. There was a leak in the event system that was holding on to
objects that had been passed through event facades so they weren’t being garbage collected.
We ended up duck punching YUI to fix this. The good news is it’s been fixed in core,
so I think in 3.7 that issue is fixed, you don’t need to worry about that any more. After we tackled the memory leaks, the next
thing we did was we changed the way that we rendered image tiles. Instead of having a
view per tile, we just created one big view for the entire set of results. We rendered
the results one at a time within this big view in blocks of 50, but we’re not incurring
that cost of a view instance for each result because that wasn’t really buying us anything. We found one of the other costs that we were
paying was just responding to scroll events as the user scrolled down. That can actually
get pretty expensive because scroll events fire really frequently and there’s a lot
of work that you have to do to calculate metrics to calculate where you are in the view port. We wrote a plugin for this. You can plug it
into any Y.Node instance and as that node is scrolled, whether it’s the body or any
other node, you get a throttled scroll event for it, so it’s not going to fire every
single time the browser’s scroll event fires. It only fires every 50 or 100 or 200 milliseconds.
It gives you efficiently gathered metrics on the scroll positioning and caches things
pretty smartly. It also tells you which nodes on the page are currently visible within the
view port. This allowed us to say, well, if the user only sees 50 images within the view
port then the 1,000 images that are up here, we can just hide those and now the browser
doesn’t have to worry about them so as they’re scrolling it actually gets more responsive. We contributed this back to YUI, so it’s
in YUI now as of 3.7. You can use this in your own stuff. So that took care of our view problem, but
we still have thousands of models on the page. We didn’t want to stop using model and modelList
because it was really useful, particularly modelList was useful for us because we were
using it to do pagination and to make API requests and load new images as we scrolled.
But as it turns out we weren’t actually using most of model’s functionality, because
once a result is loaded it doesn’t change. There’s no point using a model that has
attributes and change events and validation and save and load functionality for something
that isn’t going to change once it’s loaded. So we wrote a thing called lazyModelList,
and it gives you the exact same API as modelList but it manages a list of vanilla JavaScript
objects instead of a list of model instances. So if you need a full-fledged model you can
revive it from the list and you get an instance of model, and you can use that however you
want, and then when you’re done with it you can free it and the data still lives in
the list. You can get it back if you want it, but you’re not creating thousands of
model instances. We contributed this back to YUI as well. It’s
in 3.6, so you can use this. The performance benefits that we saw were
pretty significant. Not only did the interface feel much more responsive, but in raw numbers
we saw improvements in the initial rendering time of the page, we saw improvements in the
time that it takes to manually scroll to the thousandth result, and the biggest difference
was memory usage. After 1,000 items on the page we were using 63 per cent less memory
than we were before. In addition to that, the memory that we were using increased much
more slowly as you loaded more images. Even in IE8 on an ancient Windows laptop, this
interface was still pretty beautiful and it was still really responsive and it wasn’t
crashing people’s browsers any more. This got me thinking… It got me thinking
about taking a different approach to building YUI components. Over the last few months I’ve
built a number of components for SmugMug that basically threw out the old rule book. Before
I reach for a YUI class or a utility method I think about it and I ask myself what it’s
really buying me, and at what cost, and am I doing this because it’s the right way,
or am I doing this because it’s the YUI way? I try to think critically about that,
I try not to be too attached to YUI just because I like it. This has led me in some interesting directions.
One of the things I found myself needing was templates. I needed some really simple templates
just to handle some HTML for some simple widgets. Y.Lang.sub, which does string substitution,
wasn’t quite as good as what I needed. I need a little bit more than just substitution.
Handlebars I could’ve used, but it did a lot more than I needed and it was… You know,
it incurs a page weight cost, it’s fairly heavy. So I really wanted something in between,
but there wasn’t anything like that in YUI. I started looking in Underscore.JS. Underscore
templates are really simple. It’s a really simple implementation, it’s really fast,
it did exactly what I needed. But I didn’t want to load all of Underscore just so I could
use templates, because I’ve already got YUI on the page. Instead I wrote something similar to bring
Underscore style templates to YUI. It’s called Template.Micro, and it weighs in at
about 50 lines of code minus comments. It significantly out-performs Handlebars and
it’s even a little bit faster than Underscore. It’s a nice, lightweight templating solution
for when you need to do something that’s just sort of in that Goldilocks area between
string substitution and a full-fledged template language like Handlebars. This actually just
went into YUI in 3.8 PR1, so you can use this now as well. Next I found myself having to develop a TreeView
widget for SmugMug. I was a little worried about this because as some of you may know,
TreeView has been something that YUI users have wanted for years, and it’s been something
that has been in development for years and has never quite made it into YUI. There are a bunch of TreeView widgets in the
gallery. Some of you may be using them. I looked at those because, obviously, why rewrite
something when there’s existing code. The problem is, for the most part, they try to
do things the YUI way. This is why none of them is really very good, unfortunately, because
the YUI way is to use widget parent and widget child to manage node instances, manage your
tree nodes within the tree, or at a minimum, use Y.Base and allow the instances to have
attributes and change events and things like that, because that’s super useful, that’s
what you want. But it turns out that’s really, really bad
for performance. I mean you’ve got a tree that’s got thousands of nodes. That’s
awful. We’re back to that situation I described before with models and views. I decided sure, I’m going to write this
TreeView, it’s not going to use base for nodes. My first thought was I’ll use a modelList
or I’ll use a lazyModelList to store this node data. Then I realized I was still thinking
in the YUI way. Even though I had created this lazyModelList that was more performant,
that still wasn’t the right thing to use for a tree. LazyModelList and modelList, they’re
great for representing lists of things, flat lists of items, but a tree, it’s not flat,
it’s deep, it has a thing that can contain another thing that can contain another thing,
and it can be infinitely nested. So modelList was the wrong choice for that. There was nothing in YUI that did what I needed,
so I created a real tree data structure, and that was where I started. The tree itself
is actually a base based class. It extends Y.Base, because you’re probably not going
to have more than a few TreeViews on the page, and if you do you should rethink your life
and go talk to a designer because you’re probably doing something wrong. It’s really useful for the tree to extend
base because it has attributes, it has events. You need to have an initializer destructor
life cycle so you can clean it up after you’re done with it. But for the tree nodes, these
are just vanilla JavaScript functions. They expose properties and they have methods, but
most of their functionality actually lives on that tree. The thing that you do on the
node just calls back up to the tree whenever it needs to do something. Events for adding and removing tree nodes,
stuff like that, those are exposed on the tree delegation style. Instead of subscribing
to stuff on the node, you subscribe on the tree and the tree tells you when something
happens. This means that the tree nodes themselves are super lightweight. They’re super, super
cheap, so you can create thousands and thousands and thousands of these and the browser doesn’t
care. You get a friendly convenient API on each node, but the cost is so low that you’re
no longer in that territory of because you’re trying to do something the YUI way, it’s
actually unusable. Now this is usable. You’re not paying for something more than you should
be. The tree provides the underlying data structure
but it doesn’t provide a UI, so on top of that I created a TreeView widget, although
actually it’s not a widget in the sense that it doesn’t extend Y.Widget. It’s
actually a view, because when I looked at what I needed from it I realized I didn’t
need most of what Y.Widget was doing. Y.Widget does really good stuff, but I didn’t need
a three step render life cycle, I didn’t need to parse a DOM structure, I didn’t
need heightened width management, I didn’t need to re-fire DOM events, I didn’t need
internationalization, I didn’t need… There’s a ton of stuff that it did that I didn’t
need, that’s all good stuff but for me it would have been wasted code. Whereas what
I did need was a DOM container, I needed a render method, I needed an easy way to attach
events, and that’s basically it. Everything else was going to be custom to my implementation. It turns out that’s exactly what Y.View
does. I ended up not duplicating any code from Y.Widget, which tells me I probably made
the right choice. The end result is a tight, efficient component
that doesn’t have any wasted code, it doesn’t have any wasted memory, it doesn’t do things
strictly according to the YUI way but as a result, it’s fast, it’s efficient, and
it exists and we can use it. Most importantly, since I spent my time using the parts of YUI
that made sense and that helped me instead of fighting the parts of YUI that weren’t
helping me, it didn’t take me forever to build this and I actually really enjoyed building
it. I didn’t find it frustrating. SmugMug also needed a menu widget. We had
been using the node MenuNav plugin in YUI, but it’s pretty old, it’s virtually unmaintained,
and it didn’t do most of the stuff that we needed it to do. So I set out to build
this, and when I sat down to build it I realized it’s just a tree under the hood. An hierarchical
menu is just a tree data structure, so I had already built most of it. All I had to do
was slap a view on top of it to render the menu and to do stuff that’s specific to
a menu like repositioning things if they’re going to show up outside the view port, and
that was it. Instead of wasting my time fighting YUI again, I spent a week building an awesome
menu widget and focusing on the things that mattered to my menu instead of trying to solve
problems that I’ve created for myself by using parts of a library that I don’t need. Then I started brainstorming, because when
you’ve got free time… I had finished my work, I had nothing to do, so of course I
start thinking crazy thoughts. One of the drawbacks to my tree node approach is you
make a tradeoff, because the tree nodes just have properties, you don’t get change events
when you change a property. That’s kind of unfortunate, but it’s a nice tradeoff
for performance. But what if there was a super lightweight
way to get notifications when I change a property but without ballooning the cost of each tree
node, without using the full-fledged Y.Attribute? It turns out there is. Again, Luke mentioned
this in his talk yesterday. ECMAScript 5 introduced a feature called Object.defineProperty. It
lets you do with JavaScript properties a lot of the stuff that you can do with YUI attributes.
You can have getters and setters, you can make them read only. Since this stuff is built
into the language, you get it at virtually no cost. All I really needed was a lightweight
shim to handle IE 6, 7, and 8, which don’t support this, and then I could probably have
my cake and eat it too. I built a component called Y.Property, which
in good browsers exposes just a thin API over the native functionality, and then in those
IE browsers that I mentioned uses conditional loading to load an IE-specific shim that’s
still really small and just provides that same functionality without ES5. This isn’t
quite fully baked yet, but you can see the instantiation cost here is already significantly
lower than attribute to the point where it’s something that you could probably consider
using for a tree node that you might have thousands of. It doesn’t give you everything that attribute
does; attribute does a lot more than what property can do. But it gives you just the
core stuff and just the stuff that I cared about for my tree nodes. If you’re interested
in what this tradeoff is and what stuff attribute does give you, I hope you got a chance to
check out Luke’s talk yesterday, and if you didn’t, you should check out the video
of that when it hits YUI Theater. I haven’t contributed the tree node or the
menu or Y.Property back to YUI yet because I’m not quite done with them, but I hope
to. SmugMug is already using these, and you can use them if you want to. We’ve got a
fork of YUI 3 on GitHub where we maintain this stuff, so you can check this out there
if you’re interested. I’ve given you a bunch of advice so far.
I’ve told you to think twice before using YUI for everything, I’ve pointed out some
parts of YUI, specifically, that you might want to avoid. I’ve recommended ignoring
the YUI way when there’s a simpler or better way to do things. But what if the simplest, fastest way to do
something is not to use YUI but to use another library? Should you port your application
to that library? Should you stop using YUI and switch? I don’t think so. I think that’s
a horrible idea. If your app is benefiting from YUI in certain areas, keep using YUI.
Maybe your app, in another area, might benefit from another library, but YUI’s not a religion.
This isn’t a zero sum game. If you use another library for something that YUI doesn’t do,
or doesn’t do well, the YUI gods aren’t going to smite you. You can use JQuery occasionally,
it’s okay, we won’t judge you too much. You probably shouldn’t load another library
alongside YUI to do stuff that YUI already does really well. That would just be wasteful.
But if there’s a gap in YUI’s functionality, or if another library can help you do something
better, I say use it. You know, there’s a lot of this stuff out there now. Over the
last few years there’s been an explosion in… Some people call these things micro-libraries,
some people call them micro-frameworks. I just call them libraries. But there’s been
an explosion in single-use utilities. Some of them are crap, some of them are really,
really good. I don’t think there’s any reason not to use these when it makes sense. One concern that people have is YUI is really
modular, and if I stick with YUI I get dependency management, I don’t have to worry about
how to load stuff, I can load stuff from the Yahoo! CDN, it’s combo-handled. If you want
to pull in a third-party dependency, what a lot of people do is they’ll manually wrap
that dependency’s JavaScript in a YUI.add call so that they can manage it as a YUI dependency.
But then that adds maintenance cost for you, and you have to maintain that code for yourself,
on your servers. You can’t use a third-party CDN. That’s really kind of a pain. But it turns out there’s actually a much
easier way. YUI Loader will do this for you, and you don’t have to do any special work
despite what you may think. Here’s a simple example. Let’s say that
you’re building something that needs some really fancy regular expressions. There’s
this great library by a guy named Steve Levithan called XRegExp that implements a lot of regex
functionality that’s not available in the JavaScript language. But it’s not a YUI
module. You can load it from CDN JS, but it’s not going to automatically work with YUI,
but you can make it work. This thing right here is a YUI config object. If you haven’t
used it before, you can pass in a configuration to your use call when you create a YUI instance
and you can configure all kind of stuff about how YUI loads things and where it loads them
from. So this is where custom module meta-data lives, for example. The first thing we need to do here to load
our XRegExp library is just create a group to tell it the modules defined in this group
are different from YUI core modules. Load them slightly differently. Don’t use Yahoo!’s
CDN, don’t use a combo-handler. Load these from CDN JS. If you haven’t heard of CDN
JS it’s a community hosted service for free CDN hosting for open source JavaScript libraries. The next thing that we do after we’ve set
up our base CDN JS group is we create a module for XRegExp and we tell it here’s the path
to XRegExp relative to our CDN base, here’s how you load this file. It doesn’t have
any dependencies so I haven’t listed any requirements here. The tricky part is because
we’re loading this third party code directly from a third party server, it’s not a YUI
module, so YUI won’t know about it. That’s why a lot of people wrap third party code
in a YUI.add call themselves. But you don’t have to do that. It turns out we can cheat, because YUI gives
us this onProgress callback. Every single time a JavaScript or CSS file loads, YUI will
call our callback. This is triggered by the script and CSS load events from the browser,
it’s not specific to anything YUI related. When YUI calls onProgress, it actually tells
us the module name that was associated with whatever file just loaded. We can see that
our XRegExp file just finished loading, we can see that that module name’s associated
with the file that loaded, we can dynamically create a YUI module to wrap XRegExp, and we
haven’t had to modify the code, we’ve just put a little bit of extra configuration
in our YUI code. YUI treats it just like any other module. You’ve got this module now that you can
use in a use statement, your other modules can depend on it, and YUI knows how to load
it just like core modules. YUI wants you to succeed. It’ll happily
help you load third party JavaScript onto your page and manage those dependencies just
like anything else in YUI. By all means use YUI, but don’t use more of it than makes
sense. Be curious. Look at the source code. Sometimes you’ll be pleasantly surprised,
like I said. Sometimes you’ll be horrified. But you’ll always learn something. Before
reaching for that screwdriver, consider whether you can unscrew that screw more efficiently
with your hand, with the tools that you already have at your disposal natively. Luke said this yesterday: YUI and other libraries
aren’t magical, magic is just more code. All these libraries, they’re using the same
JavaScript engine that you have access to. Read the source of the libraries that you
use. Learn how they work, understand what they’re doing for you, understand what the
cost benefit tradeoff is. And remember that your job is not to use YUI
or to use another library, your job is to make something awesome. Your users don’t
care whether this awesome thing has YUI under the hood or JQuery or Bootstrap or Dojo or
Ember or whatever. They just care whether it’s awesome. So don’t be loyal to your
tools, be loyal to your users. That’s it. Thank you. [applause] Jenny: Thanks Ryan, thanks Ryan. Great talk.
Any questions for Ryan? Ryan: No questions. Audience member: In the case of using a third
party library like JQuery or Dojo or Prototype or something like that that has completely
different DOM accessor methods than YUI does, how do you keep that code base from getting
really dirty? Ryan: I think that’s really tricky. That’s
why I kind of stressed the micro-libraries and the micro-frameworks. I think if you’re
going to load something… I mean, Prototype, Dojo, those older libraries that kind of came
around the time that YUI did or even before, they tend to be a little more monolithic,
so they tend to include DOM management and effects and all that kind of stuff. Using
something like that might not be the best choice. You might want to look for a smaller,
single-use library that does just what you need. Like I said earlier, I saw that Underscore
had something that I wanted but it also had a ton of crap that I didn’t want, so I ended
up not using Underscore. It would have been really nice, actually, if there was something
that did just that templating piece and I could have just used that. But that’s what
I would recommend. Audience member: Thank you. Jenny: Over here. Audience member: What are your thoughts on
having good maintainability of code by offering an easy to follow structure for developers,
as opposed to having all kinds of different frameworks and just plain JavaScript? Do you
think that’s also something to consider? Ryan: That’s a really good question. Absolutely,
I think that’s part of the cost benefit tradeoff that you have to decide on. There
is a huge benefit to having easy to read, easy to maintain code, and that’s a big
part of what libraries provide for you. You pay a little bit for that. There’s a cost,
usually, in using an abstraction, but it’s about deciding where the balance is. At what
point does the cost start to outweigh the benefit? That’s why I stressed if it’s
easy for you to do something yourself, if it’s not going to duplicate code, if it’s
not going to reinvent the wheel, then you could probably do it yourself without incurring
maintenance cost or making things hard to read. But at the point where the library’s doing
a lot of useful stuff for you then use the library, even if the cost is… Even if it’s
going to slow down performance a little bit. I would tend to side on the side of making
things more readable and more maintainable, which is why I still use Y.Base, as you saw,
for my TreeView. Even though I could have done the entire thing native and made it faster,
I thought there was a good benefit to using base for the tree component. Other questions? Luke Smith: Hey. Ryan: Hey. Luke: So fantastic content, I love it, and
I think that there were actually some points in there that my talk from yesterday… This
is Luke, I guess, if… Ryan: That’s Luke Smith. Luke: Yeah, this is me, hey. That actually
work well together with what I was talking about yesterday. In particular there were
a few examples of the use of ES5 directly, those setters and getters directly from ES5,
for browsers that support that. The development of Y.Property is being a closer shim to that. The two things that I think are really great
about that is that it manages to preserve that abstraction of going through a get and
set method, it’s just not implemented using attribute it’s implemented using property. Ryan: Right. Luke: But then there’s also the idea that
now there is some work that validates the alternate implementation of that abstraction,
using that lighter shim, that can potentially now displace some of what’s in attribute
and then make attribute faster. Ryan: Yeah. Luke: In terms of the implementation improving
invisibly, that’s actually an example of that work. Ryan: Oh, you’ve proved my point wrong with
my own things. [laughter] That’s brilliant. Luke: But no, no, no. That wasn’t the impetus
of that… [laughter] But I was saying that I’m glad you’re
doing it because now we can do that. Ryan: Yeah, I think that is a good point,
and it’s my evil master plan actually. I would love to see property slide in under
the core of attribute and provide that core stuff that they both do and hopefully make
attribute a little faster. Luke: And actually by doing so I think you
make a really good point, which is that the core team didn’t do that, but you did that
as a contributor. To your point of don’t count on the magic getting cheaper over time,
if it’s not getting cheaper over time, if you’re feeling that way, fix it. Ryan: Right, exactly. Luke: Contribute that back into the library
and everybody benefits. There’s a huge benefit to being a part of the library and that community. Ryan: Absolutely, that’s how things get
better. You can’t just depend on the core team for every piece of innovation. I mean
these guys are busy. They’re brilliant, but they’re busy, they’re not going to
be able to do everything. Luke: And also, isNumber does check for NaN. Ryan: It checks for NaN, but I don’t care
about NaN. [laughter]
Luke: You care about NaN. Ryan: Who cares about NaN? I hate NaN. [laughter] Other questions? Maybe one more? Jenny: Okay, thank you Ryan. Ryan: All right, thank you guys. [applause]

Comments (2)

  1. thank you a lot, learn many tricks and some informations inside GUI

  2. not GUI in my last comment, it should be YUI

Comment here