>> ERIC FERRAIUOLO: I'm Eric Ferraiuolo. I'm going to be talking about the YUI App Framework
today. If any of you were in Luke's talk yesterday, he was talking about the building blocks of
building classes and different things with YUI, and he sort of ended at MVC stuff. We're
going to continue from there in my talk and talk about some of the stuff we're doing in
the App Framework.
The first thing I wanted to get to was MVC. MVC is a pattern of breaking apart your code
that seems to be very common in especially GUI environments or user interfaces. The idea
of Model-View-Controller... How many of you are familiar with the MVC concepts? Everybody.
Awesome.
Just to touch on maybe why you'd want to do this in a web application UI, you can separate
out your data from your rendering. One of the main things you could think of is a common
example: you have a user name displayed in the top right corner of the page and in the
main content area of the page, and then you have a UI for the user to update their name.
When they go to update their name you may have to write a procedure that basically says
OK, go store that on the server, then go manually update in the top corner and manually update
it in the main area of the page. This is a very tight coupling and leads to refactoring
problems, and it doesn't really separate the concerns of what you're trying to build.
The App Framework is an MVC-ish like framework to help formalize these concepts inside of
YUI.
I wanted to point out that Backbone is a really awesome MVC-ish library for client side and
server side, somewhat, to implement these techniques. It's a very elegant, simple approach.
It does some interesting things with respect to Models and Views that we've found to be
excellent. We wanted to follow their lead but there were a lot of things we already
had in YUI. We already have Y.Base, we already have attributes, we have Node. Just trying
to figure out, well, we need to formalize these concepts. We already have these good
underlying utilities; let's see if we can follow the lead with Backbone, which has been
getting a lot of steam, but have something in YUI where you don't have to use multiple
libraries if you want to do MVC-like stuff in YUI. You don't have to include Backbone,
which requires Underscore and jQuery and stuff. We had everything already for the requirements.
The first thing I want to talk about was just the Model, and in particular Y.Model, and
maybe some of the things that Model is doing. Like I mentioned, we already had Base, and
Base has attributes and custom events, but there are some things that Y.Model does to
help you focus more on a class that is for dealing with your data.
One thing that's common against any MVC framework is that the Model, its data is observable,
so anytime there's a change in the data housed in the Model there's a change event fired
or something. We wanted to make sure we had that. But that's already a part of Attribute;
the thing that we add in Y.Model is this coalesce change event, so if multiple data attributes
are changing at once inside the Model, one high level change event is fired. That works
out really well for being able to have a UI to respond to that one event and, say, a View
rerender itself.
We also added this idea of a sync layer inside of Model. This is so that you can sync data
between, say, a server and the client, and have your business logic around that syncing.
If you're doing any type of validation of cross attributes before you go and save that
to the server, or you need to load data from the server, that's what the sync layer handles.
There's another thing that we added around dealing with Models, which is ModelList. ModelList
basically adds collection semantics to working with a set of Models. The interesting thing
that we do in Y.ModelList and Y.Model is that a Model can exist in multiple lists, and these
lists are usually used to help you work with your data. They have nice methods for iterating
over the collections and they can be ordered. They have some nice conveniences for loading
a set of data from the server into a ModelList, and it will automatically create the Model
instances for you.
You could think of if you're working with a page set of data where the data's broken
up into separate pages and maybe you have, I don't know, a list of users, and then you're
looking at page one, and then you go to page two, you can imagine a ModelList being used
to represent the current working set that you're looking at. Like I'm looking at the
first ten users and then I can reset the ModelList with the eleventh or twentieth users.
One thing that we also added is, using the custom event infrastructure in YUI, if you
call set... Say I'm calling set on this fourth model in the list, any events like the change
event that would fire from setting some data attribute there will bubble up to the list,
so you can just listen on the list for any changes. This is really nice because you don't
have to worry about what's inside the list. You just know you have this list and any time
there's a change on one of your foo models, you can respond to that.
One of the other components in the App Framework is View. The View is a renderable chunk of
your application and it has an idea of a container. The View instance is using that container
and it will deal with rendering stuff inside of it. The thing that we have is... View doesn't
really contain much logic; it's more of a code organization tool, but it has some conveniences
as well. One thing a View has is a render method, but what the contract is, is you have
to provide the implementation of that. There's going to be no prescribed rendering of your
View.
The same goes for templating. There are hooks in there to provide your template, but it's
really up to you to choose. It doesn't force you into using any particular type of templating
or any particular type of rendering; it's totally up to you. But what it does have that's
nice is a way for you to declaratively define your events around that particular chunk of
your UI. This is really nice because it uses event delegation and allows you to declare
up front that if a particular Node in your View is clicked on that you can respond to
that.
This makes it really powerful and also helps you work with your Models so your View can
be instantiated and passed in a Model instance, but it doesn't have to. Or it can be passed
in a ModelList; that's commonly what they're used for. But you can use Views to just break
apart your rendering hierarchy of your page.
It's also a very lightweight class. Like I'm saying it has some conveniences for you but
it's really left up to you to implement the rendering of your Views.
The other component that we have is Router. It used to be called Controller but the View
works more like the Controller in the YUI App Framework. It was basically a poor naming
decision we did in 3.4, so we've renamed it to Router because it's basically used for
navigation management, for dealing with changes in your URL and responding to that. If you
have a single page application but you want to have bookmarkable URLs, Router is a good
thing to use for that.
It will seamlessly deal with older browsers by using a hash based URL. You can imagine
a URL at example.com/hash/, some URL, some path, and it can seamlessly upgrade and switch
between the two. If you were on an IE browser you would have that version but if you're
on Chrome, Firefox, Safari, or iOS, you would get the nice HTML5 pushState and full URLs.
The way that the HTML5 history APIs work is you can add history entries which will change
the full URL, the full path, without causing a request to go off to the server. Then accompanying
that is a popstate event which is used if the user's hitting the browser backwards or
forwards button; a popstate event occurs and you can listen for that and rerender the state
in your application.
I wanted to show... The Router is somewhat more complicated, or maybe something that
people haven't experienced before, so I wanted to go over it in a little more detail. Here
we have a basic example of the simplest Router you could do that actually did something interesting.
At the top here I'm just instantiating a new instance of a Router. You can also subclass
Router; it's meant to work either way. In this case I'm just going to create a new instance.
I'm telling the Router to route any path that is /library/, and then this lib here is like
a placeholder, or a variable you could think of, to this callback function. This callback
function then is passed a request object.
What I can do is look at the parameters of this request object, which include this placeholder
lib parameter from the URL. I can get a reference to that and then in this case I see if the
library equals YUI then I can just say log out to the console how awesome YUI is. Then
to have this route be dispatched, or to change the URL and then have the Router call into
my callback here, you can call save and this will save a new history entry and update the
URL and dispatch to any route handlers that match. In this case my route handler does
match, and it will print out "YUI library is awesome".
We already had a history manager in YUI, but Router adds a little more to it, and it actually
uses history under the hood. It actually has an instance of history. What this helps with
is normalizing the two different ways that the history or the URL could be changing.
I mentioned before that the popstate event is in the new fancy HTML5 history browsers;
when you hit the forward and back button it gracefully degrades to using the hash change
event which exists even in IE. But then also when you call save and replace on the Router,
the API method save and replace, it will call into history and call pushState. But all of
these things together end up firing this history change event, so the Router is listening for
its history instance to fire this change event. When it does it goes ahead and dispatches
to the route handler that matches, the first one that matches.
It's nice that all this is baked in for you. Otherwise people would be just writing this
type of thing over history all the time.
So far, I went over what we have in 3.4. What's nice is we had all these components already
and we just formalized these concepts using them. The Model, ModelList, View, and Router,
all only came out to 4.6 kilobytes of new code in the library to have all this functionality,
which is really great.
The other thing is as we were developing these App Framework components there were people
who were literally using what we were pushing to GitHub. Right after we pushed to GitHub
people started using this, so it was great to see how well received all this was with
the community. It really showed us that people did actually need this type of thing, this
formalization of these concepts, this way to help guide them in structuring and breaking
down their applications.
But we're not stopping there. Next I'll go into what we have coming. By the way, coming
is actually really soon, because a lot of the stuff I'll be talking about now is already
on GitHub. We have our first PR of 3.5 next month, so this stuff will be coming out next
month. The official GA release of 3.5 is scheduled for Q1 of 2012.
Y.App is the big thing. What it provides is... You can think of Y.App as a View and navigation
manager, but also a place for you to really start hanging your application off of. It's
a really great starting point. It's a high level component for you to be able to start
building these rich UI applications.
I just wanted to start off with a super basic example application. Imagine this is a user's
app. Similar to Router, you can instantiate Y.App or you can subclass it. You will probably
end up subclassing it for anything that's not trivial. The one thing that it does here
is it allows you to declare your main application views of your application. You could think
of these as like the different pages. The first one is this user's View. In this application
we would have a list of users on one page and you could click on a user and then see
the detail of a particular user and be able to go back and forth between those, all doing
this on the client.
In this case we're specifying a type which is our user's View subclass, and we're telling
it to preserve any View instance it creates for this user's View. You can imagine if we
have 100 users we don't necessarily need to rerender the DOM for that every single time.
This is one option where you can specify to preserve a View or not. Then we have this
user View. This is used to render details of a particular user, say. But we can specify
a hierarchical relationship between these two by saying that the parent for the user
View is the user's View. This way we can do nice sliding transitions between these things.
Then to look at the code here, the most basic thing you could do with this. Imagine at the
top here I have a new user's list, which is a ModelList of my user data. Imagine that's
filled out. I can use the same routing stuff that you just saw on Router. I can say that
I want to route /users/ to this handler here, and for this handler I want to show the user's
View. What I want to do is pass to that View my list of users so it can render it out.
Or if it's already rendered just redisplay it or transition to it.
Then one that's a little more interesting is the user View. Here again I have this placeholder
for the id. I can go ahead and look at my user's collection, and I want to get the specific
user Model instance out of it. ModelLists have this method on them, getById, and the
id is on the request parameter's object. Now I have a reference to my user Model instance.
Then I can say show View, the user View, and this doesn't preserve the View instance so
it'll create it new every time. In this case I want to pass it the Model of the user that
I would like it to render, and then I can be called back after, say, the transition
has completed if you're doing sliding transitions or something, to do anything else that I may
need to do.
This is like the most basic type of application you can do. This is all around managing your
Views and the life cycle of these Views: dealing with instantiating them, transitioning them.
But then there's a little bit more that it does too.
Baked into Y.App is this idea of enhanced navigation. What I mean here is... We've all
seen this on GitHub. They have this really nice source tree browser. The URL, if you
watch up there, is actually updating. It's the full path; it's not just a hash fragment.
They're transitioning in this content. It's really nice, it's fast. The back button still
works, and it's switching the URL. This is just like a nice enhanced experience. GitHub
wrote this correctly, because if I just go up to my URL bar and refresh the page or send
somebody a link to that, the server will handle that request and render the entire page, where
here it's just going off and fetching a little snippet of content and showing it and transitioning
to it.
The GitHub developers actually named this technique. It's called Pjax, which is pushState,
meaning the HTML5 pushState history API to update the full URL, plus Ajax, where by Ajax
they're meaning dynamically loading and rendering content.
How it works is basically you're handling a link click and then you can, instead of
letting that click bubble up to the window object and then having the browser go and
send the request for that URL to the server, you can prevent that from happening. Instead
you call into the history pushState API to update the full URL, and then go and fetch
your content, maybe say over XHR to grab the little snippet of content that you want to
show in. That's the basic idea.
The one thing we realized, though, is that the Ajax part of pushState does not necessarily
mean just XHR. You may already have the data sitting in the client, like in a Y.App instance
or something, and you may not need to go to the server to do it. But this idea of dynamically
rendering the content is the important part.
Of course, it maintains the browser forward and back buttons. It's really like a seamless
upgrade. IE browsers just get a full page refresh, but any newer browser gets this nice
enhanced experience.
We actually created a Y.Pjax module. It's not necessarily under the App Framework set
of components, but it's used by them. PjaxBase is an extension that is meant to be mixed
in with Router subclasses, and PjaxBase handles the link click events. What it will do is
it will look to see does the Router have a route for this URL? Can the Router service
this request, or does it have to go off to the server? That's what PjaxBase's main functionality
is. But then we mixed these things together and created a Y.Pjax as well, and this is
an instantiable class.
There's also a Y.Node plugin, as well, to make it even simpler to use. But the basics
here are it's just doing a convention. It's using PjaxBase, it's mixing it into Router,
but it just has a specific convention that it's using which is that the Pjax has a route
for star, so that matches everything. What it says is that all link clicks will then
go to the Pjax class's navigative method. What that will do is update the URL, make
an XHR request to the server using that URL adding additional headers so that the server
knows that it's a Pjax request, and then the server can respond with giving, say, a rendered
snippet of the page or data or something back. Then it will automatically go and set that
content into some container in the DOM.
I just want to recap what Y.App is. It actually is built up using a View. It mixes in View,
Router, and PjaxBase together into one class. It gives you your containment and rendering
of View. It has the URL handling of Router, and it has this enhanced navigation that Pjax
adds. But it also has this idea of an active View; like which page am I currently looking
at. It deals with actively managing the life cycle of those page Views and transitioning
between them. You can instantiate it, subclass it.
One of the other things we've been thinking about and working with in YUI for 3.5 -- and
this also has a really big use with the App Framework, you would use this a lot -- is
templating. YUI has this string substitution templating, but we wanted to go a step further
and we've adopted Mustache-based templating for YUI. Specifically we're going with Handlebars
here. Dav mentioned this in the opening keynote. I just wanted to go over a couple of details
about this and show why it's cool and interesting.
Here's a very basic Handlebars template. This is using a script element with a more-or-less
fake MIME type here, so that the browser will not interpret this as JavaScript. It's more
of just a placeholder to put content that is not code. But it has an id, which is important,
so that we can reference it later. In this template, say this is just some entry like
a blog entry or something, we have a title. It has these very basic conditionals and looping,
which are nice. If there's an author for this blog entry it will just go ahead and show
the author, and also print out the body. Then working with this from the JavaScript side,
we've made Handlebars a first class YUI module. This way you can say use('handlebars'). In
this case we're using handlebars and node-base.
What we can do with that template on the previous slide, we can reference it by ID, it will
just give us a string back, and then Handlebars has this ability to compile a string template
into a function which you can use to pass data into. It will render the placeholders;
put the data in the placeholders. We're creating this render function here, and then we have
this entry which we can then go ahead and render into some container.
This is very useful when you're developing applications to be able to have something
like this. But one of the other things we're thinking about and working on is making sure
that YUI runs really well on the server, and particularly on Node.js. Handlebars also runs
in a Node.js environment, which is really nice because we want template sharing between
your client code and your server code. You don't want to have to write your templates
twice or in two different languages, so this is a big thing here.
Also we want to make sure that Models can be shared across the client and the server,
that the Router or the app can be shared between the client and the server. We're just trying
to get as much code sharing as possible. With YUI and Node being a first class environment
for YUI, we're definitely thinking about all these things and working on making sure that
there's as much code sharing as possible between the client and server side of your applications.
The other thing we're doing is we're working on guides to help show how you can use these
tools, how you can use the App Framework components, to actually go through and look at how we
envision applications being built using responsive design techniques, working well on mobile
devices, code sharing with the server. We're also going to be developing these types of
guides to help people get started and see our vision of how applications can be built
with this stuff.
Now I have a little demo app which is actually using the App Framework and even the new stuff
I've been talking about. You guys can feel free to load this up on your phones. I've
only ever tested it on the iPhone and iPad, but I know it definitely works on there, so
go ahead and launch this up. If you have an issue, this is using geolocation so you may
need to enable Safari on your iOS device to allow location. I'll go ahead and look at
it too.
All right. The whole point of the app is just to find interesting photos near your current
location. This stuff really found some interesting ones. What happens is the app starts, it figures
out your location, and it actually updates the URL up here to be the location so that
you could send this off to somebody else. For example I have one from Boston near where
I live, so I can just refresh this page and it has all the photos near Boston. It's nice
there are these permalinks for these photos.
If we look around here we can see this list of photos here. It kind of does an infinite
scrolling thing, so it'll load more. This is using YQL and Flickr. All of the Model
and Models that I have are backed with YQL. I'm not sure why that's not loading. But I
can go ahead and look at some of these photos if the internet works. There we go. This shows
the large version of it. It updated the URL to include /photo/photoID. It's nice. You
can use the arrow key to go between them and that sort of thing. I can come up here and
just refresh this page, and it should reload the state as long as the internet's fast enough
from where I was before. Imagine it worked.
Is it working for people?
>> AUDIENCE MEMBER: The internet's slow.
>> ERIC FERRAIUOLO: It's slow, yeah. This is a full client side app; I didn't bother
to really build a server. The server's a very simple Express server running in Node that
just says return the same page for every URL and let the client app render everything.
Like I was saying, this was built using the components of the App Framework, all of them,
including Y.App. It's using the enhanced navigation stuff using Pjax. When you're clicking on
a photo it's updating the URL but not doing the full page refresh, and letting the app
handle that by showing the photo's details. It took about 650 lines of JavaScript that
I wrote specific for it. It has a nice responsive design; the same thing I was showing on my
browser is the same code that's running on your phones, and it adapts to the screen size
real estate.
I actually have all this code up on my GitHub account too. It's too much to go into, but
you guys should all check it out because I think it's a really great example of the power
of things you can do with the App Framework. It's not too much code where it'd be hard
to get through; it's a nice size application I think.
Just to show the breakdown, the app's basically taking over the full page here. Then we have
a place Model which is dealing with rendering; in this case it was Sunnyvale California.
Then we also have this ModelList for the photos, and then each of the photos is a Model as
well. That's the breakdown of the Models here. Then this particular View is what I called
the GridView, and it shows just the thumbnails and deals with when you get to the end of
the page, requesting more photos or asking the app to get more photos for it.
Then when you're looking at a photo, again, the app's the full page. You still have the
place Model here, but now you're looking at the photo Model and using this lightbox View
to look at more details and a larger version of this photo.
We're definitely seeing a lot of potential of things we can do with the App Framework.
Looking further out, now, some of the stuff we're thinking about is how to better deal
with data access -- things like sync layers -- or deal with data binding. These are all
things that we're looking at. Also just expanding our reach on the server, making sure there's
as much code sharing as possible, making sure that there's some infrastructure stuff in
place like app provides to make it easier to develop single page mobile apps. Also we're
looking at having people contribute View extensions or plugins. Model and View and App are all
Base-based classes, so they have the whole extension and plugin architecture that they
can use.
We just are really thinking that the App Framework is meeting people closer to where their problem
space is. It's coming up to meet them. They have this problem, they're coming up with
a solution, they want to implement it, and we want to be right there with the App Framework
saying OK, you don't have to worry about these infrastructural details. This code will be
there to help you structure your application, help your organize your code, help you do
some of this boilerplate stuff with managing Views and navigation and that sort of thing.
We're excited about the potential of where this could go.
With that, I'm happy to take any questions that anyone has.
>> AUDIENCE MEMBER: Do you have any plans to somehow enable to use the Model and ModelList
components somehow with the DataSource?
>> ERIC FERRAIUOLO: Yeah, the question was: do we have plans to couple Model and ModelList
with the DataSource. I've actually been thinking about that exact thing, and I think that's
the right type of solution. That's some of the stuff we'll be looking at definitely in
3.6, to yes, use DataSource because it has this abstraction over where the data's coming
from, and it would fit in perfectly with the sync layer of Model and ModelList. So definitely
that seems to be something that makes sense.
>> AUDIENCE MEMBER: Yeah, obviously DataSource is a great tool to put data inside of the
DataTable, and DataTable is a great tool for a lot of things.
>> ERIC FERRAIUOLO: Yeah, yeah. DataTable and DataSource... Actually, Luke is going
to be looking at trying to use some of these, Model, ModelList and View to help implement
DataTables into such a complex widget. We're definitely looking at that as well.
Yes?
>> AUDIENCE MEMBER: With the new Y.App, you have all these Views coming in and potentially
not all of them are being used right away or whatever. Is there any integration with
Loader to say put off loading some of that code that's going to render those Views until
the user clicked and went into one of them?
>> ERIC FERRAIUOLO: The question was: if your application has a lot of Views, the Views
may be containing widgets and stuff which is a lot of code that you may not want to
front load. That's a great question.
What you can do is you can use the routing infrastructure within Y.App to basically use
a Y.use() call, load in the code you need and then once all that code's ready you can
call showView on your application, and then show that View because all of its code is
there. I think that we're probably going to leave it up to the implementer to use Y.Use
instead of trying to re-implement some of those parts of Loader. That'll definitely
be something that we should probably show in the guides so that people see that type
of pattern.
Yes?
>> AUDIENCE MEMBER: In relation to Model [inaudible] from making changes in ModelList and then
making changes inside of the Model, do you use any kind of event management if you're
changing many things within a very short period of time to manage the number of calls?
>> ERIC FERRAIUOLO: Yeah, the question is if there's a lot of changes to the Model's
data attributes over a short period of time, is there anything that we're doing to manage
the number of events fired, probably because you don't want to re-render the DOM one hundred
times?
We don't have that type of throttling or transaction based stuff built in per se, but what there
is is the Model's coalescing of change events. If you call setAttrs(), which you can pass
in a hash of key values and multiple attributes to update, that will only cause one change
event to fire. But it's definitely something that we're looking at because there's some
more complex things you could do like a transaction where you start it, you do a bunch of changes,
you end it, and then have the changes be rendered. That's something that we're looking at. There
isn't anything in there right now, but it would definitely be great to hear more thoughts
on that type of thing, what you think would work well.
In the back?
>> AUDIENCE MEMBER: Are you planning on integrating or adapting Mojito so that the Router can
use the same routing mechanism? Personally I prefer this routing over Mojito's routing.
>> ERIC FERRAIUOLO: The question is: are there any plans to share some of the code with Mojito
and also, in particular, the routing? Just to talk about the routing, the way that it
behaves is very similar to Express. That's what we looked at as a good way to do routing.
I believe that Mojito also uses Express. I think that there definitely can be some sharing
in there, and we would probably like both projects to figure out and settle on something
that's similar, but I don't know if there are any plans right now on that. But I think
it's a good idea.
>> AUDIENCE MEMBER: So do I.
>> ERIC FERRAIUOLO: Matt?
>> MATT TAYLOR: The pages are going to have a long lifecycle when you're using an App
Framework like this. I'm wondering if the instances of these objects that you're creating
have events or methods that get called so that they can clean up after themselves as
they're being destroyed or something to prevent leakage?
>> ERIC FERRAIUOLO: The question is around when you have a long running app you're creating
a lot of objects, and there could be a lot of memory usage or leakage. How do you clean
up after yourself? One of the things that is part of the View management for Y.App is
dealing with the life cycle of use, destroying them and creating them. I mean it's definitely
something we're conscious about because mobile devices, with their constraints eating up
a lot of memory, would be a bad thing.
I think what we would try to do is make sure that we're doing things right in the app framework
infrastructure to kind of clean things up where it's appropriate so that application
developers don't have to worry about destroying Views as they're showing new ones and stuff.
Like in the photo example, as you're arrowing through or going through the large views of
each photo, it's creating a new View instance and destroying the old one, and it's showing
the new one, destroying the old one. It's also detaching it from the application in
terms of not having its events bubble to the application anymore, and tries to break those
types of relationships.
Other questions?
>> AUDIENCE MEMBER: Is it typical to have one Y.App for a document, or many?
>> ERIC FERRAIUOLO: The question is is it typical to have one Y.App per document or
many? I think that the best answer is to say you could go either way. Y.App defaults for
its container to be the body of the page, but we've definitely been thinking about the
idea of having multiple applications on the page at the same time. With the current code
on GitHub, Router, which is the infrastructure that's dealing with the URL changes, you can
have multiple Routers on the page. If they have route handlers for that URL they will
respond to it. The thought is that you could do one app that takes over the whole page
or you could do an app that takes over part of the page, or have multiple applications.
That's definitely something that we want to make sure it does well.
>> AUDIENCE MEMBER: One question. You did mention this, that the Router in a lot of
ways it's all about routing but it's also a lot of the stuff you would normally think
about the Controller. Like you just mentioned, when you're having separate totally different
Routers that are handling different parts of the app perhaps on the same URL, on the
same route, but in different parts of the application doing separate things that might
be modular.
>> ERIC FERRAIUOLO: What is it that you're asking, then? Sorry.
>> AUDIENCE MEMBER: I guess I'm saying that the intent with the Router is that it's more
Router focused, but the idea is that you could also use Controller or handle things you typically
think of going in the Controller.
>> ERIC FERRAIUOLO: Yeah. The question is the Router is kind of doing some of the stuff
you would think of Controller doing, especially in a server side MVC framework. What about
modularizing your application, where does some of this more Controller-like code go?
I think it could go in the App or on the View. It kind of depends. Our Views are these Base-based
classes, so they're rich in the sense of what they could do. You can subclass it, add attributes
to it, do all this stuff. If it makes sense for some of your logic to go there, that's
fine. There's no hard and fast rule there. But I tend to keep it in the App.
The Router has this idea of a next route, so you could have the first route say... In
the photos app when you're looking at the details of a photo, I have two routes that
handle that URL. The first one goes ahead and pulls out the photo Model, does some stuff
with it, loads the large image in the background to make sure it's ready, and then it calls
next(). The next route in that chain, its only job is to just now take the photo which
has been added to the request object from the previous route and go ahead and call showView()
and pass it into the View. That helps break apart the logical parts of your code that
way. That facility helps a lot.
But yeah, that's where all these MVC frameworks... Depending on what you're doing it blurs the
line between Controller-ish code and where it should live. I hope with the guides that
it helps provide people with at least some ways that it could work out and we would definitely
be excited to see if people come up with better ways, too, about structuring code.
Other questions? No? All right, well I'll be around so just come and get me if you want
to talk more about this. Thanks.
[applause]