YUI3 App Framework Writeup
I’m writing this as a living guide of my own understandings. It is in no way meant to be authoritative.
YUI 3.4 is introducing an application framework. This is similar to what you would see with Backbone.js and others, except in the YUI way. I believe in the YUI way for a variety of reasons, mostly because the component management. The YUI3 app framework continues that top-level care of components.
Core Concepts
The core concept itself is MVC. There is a controller that handles dispatching user actions to the necessary places. Multiple views handle what the user sees and the events relating to those. Models handle the actual data (fetching from remote sources, etc.
Views
A view is a representation of a model type (or model list, read more). My understanding is that a view will generate the markup and instantiate any widgets.
Most importantly, the view is responsible for catching any events in its own markup (such as a link click) and emitting a modified event with the constraints.
The example is that clicking a link would be caught by the view, which then looks up which link was clicked and emits an event with that specific model.
In the photosnearme.com example, the GridView catches all click
events on photos and then fires a select
event. The controller subscribes to gridView:select
and when that event fires the controller loads the URL /photo/{id}/
. This in turn causes a new request that is dispatched.
Controllers
A controller is the application. It establishes the routes and handles dispatching. This essentially means /some/url
to some function in the controller. It’s quite simple.
Primarily what it does is subscribes to the individual events and then dispatches or acts upon those events.
Models
Models are the interaction with the data itself. Not really user interaction, but application interaction. Because no application consists of a single, atomic object but instead is several “sets” of models, YUI3 has ModelList as a separate entity. This is similar to NodeList vs. Node when looking at the DOM.
ModelList
A model list is simply a collection of models. The plurality, with methods to make it easier to iterate over them.
Again looking at the photosnear.me example, this is a query of all photos on a place. You tell a model list what it is comprised of (the model
property) and how to fetch the data.
Model
A Model is the actual stored data object. This should be what is saved. A model should have some unique identifier associated with it.
The Model is very easy to understand, I thik. It’s just a structured chunk of data that can be saved.
Model vs. ModelList
After developing more, I encountered confusion between what is a Model and what is a ModelList. In the example application I was working on, I had Projects with Tasks.
That immediately left me with the following:
- ProjectList, a ModelList with
model: Project
- Project, a model containing not much more than a name.
- TaskList, a list of tasks, bound by Project
- Task, a simple task model. Name and status.
I then started thinking about a common design decision with Document databases. Should I embed the TaskList as an attribute of the Project? Should it be standalone?
Lets run through each scenario.
A Model with a ModelList Attribute
If my Project
model has an attribute tasks
, which is a ModelList I must at inflation and deflation (as part of the sync) know this.
It ends up being saved, in JSON, as something like this:
{
name: "My Project",
tasks: [
{ name: "Task 1", status: 0 },
{ name: "Task 2", status: 1 }
]
}
When I fetch tasks from the storage sync, I need it to know to turn tasks into inflated Task
objects. Additionally, the Task object needs to know what project it belongs to (but we don’t want to save that field).
This quickly ends up with a series of difficult design choices. These are fairly common when working with document databases. It’s solvable, but there are some nuances.
Also, depending upon how the data is stored behind the scenes it can be difficult (or expensive) to store if the only difference is one task out of many.
A Model with a method for fetching a subordinate ModelList
What this method really means is that my Project
model is actually a model and a ModelList. Aside from this blurred distinction of traits, there isn’t any problem with this from a design perspective.
This doesn’t change the option of storing the Tasks embedded or linked. I believe it does simplify the fetching of the Tasks as far as inflation goes. The code is simpler.
The data store can have better handling done when fetching a stored ModelList versus a Model. However, I don’t believe the intention was that a ModelList would ever be stored in the database. It’s a container that is to live in-memory.
Again, this isn’t an actual problem. It makes the code cleaner to have a ModelList and a Model live together as the same object. It’s also the time where I wish that JavaScript had a really good MOP, similar to Moose.
On both choices, the problem of whether to store via reference or embedded continues to pop up.
Embedding Models in a Model
The general decision I make as to whether to store an embedded record set versus store references is not just how big is the embedded set, but whether I will want to query it.
If I can reasonly say, “I will want the status of tasks that meet a criteria without the container” I will store references.
In the case of Tasks and Projects, I think that’s the same. If I have 3 projects and a task named “Development” in each, I could want to find the status of each Development task and deliver that summary.
As such, in this example, I think it is best to store references and then I can have a separate ModelList for fetching Tasks without even taking into consideration the Project above it.
But then how does a Project get a list of Tasks assigned? Well, that’s more difficult to answer, but here is what I’ve come up with:
Using Model Events to Establish Views
In the example above, the Project model itself rarely (if ever) needs to know what tasks are under it. It’s a separate container mechanism that simply acts as a search filter.
In an application, selecting a Project can emit an event that the controller handles and redispatches to a view that just handles rendering TaskLists. Then, the view receives the event notification and fetches the TaskList that is related to that project.
This way I can even use the same TaskList view for any arbitrary search that may or may not be related to a Project.
I think this is the best way forward, as it makes my TaskList view more general purpose as it only accepts search criteria. My Project is a very simple model that is separate to anything else. The ProjectList view just handles selecting a project, emitting an event with that project and the controller handles dispatching.
Subsequently, when a task is selected in the TaskList view, this same design pattern is carried on. The controller accepts a selected task event and routes to the appropriate detail panel.
A Conclusion
The YUI3 App Framework is making me think about applications in a more desktop-y fashion. I appreciate this as I got my start working on desktop applications, and have been doing web-based development for a solid 10 years now.
This feels like a natural merge of the two worlds in such a way that good software is easier to write than bad software.
I judge tools based on the ease at which one can write bad software. If it’s easier to write things poorly, I do not like the tool. If it is equally challenging to write bad software as good software, it’s a good tool.
YUI3 App Framework is a great tool. It seems to actively dissuade me from making poor design choices and the final result is significantly better.
I hope to actually release something in production that is using it, more than simply throw away exercises.