Common Closure, Not RSI! Common Closure, Not RSI!
Some time last year I started getting really annoyed. Every time I picked up a new app, I had to open at least three rather busy folders to grok what was going on. Maybe you’ve heard of them:
Models, Views and Controllers
Yeah, I get it, it’s the de-facto layout for most apps. I’m all for consistency for the sake of simplicity. It’s a grand plan.
But my eyes and keyboard are tired of jumping around to find out what the Home page is up to. Last time I checked, those things that change together, stay together1 2. I don’t recall the “Those things that look like controllers stay together” principle. Not even a smidge of alliteration.
I’m glad to see I’m not alone. Feature frameworks are slowly popping up for Rails mostly, but I suspect ASP.Net won’t be too far behind. Uncle Bob also seems to have a rant going on the topic as well. You can watch one of his talks on the topic here. Good stuff all around.
My Change to get Feature Focused
In December of 2011, when I picked up a new project I decided to try something new. Features that made the app useful were going to highlight the app structure. Instead of folders called Models, Views and Controllers, the first thing you’d see is Chat, Tasking, and Notifications. Want to add some information to the Chat notifications… guess where you go? Yup… Chat.
Now most js frameworks don’t subscribe to the Model, View, Controller discovery convention like server frameworks. Instead, they’re mounds of scripts crumpled into some scripts directory. Not the framework’s fault, but again, not exactly organized with discipline.
Here are the weapons I chose to go into battle:
Provides dependency definition and resolution. Not crucial for the code, but it made optimizing a loosely coupled JS app into Sweet Apple Pie™.
‘cause sammyjs had a personality disorder.
Model Binding for realz. Backbone.Modelbinding just wasn’t there yet. I felt like I built a lot of Backbone by the end, but the knockoutjs’ binding is butter.
Our app is all client side; single DOM. Should you do your app that way… dunno. For this one, I had index.htm and was done.
The only thing of interest is that we’re sourcing require.js and we’ve specified the data-main attribute with a value of bootstrap. This refers to bootstrap.js which is going to get things rolling.
As you can see on the left, the client app is in a src directory under my app’s root of featurefocusedjsapp.
Dilemma: I really want to experiment with hosting the server components along side corresponding client components where appropriate. If you have ideas or experiences here, share them in the comments.
Bootstrap.js Feature Modules
bootstrap.js uses the require.js require function to create a module. require takes two things, an array of dependency module names and a function to be executed once all dependencies are available.
The purpose of bootstrap.js is to kick off the modules of our application. In many common frameworks, you might start by declaring routes using Sammy, Ember, or Backbone. We might need that, but I really want to start features. And that’s where modules come in.
Since our app is so awesome, people will want to know a little about the creators. Let’s give them some credit. We’ll start by creating a CreditsModule.js in the Credits feature directory. Bootstrap will simply call start on our module.
Instead, I want the creditsview.htm to sit alongside the rest of the credits module. We want to show this in the main content region of the app, but I don’t want my module coupled to some css selector or jQuery. So let’s see how we can put this all together:
Here we use the text.js plugin for requirejs. This sources the creditsview.htm content, sending the raw string as a parameter to the callback. We use this view content as a closure in the start function which is, again, exposed as a module using the reveal module pattern.
Check out our awesomeness
I’m running this using python –m http.server from the src directory. This is so convenient I created a serverpy function in my Powershell profile.
As you might imagine, this isn’t doing great things for our site resource performance. Lots of little files are bad for a browser. Our crazy simple site is bad.
Remember how I said requirejs wasn’t crucial. Everything we’ve done so far could pretty easily have been done by hand. Here is were requirejs begins to pull it’s weight.
r.js to the rescue
r.js also by James Burke is here to slim things down with it’s optimizer option. This is going to take our collection of scripts and templates and turn it into a single script resource.
node r.js –o build.js
Running that command in the root of the repo will show us this:
r.js has just walked the dependency tree of bootstrap.js and consolidated it into a directory called build in the repo root.
At first glance this seems wholly unimpressive
until you open bootstrap.js…
Delete all that working garbage and serve up the build directory.
What do our downloads look like now?
You can find the code to this point at https://github.com/cromwellryan/featurefocusedjs
Next time I’ll talk about features talking to one another. Then we’ll talk testing pieces of this thing.