Making sense of dojo.when: A simple XHR caching example

Right before Dojo 1.5 came out, the Sitepen blog had a great post about the improvements 1.5 would bring for dojo.Deferred. The part that really caught my eye was dojo.when, a method that lets you pass a value to a function whether that value is available now or as the result of some asynchronous operation. Either way, you get a “promise” that when the value is available, the function you provided will run.

This is one of those things that was super-neat when I read about it, but it took me a while to incorporate it into my code — it’s only in the last couple of weeks that I’ve had that wonderful moment when I’ve said “oh, I could totally use dojo.when for that!” Moments like these make me very happy.

It’s pretty common that an application makes an Ajax request for some data, and then caches that data so the request won’t have to happen again; the pattern might look something like this:

var myCache = {};

function getSomeStuff(stuffId) {
  if (myCache[stuffId]) {
    handleResponse(myCache[stuffId]);
    return;
  }

  dojo.xhrGet({
    url : 'foo.php',
    content : { id : stuffId },
    load : function(response) {
      myCache[stuffId] = response;
      handleResponse(response);
    }
  });
}

Here we have a function that takes an ID; the function looks in the cache to see if there’s a value stored for the ID, and if so, it passes the stored value to a handleResponse function. If not, it does an XHR to get the data; when the XHR succeeds, it stores the data in the cache and, again, passes the value to the handleResponse function.

There’s nothing strictly wrong with this, but I discovered that some neat abstraction opportunities became more clear when I switched to using dojo.when instead:

var myCache = {};

function getSomeStuff(stuffId) {
  dojo.when(
    myCache[stuffId] || dojo.xhrGet({
      url : 'foo.php',
      content : { id : stuffId },
      load : function(response) {
        myCache[stuffId] = response;
      }
    }),
    handleResponse
  );
}

Now we’re telling our getSomeStuff function to look for a cached value; if it finds one, dojo.when will immediately pass that value to the handleResponse function. If it doesn’t find one, it will run the XHR, and dojo.when will magically pass the XHR’s response to the handleResponse function instead. This is hot.

This works because dojo.xhrGet returns a “promise” object with a then method. dojo.when looks to see whether it got a promise object as its first argument; if so, it uses the then method of the promise object to attach the callback provided as the second argument to dojo.when. If not, it simply calls the callback immediately on the first argument. The real magic is actually in dojo.Deferred, not in dojo.when itself. Since all of Dojo’s XHR methods return a dojo.Deferred promise, dojo.when will “just work.”

I found that I was going through my application and ripping out instances of the old code, replacing it with the new. And then I had that “oh sh*t I’m copying and pasting, aren’t I …” moment, and saw my way to an abstraction.

In my application, I was actually caching the responses using the URL from which I’d requested them, which works out to be a perfectly unique ID for the data. (This particular part may or may not work in your application.) My abstraction was an essentially drop-in replacement for dojo.xhrGet calls:

var cache = {};

function cacheableXhrGet(settings) {
  var url = settings.url,
      req = cache[url] || 
            dojo.xhrGet(dojo.mixin({
              // override the load handler
              load : function(resp) {
                cache[url] = resp;
              }
            }, settings));

  dojo.when(req, settings.load);
  return req;
}

I can pass a settings object to cacheableXhrGet that looks exactly like the object I’d pass to dojo.xhrGet, but replace the load function before actually passing it to dojo.xhrGet. But before the XHR even has a chance to get set up, I check my cache for a stored response; if I find one, I store it in the req variable, but otherwise I store the XHR there.

In either case, the function defined at settings.load gets the proper response value via dojo.when. For bonus points, I then return either the cached value or the XHR — which means other code can use the return value of cacheableXhrGet for its own dojo.when. How neat is that?

Conclusion

Promises and deferred’s are a really pleasant tool to have in your JavaScript arsenal once you get the hang of them, and dojo.when seems like a great place to start understanding them.

Out of the box, Dojo makes use of deferreds for all of its XHR functionality, meaning that you can pass around the return value of any Dojo XHR method and do fun things you can’t do with jQuery’s $.ajax, like add more callbacks to a request after you’ve set it up.

I’ve just recently started realizing when I could incorporate dojo.Deferred functionality into my own code — again, now that I’ve got the hang of it, I’m pretty sure it’s going to dramatically change how I write asynchronous code.

Disclaimer: This post contains sample code for illustration purposes. In reality it’s all namespaced and these naked functions are actually methods in classes and stuff, and the real code doesn’t even look much like the code you see here. I’ve also completely ignored questions of when to clear or invalidate the cache. You’ve been warned.

Loading mentions Retweet

Filed under  //  deferreds   dojo   dojo.when   promises  
Comments (3)
Posted 3 days ago

Code Org, Take 2: Structuring JavaScript Applications

It’s hard to believe it was not even a year ago that I spoke at the jQuery Conference in Boston about code organization. At the time, I’d been thinking for a few months about how to improve my own code and give it more structure, and how to give advice to others about how to do the same.

My talk was about code organization, but really I was talking about how you might organize a single piece of functionality; I didn’t even begin to answer the larger question of how to structure a bona fide JavaScript application. Really, that question is almost perpendicular to the one I was tackling at the time; it’s a question of strategy, not tactics.

A year later, I’d like to share my thoughts on how I’m answering it these days.

First Things First: What’s a JavaScript Application?

GMail is a JavaScript application; this Posterous blog, while it makes use of JavaScript a bit, is probably not, but the admin interface most certainly is. The line can be frustratingly fuzzy, but at the same time it’s pretty important to realize when you’ve crossed it.

To me, the defining characteristic of a JavaScript application is that the heavy lifting of manipulating and displaying data falls to the browser, with most communication with the server happening via XHR.

If you find yourself in application land, welcome. Now what?

My Building Blocks

My approach to organizing an application is really just an MVC variant, so I don’t want to sound as though I’ve discovered something novel or new. However, there are a couple of things to note: For one, the term “controller” has a couple of different meanings to me, as explained below; for two, there are two distinct flavors of “views,” though I’m not sure exactly how important the distinction is.

I also want to be super-clear that I don’t tout this as The One and Only Way; it is just a way that has worked for me, a way that I evolve and adapt with every project I work on, and a way that I’ve run by a few people and they haven’t laughed at me. My point in dissecting it isn’t that you’ll try to follow it word-for-word; rather, I hope it might get you thinking about JavaScript applications beyond the DOM.

Models

There’s nothing particularly unique to models in a JavaScript application. They are responsible for fetching and storing application data and maintaining its integrity in the browser. They fetch data, store data, and provide an API for other application components to get access to that data. There may be more than one destination for the data: memory, the server, or some type of local storage. But if it has to do with managing data, it’s the model’s job.

Models stay out of the way when it comes to displaying data or responding (at least directly) to user interaction. Those tasks are left up to other pieces of the application, as we’ll see below.

Example

A simple search application would likely have a search results model, responsible for receiving the current search term, fetching the data for the term, and broadcasting it to the rest of the application. It might also allow for manipulating individual search results, such as indicating that a particular result was a favorite or a dud, though that task might also fall to an individual search result model depending on the needs.

Widgets and Data Views

Views comprise HTML (generally in the form of client-side templates) and CSS for a component, and are generally accompanied by a view controller (the JavaScript related to interacting with the vew; see below for an explanation). The HTML for a view consists of a single parent node with an arbitrary internal structure; the parent node will optionally have one or more classes on it that can be used to target CSS.

There are two flavors of views, in my mind: widgets, which are responsible for supporting user interaction with the application but don’t render any application data; and data views that are responsible for displaying and allowing interaction with application data.

Data views are instantiated with the initial data required to populate them; then, their view controllers listen for messages from other pieces of the application to tell them when new or updated data needs to be rendered.

Examples

A basic search input box would be considered a widget — when it is created, it doesn’t need any application data in order to render properly. The widget is strictly responsible for allowing the basic interaction of typing a search term and hitting enter; that is, it’s not responsible for actually performing the search.

A search results list is an example of a data view; it renders application data and, potentially, allows for interaction with it. Again, though, it’s not responsible for performing the search; it just renders data and then allows for interaction with it.

View Controllers

View controllers manage interaction with a data view or widget — interaction by the user, and interaction with the rest of the application. They are responsible for binding and handling events, for broadcasting user interactions with the widget to the rest of the application, and for listening to other pieces of the application to tell them they have new data to render.

View controllers never handle server communication directly; their role is solely to provide a user interface to the application. When something interesting happens to a view or widget, the view controller announces it. When new data is available for a view, the view controller should know how to handle it. But, again, the view controller itself should focus on providing a user interface, not on interfacing with the server.

Examples

The view controller for a search box might listen for the user to focus on the search box, hiding placeholder text for the input. Then, it might listen for the user to hit Enter inside the search box; when that happens, it would broadcast to the rest of the application that the user had submitted a search, along with the term that was searched.

The view controller for a search results list might listen for another piece of the application to announce that new search results are available to be displayed. If the results were for the currently displayed search term, it could add them to the list; if they were for a new term, the results list could empty itself and display the new results.

Application-Level Controllers

Application-level controllers are the glue of an application. Loosely, there may be one per “page” of the application, or one per feature. For example, an application that includes a search feature and a checkout feature might have a controller for each feature, even though the checkout feature might spread across multiple pages.

These controllers are responsible for getting the models and views/widgets for a feature in place and talking to each other. So, a controller might first make sure the required models are in place, then tell them to fetch the appropriate data; once the data is available, the controller would instantiate the views for displaying the data. Finally, the controller would broker future interactions between the views and the models.

Examples

On a search results page, a user might click a Favorite button on a search result. The search results list’s view controller would handle the click, broadcasting a message about the user’s action to the rest of the application. The controller would observe this message and pass it, along with any other relevant information, to the search results model, which would in turn pass the information to the server, or store it locally.

Notes on Enablers

I’ve glossed over a few implementation details that are somewhat tangential to the organization question, but I want to touch on them briefly:

Pubsub and Friends

I didn’t want to get too specific about how all of this “announcing” and “broadcasting” and “listening” happens, because there are lots of ways to accomplish it. One could use pubsub, custom events, or any number of other solutions. I don’t think the actual implementation is important, though personally I lean heavily on pubsub — what is important is the notion of broadcasting and listening for announcements that something has happened, allowing other components of the application to react appropriately.

Templating

If you aren’t using a toolkit with templating built in (or, heck, even if you are), I’ve kind of fallen in love with mustache.js lately. It’s a great client-side templating companion, making it dead-simple to turn data into markup without ending up with templates that look more like JavaScript than HTML.

Figuring out how to maintain templates can be tricky — do you store them in your page’s markup? Do you maintain them as separate files requested via XHR and then cached? Or do you put them in your JavaScript? Dojo’s dojo.cache() method provides a handy way to keep your templates in separate files and load them via XHR, while interning them into your JavaScript for you if you use Dojo’s build tool. I like this.

Attaching Events to Views

Another shameless Dojo plug: dijit.\_Templated provides some serious hotness when it comes to attaching events to views. Read up on dojoAttachPoint and dojoAttachEvent; together with dijit._Widget’s connect and subscribe methods, which provide automatic cleanup for you, there’s some real power here, which has me writing hardly any selector-based code these days.

File Structure

I hesitate to make any particular recommendations here, because the needs of an application can vary widely. However, I tend to have a directory each for models, views (for view controllers and templates), and controllers (for application-level controllers). Those directories — especially the views directory — may contain subdirectories, for instance if there’s more than one view for a certain type of data.

Why Go To All This Trouble, Again?

So this is the part where you might say “OMG, srsly, what happened to ‘get some elements, do something with them?!?’” Let me be clear, that approach may be entirely appropriate for your particular needs; I’m not here to convince you otherwise.

But: if your application is complex enough to warrant considering an approach like this, I’ve found that in the long run it actually simplifies my code by cleanly separating concerns and providing a decent roadmap for building new features. I can build and test a solid model for some Thinger, and then use that model throughout my code; I can build and test a user interface component for editing a Thinger long before the data exists to support it. I can map “pages” of my application to application-level controllers, providing a high-level view of what’s happening where.

Best of all, paths to code reuse become clear and entanglements become fewer when I keep this division of responsibilities in mind as I code. A search results data view, for example, can be made to accept search results from any model that provides them in the proper format; a search can be initiated and the results displayed without depending on a user entering text into a search input widget.

Dividing the responsibilities into well-defined sections leads to components that are truly pluggable, often in ways you may not have even imagined when you wrote them. In an application that evolves over time, it’s hard to overstate the benefits of this.

In Conclusion & A Plea

If you find yourself working on a JavaScript application, I can’t recommend enough that you consider, at length, what underlying structure makes the most sense; it’s almost inevitably more complex than you can manage via the DOM alone. Again, my answer isn’t the right answer, it’s just an answer, but I hope it helps you start thinking about what the right answer might be for your project.

If you’re interested in this stuff, I’d encourage you to check out JavaScriptMVC, if only to see how they approach these problems; Cujo.js is another framework, built on top of Dojo, that aims to enter this space, but you’ll have to wait until mid-September to see it.

Finally: If you have your own thoughts to share about how to approach these large application questions, I’m pleading with you to write your own blog post(s) about them. If you have other reference material on the topic, I beg you to share it. As more and more people transition from simple JavaScript enhancements to non-trivial applications, the need for education is huge.

Loading mentions Retweet

Filed under  //  javascript   large-applications  
Comments (6)
Posted 5 days ago

Dear conference organizer

Thank you for the invitation to speak at your conference, and your offer to pay my hotel and airfare in exchange. I notice that you are selling tickets for upwards of $1,500, in addition to hotel and travel costs. In exchange, you are hosting a three-day event, meals, a USB drive, a shirt, and a binder.

We need to talk, and not about the binder.

TXJS was a one-day conference with approximately a $30k budget -- some tickets cost a whopping $29, and the most expensive tickets were $109 -- and yet it managed to offer exactly what you're offering to me to its out-of-town speakers: hotel and travel. It had two nights of open-bar parties; a shuttle bus to get people to and from the amazing, eclectic, venue; catered breakfast and lunch; an open bar at the event itself; and a speaker and VIP brunch the following day. It also had some of the best JavaScript minds in the business on stage and in the audience, drawing people from around the country and beyond. 

I hope you can appreciate the disconnect here. It's not so much that I want to get paid -- I have gladly and eagerly spoken at lower-cost conferences without even getting my hotel compensated -- as the fact that I know now that conferences just don't have to cost that much. When they do, it's hard to get on board with lending my name for free when the conference stands to have revenue of hundreds of thousands of dollars and I know I only needed revenue tens of thousands to put on an amazing event. 

As a self-employed consultant, speaking at a conference has, at best, intangible benefit to me, and non-trivial costs. You and many other organizers can seem as though you assume the benefit is obvious, and the costs negligible. In fact agreeing to a speaking engagement -- one that requires two non-working days for travel, a non-working day for speaking, and whatever prep time is required to actually put together my talk -- is a tough decision regardless of how much tickets cost, especially for someone without corporate backing or a product to promote. Call me selfish, but I need to be very clear that there's a benefit to me. A high-dollar conference likely to attract almost exclusively corporate-backed attendees with at best a peripheral relationship to my area of expertise is exactly the kind of conference where it's not clear what the benefit will be. Being away from home and work for three days, even in a nice hotel, just doesn't count. 

--

Finally: To all of the TXJS speakers, we heart you unbelievably and stand in awe that when we asked you to present at an event that had never existed before, each and every one of you said yes without batting an eye. I hope you know that we know that even with the open bar and the parties and the shuttle and the venue and all of it, we couldn't have had a conference without you. 

Loading mentions Retweet

Filed under  //  conferences  
Comments (8)
Posted 8 days ago

Scaffolding a Buildable Dojo Application

Note: I’ve created a GitHub repo that served as a sort of scratch pad for this article; you may want to clone it and follow along. If you do, though, please note that it does NOT include the Dojo downloads; you’ll need to download the files indicated in Step 1 and then place the extracted directories as indicated in Step 2 if you want any of the build stuff to work.

One of the most confusing things about using a toolkit like Dojo can be getting it set up properly to take advantage of all of its features, such as its package management system. Sure, you can use a CDN-hosted version of the toolkit, but one of the major reasons I like Dojo is because of the dependency management and build tools it offers, and it’s difficult to really take advantage of these when you’re only using the library from the CDN.

If you skip the build step, Dojo’s modular nature means you’ll end up downloading a whole lot of files, and making a whole lot of HTTP requests in the process. It’s fine for development and general messing around, or if your project just requires a few files, but for the kinds of projects where I think Dojo really shines, you’re going to want to do your own build.

My goal in this article is to show how I set up my files to make this easier. This is by no means the only way to do it, nor even necessarily a best way to do it — just one way to do it that you can hopefully follow along with to get you started.

Step 1: Getting Dojo

I like to download two different Dojo packages:

I generally don’t maintain these files in a project’s version control system, but I do document that downloading and extracting them is part of setting up a new development instance. Your exact strategy here may vary, but I do encourage at least the JavaScript developers on a project to have both on hand. The former will be used during development; the latter will be used for reference, and to perform the build step.

Step 2: Where Do I Put It?

For the sake of this article, let’s assume that all of your public, static files are served from a directory www/. Here’s how I might structure things from there:

  • www/
    • dojo-toolkit/ (extracted from toolkit release)
    • dojo-sdk/ (extracted from SDK release)
    • myApp/

Easy enough. Next, we need to point to Dojo in our HTML.

<script src="dojo-toolkit/dojo/dojo.js"></script>

At this point, we could start writing JavaScript that uses Dojo anywhere after that script tag, but that wouldn’t be very exciting, smart, or sustainable. Instead, let’s create an initial JavaScript file in our myApp/ directory, called base.js.

dojo.provide('myApp.base');

console.log('you found me!');

We could just include this file in our page using a script tag, but again, not very sustainable — next thing you know we’ll have 30 script tags in our page, and the whole point here was to take advantage of dependency management and building, right? We can tell Dojo to find and load our file for us, but first, we have to give Dojo a hint as to where to look.

Step 3: Pointing Dojo in the Right Direction

The one “rule” imposed upon you by using Dojo’s package system is a simple mapping of dot-notation strings to file locations. If you say dojo.require("a.b.c.d.e.f.g"), Dojo will go looking for a file at a/b/c/d/e/f/g.js. By default, Dojo assumes that the directory a/ is a sibling of the directory that contains dojo.js, but you can adjust the location of any namespace.

There are a few different ways to do this; my personal preference is to declare the global djConfig variable, but any of the ways mentioned at the link above is obviously valid. If you go the djConfig variable route, just be sure to declare the variable before you include dojo.js in your page if you want Dojo to pay attention to it.

Here’s what it would look like for our little app:

<script>
var djConfig = {
  modulePaths : {
    'myApp' : '../../myApp'
  }
};
</script>

What’s up with the ../../ stuff? As mentioned, Dojo by default assumes that any namespace, such as our myApp namespace, is a sibling of the dojo/ directory by default, just like dijit/ and dojox/ are. Problem is, our myApp/ directory doesn’t follow this convention. Namespace locations are specified relative to the location of dojo.js itself — in our case, dojo.js is located at dojo-toolkit/dojo/dojo.js, and so relative to that, our myApp/ directory is exactly where we said it was: at ../../myApp.

Why don’t we just make the myApp/ directory a sibling of the dojo/ directory, and skip this whole part? We could, but keeping it external to Dojo itself makes managing those Dojo downloads — especially within a version control system — a whole lot easier. This way, we can keep our application code entirely separate from Dojo, and add or remove or upgrade Dojo at will without having to worry about our application files. This makes me happy; if it doesn’t make you happy, feel free to put your application code wherever you’d like :)

Step 4: Hooking it Up

Now that Dojo knows where to find our stuff, we can tell it to start looking. We’ve already included Dojo on our page. Now, instead of adding more script tags to our HTML, we can start to take advantage of Dojo’s dependency management system:

<script>
dojo.require('myApp.base');
</script>

This is the only other script tag you’re going to need to add to your page; from here on out, everything can be managed inside the JavaScript itself.

Step 5: Writing Your App

This step is mostly up to you. Dojo provides great tools for building large applications — a solid base library with CSS-based node selection, inheritance, pubsub, effects, events, and various other hotness — and it also has a great UI toolkit in Dijit, including abstracted base UI functionality in dijit._Widget and dijit._Templated. It provides patterns, but no real prescriptions, so I can’t show you how to build a great Dojo app in three paragraphs or less.

However, let’s talk a bit more about this dependency management stuff, because by the end of this article, I want you to be able to leverage that dependency management stuff to create production-ready files, regardless of how you build your app.

So, we have our myApp/base.js file, and so far it contains this:

dojo.provide('myApp.base');

console.log('you found me!');

Let’s assume our app does more than log to the console:

dojo.provide('myApp.base');

// specify the file's dependencies
dojo.require('myApp.Settings');
dojo.require('myApp.Thinger');
dojo.require('myApp.Doohickey');

// run code when the dependencies are met
// and the DOM is ready
dojo.ready(function() {
  if (myApp.Settings.isThisThingOn) {
    new myApp.Thinger({ things : [ 'a', 'b', 'c' ]})
      .placeAt(dojo.body());
    new myApp.Doohickey({ awesome : true })
      .placeAt(dojo.body());
  }
});

Now we’ve said, in code, that our app requires three other pieces: Settings, Thinger, and Doohickey. Dojo looks at those dojo.require() statements, and decides that it’s going to try to fetch myApp/Settings.js, myApp/Thinger.js and myapp/Doohickey.js to satisfy those dependencies. Once it finds them, we can use them.

The details of our application here aren’t super-important (in fact they’re entirely made-up); what’s important is to understand that we’ve specified a dependency, and once it is met, some other code runs.

Chances are that some of our modules have some dependencies of their own. Let’s take a look at the make-believe contents of myApp/Thinger.js:

dojo.provide('myApp.Thinger');

dojo.require('dijit._Widget');
dojo.require('dijit._Templated');

dojo.declare('myApp.Thinger', [ dijit._Widget, dijit._Templated ], {
  // template for Thinger
  templateString : '<ul></ul>',

  // what to do after a new Thinger 
  // is on the page
  postCreate : function() {
    // create a new list item for each item in things
    dojo.forEach(this.things, function(thing) {
      dojo.place('<li>' + thing + '</li>', this.domNode, 'last');
    }, this);
  }
});

Why look! We’ve specified yet more dependencies while keeping our code modular and abstracting away common pieces of behavior. Nifty, eh? Meanwhile, our HTML still only has the single dojo.require() statement in it, because all of our dependencies are expressed in our code, where they belong.

Step 6: Build It

We’ve seen how to express these dependencies, but if you’ve been paying attention to Firebug or your development tool of choice, you’ve noticed there are still a ton of HTTP requests happening. What, exactly, have we gained here?

Remember how we downloaded that 19mb SDK? Besides the fact that it has uncompressed, commented versions of every single Dojo file, it also includes the build tool, and now we’re going to put it to use.

The commands for running a build are, sadly, not something I keep in my brain, so I like to make a tiny shell script in my application directory that looks like this:

cd ../dojo-sdk/util/buildscripts
./build.sh profileFile=../../../myApp/myApp.profile.js releaseDir=../../../release

Could this be prettier? Probably, but it does the trick. It puts us in the buildscripts directory, then runs the build.sh file that’s there with the provided arguments: the location of the profile file for the build, and the location we’d like the build to end up. Both of these locations are relative to the dojo-sdk/util/buildscripts/build.sh file, so keep that in mind if you decided you didn’t like how I organized my files and did something different.

Now all we have to do is create that profile file. You can look in dojo-sdk/util/buildscripts/profiles/ for some examples, but here’s a good start:

dependencies = {
  stripConsole : 'all',
  action : 'clean,release',
  optimize : 'shrinksafe',
  releaseName : 'myApp',
  localeList : 'en-us',

  layers: [
    {
      name: "../myApp/base.js",
      resourceName : "myApp.base",
      dependencies: [
        "myApp.base"
      ]
    }
  ],

  prefixes: [
    [ "dijit", "../dijit" ], 
    [ "dojox", "../dojox" ],
    [ "myApp", "../../myApp" ]
  ]
}

OK, seriously, what is up with these relative paths? I will tell you right now that the first time I saw this it was a complete mindf*ck, and the only way I can put together a build for a new project in 10 minutes or less is by referring to a profile file for an old project (which is part of the reason I’m writing this post). Let’s take a look at what’s going on here, though:

  • The dependencies object is the top level object describing the profile. Initially, you can set all of the command-line arguments here as members, e.g.: stripConsole to remove any console.* calls in code, a required action parameter, and so on. (Note that we could also specify the releaseDir argument here if we wanted; I tend to keep it in the shell script, but not for a particularly good reason.)
  • The layers array contains a list of all of the production-ready “layers” you want the build to create. In this case, we’re telling the build to create one layer that contains all of our application code (in a minute we’ll look at how to specify multiple layers for serious hotness).
    • The name property of each layer tells the build tool where the created layer should be placed relative to dojo.js in the destination directory.
    • The resourceName property tells the build tool how we plan to refer to this layer in our code. For the sake of this article, we’re going to refer to it in our code exactly how we’re already referring to it in our code.
    • The dependencies property is an array of modules that this layer depends on. In this case, the layer sort of depends on itself, causing the build to physically replace the original myApp/base.js file with the result of all the dependencies.
  • The prefixes array is sort of like the modulePaths specification in djConfig, which makes sense because the build tool can’t see the djConfig settings. It tells the build tool where it’s going to find files for a given namespace. Any namespace that you use in your code needs to be specified here. If you aren’t using any DojoX modules, feel free to omit the “dojox” prefix to avoid copying the unused code into your built tree.

So! Let’s cd into our myApp/ directory, where we’ve created our little build script and myApp.profile.js, and run that build script.

[ … about 30 seconds later … ]

Sweet. Now we have a release/ directory next to our myApp/ directory, and it looks like this:

  • release
    • myApp
      • dijit
      • dojo
      • dojox
      • myApp

We can see exactly what the build did by looking at release/myApp/dojo/build.txt — it shows that it created a dojo.js file for us, as well as the myApp/base.js file we asked it to create, complete with all of our dependencies.

Now, to use our built files, we need to do two things:

  • Remove our djConfig settings; they’re not necessary now that the built myApp/ is a sibling of the dojo/ directory.
  • Change the script tag in our HTML that includes dojo.js to point at release/myApp/dojo/dojo.js.

We can do this by hand, but once we have this working, we’d be smart to do it with some sort of switch in our application that decides whether we’re in development or production mode and outputs the right code accordingly.

Step 7: Building it Better

Imagine, if you will, that the myApp.Doohickey module is only needed on one page of your application, and that page is used rarely. Not only that, the module has a ton of dependencies that aren’t shared by any other modules, and it’s seriously stupid to be taking the time to load all that code when it’s unlikely it’s going to be needed. Our current profile file doesn’t make any allowances for this, but two adjustments can separate this functionality from the built files of the core application.

First, let’s give the directive in the profile file to build a separate layer for myApp.Doohickey. It won’t work without myApp.base, so we specify that as a layer dependency:

dependencies = {
  stripConsole : 'all',
  action : 'clean,release',
  optimize : 'shrinksafe',
  releaseName : 'myApp',
  localeList : 'en-us',

  layers: [
    {
      name: "../myApp/base.js",
      resourceName : "myApp.base",
      dependencies: [
        "myApp.base"
      ]
    },

    {
      name: "../myApp/Doohickey.js",
      resourceName : "myApp.Doohickey",
      dependencies : [
        "myApp.Doohickey"
      ],
      layerDependencies : [
        "../myApp/base.js"
      ]
    }
  ],

  prefixes: [
          [ "dijit", "../dijit" ], 
          [ "dojox", "../dojox" ],
          [ "myApp", "../../myApp" ]
  ]
}

Second, we need to make sure the build tool doesn’t see dojo.require('myApp.Doohickey') and decide it needs to include it in the base layer. This may seem a little weird, but the build tool basically just parses files to figure out which other files they require, and it does this by looking for dojo.require() statements. Hiding the Doohickey requirement from the build tool while keeping it in place for development is easy:

dojo.provide('myApp.base');

dojo.require('myApp.Settings');
dojo.require('myApp.Thinger');

dojo.addOnLoad(function() {
  new myApp.Thinger({ things : [ 'a', 'b', 'c' ]})
    .placeAt(dojo.body());
});

if (pageNeedsDoohickey) {
  dojo["require"]('myApp.Doohickey');
  dojo.addOnLoad(function() {
    new myApp.Doohickey({ awesome : true })
      .placeAt(dojo.body());
  });
}

Step 8

There is no step 8. There is step 1 through 7, which is way more than “put this script tag (and 20 others!) on your page and GO”, I’ll give you that. But take heart: not long ago, these steps had me pulling my hair out, and now I can write a blog post about them (with some much-appreciated review from Ken and Pete). I hope they help you understand the steps you’d take to start taking advantage of the power of Dojo’s package system, and I promise that once you’ve done it once or twice, it won’t seem like the roadblock it does at first, especially because the payoff in the long run is huge.

Further Reading

Loading mentions Retweet

Comments (3)
Posted 11 days ago

EnterpriseDojo.com uses jQuery!

And you should too ... for your WordPress blog that came with jQuery already installed and probably barely even needs JavaScript in the first place. 

Here's an idea: Let's have an honest discussion about when a given solution makes sense and when it doesn't, rather than mocking a contributor to that discussion for choosing a perfectly appropriate tool for a perfectly mundane task. EnterpriseDojo.com is a blog about using Dojo in the enterprise, not a blog about using Dojo on blogs. Snickering at its use of jQuery is approximately as useful as pointing to this graph and saying case closed, leaving more reasonable, thoughtful people to explain all the ways that graph doesn't tell us a damn thing

I want to be very clear, as the dust settles around my several recent rants: jQuery has its place, and it is a very, very big place. It is a lovely DOM, Ajax, and events library, and a great way to get certain things done quickly, especially for people who may not have the luxury of learning the inner workings of JavaScript (noble a goal as that is). There was a time when DOM and Ajax and events questions felt like the questions of the day, and jQuery showed us how to answer those questions using a simple, easy-to-learn API that suddenly made JavaScript accessible to the masses. Other libraries solved the same questions but those solutions felt ugly and clunky and goshdarnit, hard, and I give jQuery the utmost credit for making JavaScript suck so much less when all I wanted to do was show or hide or slide a thing or load some content onto my page. I'll even grant that it can be used as a piece of a large application solution, though I question the wisdom of doing so for reasons outlined in another post. Heck, I'll even grant that "enterprises" aren't off their rockers to use it -- for the things it was meant to be used for. 

What upsets me is when smart people seem to say that jQuery's victory in an internet-wide popularity contest suggests, well, anything at all when it comes to more complex needs. It upsets me because my clients hear those suggestions, look at that same well-marketed graph, and I am left explaining to them that, yes, jQuery is popular, but it's popular because it answers a small set of questions easily and well -- even for people who don't even know JavaScript! -- and you, dear client, have vastly larger questions than that.

At the end of the day, these toolkit decisions ought to be about more than a popularity contest; jQuery may be the right answer, or part of the right answer, but it's imperative, to me, that my clients understand the scope of the question first. It's imperative that they make their decisions based on a full understanding of pros and cons, risk and reward, cost and benefit -- not based on a graph, not based on a popularity contest.

So again I say: we, as a community, and especially the influential ones among us, do well when we elevate the conversation beyond that contest and acknowledge that choosing the right toolkit depends on first understanding what you're choosing the toolkit for. We do well when we educate teams and decisionmakers on the lessons we've learned in the time since DOM, Ajax, and events were the big question of the day, on the best practices that have emerged, on the situations where we've, gasp, had to look beyond jQuery -- either to other tools or other toolkits -- for the answers. And we do well when we start showing them how they can do the same.

An aside: Some people I like a lot have pointed out that in the midst of all of my complaining, I have not come out and offered a solution. This is fair. Two things: One, I have not wanted this conversation to collapse into Dojo vs. jQuery vs. YUI vs. Ext vs. MooTools vs. whatever, because if it does, I think we've missed the crux of the matter: that different tools do different things, that some set out to answer complex questions and some do not. If anyone has been unclear, which I rather doubt, my personal preference of late has been to use Dojo. I do not recommend using Dojo for everything under the sun, but I find it offers a lot of utility when writing non-trivial applications. I cannot make a compelling argument for using it vs. YUI, simply because I don't know YUI well enough. I can't even make a compelling argument for using it vs. Ext, except for licensing issues that may or may not be relevant in a given scenario. Two, if you're disappointed that I haven't offered a solution, especially a jQuery-based one, I apologize. However, I feel there are too many viable existing solutions out there already, and I haven't come up with a good reason to promote a jQuery-based solution besides jQuery's popularity. And, well, see above for my thoughts on that.

Loading mentions Retweet

Filed under  //  dojo   jquery   large-applications  
Comments (4)
Posted 12 days ago

2 Years In, Some Thoughts on Working for Yourself

Two years and three weeks ago, I lost my job. My partner and I had just had an expensive deck built; I’d just bought a gratuitously fancy grill to go on it. My token severance check was in the mail — I’d spend most of it to be able to keep my work computer. And so, six-pack of Yuengling and a pack of Parliament Lights in hand — I hadn’t smoked in years — I sat on said deck near said grill, contemplating a world I’d last contemplated when I, age 6 at the time, came home in the middle of the day to find my just-laid-off dad sitting on the porch.

It was not a good day.

Two years on, things look a lot better than they did. My “salary,” as best as I can figure it, is comfortable. Figuring it is hard: I travel to conferences whenever I want, and work pays for them. I buy new equipment and software when I want, and work pays for it. I don’t work a certain number of hours in a day or a week or a month, so I’ve been able to get my pilot’s license, spend two weeks in Hawaii without drawing on some meticulously calculated vacation balance, and take on projects like TXJS without having to get anyone’s blessing — hard to put a value on that. On the flip side, I’ve had more sleepless nights than I’d dare count, wondering where the money was going to come from next month, wondering whether it was time to walk away from an abusive client with no other work on the horizon, wondering whether my relationship could tolerate all the ups and downs, wondering how it was that little ol' me, the Independent Consultant, had any business telling people what to do.

People ask me, now and then, what advice I have for them about being independent, about working for myself. More than a few of them have suddenly found themselves sitting on that proverbial deck, waiting for that severance check (or not). I’ve written many an email, but I thought I’d take a few minutes to try to assemble all of them into a coherent post.

The Touchy-Feely

Network

Once I decided I was going to stop looking for a job and work for myself, I wrote an email to absolutely everyone I could think of who might help me find work. It felt weird, and it’s also exactly how I landed a job that paid the bills fairly solidly for the next nine months. When you decide to take the plunge, it’s imperative that you let people know. Let them know you’re looking for work, and what kind of work you’re willing to do. Get out and participate in your local tech community, giving talks and connecting with people who can connect you with people. Start writing blog posts, answering questions on forums, helping people in IRC channels. Become known as a helpful and knowledgable person. You do not get to be an introvert. Getting your name out there, when you start and constantly after that, is the No. 1 most valuable thing you can do — at least as important as being good at what you do.

Dive in and Do

I cost a fair bit of money. In return for paying that, clients expect that I can come up to speed on their project quickly and start solving their problems for them — they don’t want to pay for a long ramp-up period before they can even accurately assess whether my time was a good purchase. Part of doing this is having solid fundamental skills — an understanding of basic application development patterns, version control systems, development environments, etc. When I don’t have those fundamental skills for a particular project and I expect that may get in the way of a quick ramp-up, I make that very clear to my clients.

More generally, it’s critical that you demonstrate value as soon as you can, and make sure your clients are well aware of the progress you’re making — if they don’t ask you, tell them anyway. If you get stuck on a particular problem, part of your job is to recognize that you’re stuck, and honestly assess whether this is your own shortcoming or not. If it is, think long and hard about whether you should bill the client for your learning time; if it’s not, at least let the client know about the roadblock and your plan for overcoming it — you never know, the client might re-frame the problem in a way that’s easier to solve.

Don’t Specialize … Yet

When you first start, it pays to be open-minded about the kind of work you’ll take on. It helps get those bills paid, but also, it helps you zero in on exactly how you’re good at providing value to clients. The value you provide may be entirely different than the value you were providing at your job, or even than how you thought you provided value in general. Over time, you can start to market yourself using true stories of how you helped real live clients, and start to develop your niche.

Think Global (and favor clients who do, too)

I have had clients in California, Florida, New York, and places in between, but I’ve never needed to travel to any of them. I find that the work I do is incredibly time and place independent, as long as the client has good systems in place. This means version control, a development environment I can ssh to, liberal use of IM, a sane deployment process (read: not FTP), and some sort of project management tool and/or ticketing system. Projects that have lacked these systems have been more challenging, and these days I tend not to accept them.

Don’t Accept Abuse

There are terrible clients out there, but you do not have to work for them. If a client is impossible despite your best efforts to improve the situation, quit in a professional manner but without remorse. The client is not always right. You will find more work from someone better. Every. Single. Time.

Ignore the Economy

One question that’s come up a lot is how I think the economy has affected my ability to find work. Lehman Brothers would declare bankruptcy less than two months after I lost my job; the Dow would lose 3,000 points in the following weeks. My general theory on the economy question is this: rarely is full-time employment of a web worker an efficient distribution of labor, unless you are working for a very, very large company. The volume of work can fluctuate tremendously. I think of all the hours at previous jobs when there was literally nothing to do, yet the companies kept me around for the moment when there was. This was dumb. I’d like to think that as companies are looking for ways to cut costs, they’ll realize that was dumb, and bring people on as needed. The flip side of that is that those displaced workers are now competing for the consulting work. In the end, I think the economy may be a bit of a wash if you’re good at what you do.

Get Support

This feels like the single most discouraging thing I have to tell people: I am not sure I could have done this without the knowledge that the bills would still get paid if I failed. Our double-income-no-kids salary is embarrassing, but we were very intentional when we bought our house that we wouldn’t take on more than we could afford with one salary, no matter what the lenders told us we could have. My partner’s employer allowed me to enroll in their insurance coverage almost as if I were her spouse (I had to wait a few months for open enrollment, costly months I wouldn’t have had to wait if we were married). The comfort of this knowledge has been amazing, in those first few months when it became clear that I just might not need a job and in those dark months when it’s been unclear where the next check would come from. I am sure working for yourself is possible without these stars aligning, but it would require a braver soul than me.

Practical Matters

Have Clear Payment Terms (and realistic expectations)

I learned early on that I can’t expect anything quicker than Net 30, and that’s a long time — as much as 60 days after I did the work, assuming I bill monthly. One client failed to pay due to some issues with their accounting department, and it got to the point where I had to let them know that I couldn’t continue working with them until I got paid. A deadline was looming; a check arrived FedEx the next day. Be clear about your payment terms. You’ll get Net 15 if you’re lucky; Net 30 is standard. Incentivize them with late penalties if you need, and don’t hesitate to contact a client once that deadline passes.

Decide What You’re Worth

Honestly evaluate what your fee system should be, then stick to it. People who want to pay you less will cause other headaches that will make you wish you’d charged them more without fail. If you enter into any retainer situations, make sure the terms are crystal clear to both sides. Generally retainers work where the client purchases a minimum number of hours per month (potentially in exchange for a bulk discount). Communicate with them if they are not using their minimum hours, but try hard not to end up in a situation where you’ve cleared your plate for a client who then doesn’t need you as much as they thought they would. On the flip side, if the client has promised you 30 hours a week because they overestimated a task, but you’re so good the work is only taking you 15, make that very clear to the client and move toward arriving at a new arrangement quickly. They’ll appreciate your honesty, and you can free up your time for other work.

Decide How Much You Want to Work

Be clear about your availability if it’s not 24/7. Let clients know what the best way is to contact you. For me, for example, I hate being interrupted by phone calls, and greatly prefer IM over email for quick exchanges. I’ve learned to tell my clients this up front. For your own sanity, contemplate whether there’s a minimum number of hours you’re willing to work on a project. Too many times I’ve spent more time discussing a project than actually doing it. Make sure you account for that discussion time, and for the cost of getting you to sit at your computer rather than playing outside.

Get an Accountant

If you find yourself making any money at all, get an accountant. Taxes are complicated for self-employment. April 15 will either suck or it will suck a whole lot. An accountant will help you figure out estimated payments and advise you on the best way to keep as much of your money as you can. For me, that meant forming an LLC, which meant a lot more paperwork throughout the year, but a lot more money in my pocket at the end of it.

So, Go!

This working for yourself thing is hard. It’s so very important to be good at what you do, and yet being good at what you do has so little to do with being able to pull off working for yourself. On one level, I wish more people would do it — I believe it achieves a far more efficient distribution of skills and labor while allowing for some serious specialization. On the other hand, the instability of it ranges from mildly uncomfortable to downright terrifying, and so reality dictates that most people will wander back to the full-time world soon enough, and the independent thing will be but a blip on the resume. I, though, feel lucky I’ve made it this long.

Loading mentions Retweet

Comments (2)
Posted 19 days ago

On Rolling Your Own

There’s been a lot of activity around my last post, On jQuery & Large Applications. A number of people have asked me why, exactly, I’m so opposed to using jQuery as part of a roll-your-own solution.

To answer that, let’s start by looking at (some of) the pieces my ideal large application solution might include:

  • DOM manipulation tools
  • Ajax tools
  • A dependency management and build system
  • Clear patterns for code organization, such as namespaced modules
  • An inheritance system, preferably one that offers multiple inheritance, for sharing code across modules and staying DRY
  • A non-DOM-centric, loosely coupled API for communication between modules
  • A widget system that makes use of the inheritance system, with lifecycle management (setup/teardown) and templating
  • A system for maintaining templates separate from JavaScript while interning them into the build to eliminate HTTP requests
  • A system for abstracting RESTful server communication
  • For a UI-intensive project, a rich widget system pluggable to arbitrary data sources and designed with an easily-extended API
  • For an enterprise project, a11y and i18n provisions, as well as clear patterns for file organization

To all of you who have said you can do this yourself, you win. I can’t argue with you without sounding like I’m saying you’re too dumb, and you’re probably not.

But here’s my question: why? What, exactly — exactly — do you gain by putting all of this together for yourself, rather than using the pieces you need of a toolkit that provides all of this out of the box? Because here are a few things I think you lose:

  • Integration. Is your abstracted RESTful data API designed to talk to your widget system that’s designed to talk to your template system? That’s hott. Now what about when a new version of one of those components comes out that violates an assumption you made?
  • Maintenance. I heart the good folks who have put together individual answers to these individual questions, but they have no obligation to continue being the good folks they are, and they certainly have no obligation to do it on any sort of schedule. Remember all those plugins that broke with jQuery 1.4? That sure was fun.
  • Documentation. I’m going to grant you, right now, that jQuery is one of the best-documented JavaScript libraries out there, hands down. But what about all these other pieces you’re putting together? Especially the ones you really are rolling on your own, like that templated widget thing that communicates so nicely with your abstract data API. There are a wealth of resources for understanding, troubleshooting, and using these pieces in established toolkits. Where will the next developer turn when they have questions about yours?
  • Experience. Like I said, I get that you’re smart. Possibly smarter than me. That’s cool. But are you smarter than the combined wisdom of a team of people that has been thinking about these questions for years? Are you sure your solution has thought through all the questions they have?

I’ve noticed that, in the conversations I’ve had the last few days, it seems to fall to me to “prove” that a roll-your-own solution that includes jQuery isn’t advisable. Perhaps that’s fair — “you started it!”, you might say, and that I did. But simultaneously, others argue that jQuery never set out to answer these questions, and so it’s not jQuery’s fault that people are trying to use it in ways it wasn’t intended to be used. I have waited in vain to hear a compelling reason why jQuery should be part of a large application solution, to hear why I should recommend a roll-your-own solution that includes jQuery to my clients. The extent of the argument seems to be “because I like it, and it doesn’t force me to think a certain way.”

No one puts baby in a corner. Got it. But the straw man-ness of this argument has me, literally, chuckling right now. Let’s not confuse a mythical one-size-fits-all solution with a toolkit that provides, well, tools. Tools to do all sorts of things, tools meant to work together, tools developed and tested and maintained by a whole big team of smart people, tools that are, actively, being used in really frigging big, really frigging enterprisey applications.

I very purposefully didn’t propose a particular alternate solution in the original post, but it’s hardly a secret that my personal favorite, of late, has been Dojo. Not because it purports to solve every problem or prescribes how to solve them, but because it gives me so many tools to use to solve a given problem. Time and again I find that “Dojo already did that” — they already wrote the tool I’m wishing I had. Now I don’t have to write it, and, perhaps more importantly, I know it was written to work with all of the pieces I’m already using, and when I use it I’m not risking duplication of code or a lack of testing, maintenance or support. Win.

But let’s be very clear: no one’s forcing me to use that component! No one is forcing me to do things a certain way, any more than jQuery is “forcing” me to think of my application entirely in terms of the DOM. I can write my own component if I want, or use someone else’s if I want, or change it a bit if I want! For example, on a current project I pulled in mustache.js because the project had a lot of templates that had already been written to use it. The brilliant thing, though, was that integrating mustache.js into dijit._Templated instead of the standard templating system was trivial. That component, and all the others in Dojo and Dijit, are architected explicitly not to be one-size-fits-all. They provide a rock-solid base for large application development, for getting up and running quickly using a bevy of ready-made solutions, but also provide so many extension points that you can turn those solutions on their head if you want or need.

Garann Means, whose blog you should be reading, took a bit of issue with my original post in model-view-controller and comfy clothes.

I do agree that it benefits everyone to be working in the same setup and making use of tools that have been vetted by geniuses whose entire job is to create such things. But I’m dubious about any approach which comes too close to promising one size fits all. If you’ve ever sewn a dress, you understand that one size fits all is technically possible, but some people are going be left with a lot of excess while others will scarcely be able to breathe.

Carrying on that metaphor, these pieces provided by Dojo — or any other comprehensive toolkit, for that matter — are but starter patterns, and thread, and scissors, and pins, and a sewing machine, and OK I’m stretching the metaphor, now, but my point is they’re definitely not finished one-size-fits-nobody garments. On the other hand, if I decide to use jQuery in a large application, it can feel like I’ve been given a black marker and some of that crinkly brown paper, and now it’s up to me to draw a pattern and then come up with all those other pieces, too. Intellectually interesting and pleasingly crafty, perhaps, but not particularly efficient, sustainable, repeatable, or maintainable.

So again I ask, in all seriousness and in hopes of fostering a good discussion: Why? jQuery provides you with DOM, Ajax, and event management tools, but little else. There are tools designed for building large applications, designed to provide all of the pieces I want and so many more it’s not even funny, and they provide you with DOM, Ajax, and event management tools, too. What’s the compelling case for rolling your own solution that includes jQuery instead?

Loading mentions Retweet

Filed under  //  dojo   jquery   large-applications  
Comments (17)
Posted 22 days ago

On jQuery & Large Applications

Update: I’ve written a separate post on the wisdom of rolling your own large application toolkit that incorporates jQuery.

I’ve been thinking a lot lately about JavaScript applications. As my skills have evolved, I’ve had the privilege of working on more actual applications, and I’ve gotten further and further from clients who want to add a bit of Ajax or bling to an otherwise fairly traditional web site.

The most interesting applications I work on are client-side intensive: the server is responsible for providing data as JSON to the client, and most everything else — templating, state management, data management, site navigation, and of course user interaction — is left to the client side.

It’s a lovely way of writing an application. There’s no need for me to touch server-side code; in some cases I work with a server-side developer to decide what the data they send will look like, but in others I just take what an API already provides and make it work. I get to use the same templating framework across projects, regardless of server-side technology, and I can prototype complex interactions before the server side even exists.

This is a land where HTML, CSS, and JavaScript are almost all you need, and I like it. I’ve become a firm believer in moving giant hunks of functionality that used to belong to the server over to the client. For a variety of reasons, I think it’s clear that this is where most interesting web development is headed, to the extent it’s not already there.


This style of building an application changes the front-end development game. In fact, “development” may no longer be an adequate description; we’re moving into the realm of engineering, here. We’re not using JavaScript to add a bit of bling to our sites — a slideshow here, some Ajax there — we’re architecting an application, damnit. We can’t just write some procedural code that binds a bunch of anonymous functions to some events and call it a day; if we do, I can tell you from experience that we’re going to end up with a steaming pile of unmaintainable crap.

Among a host of questions presented by these sorts of applications, some of the most interesting to me are:

  • What are the units of functionality that will make up the application?
  • How will those pieces be organized into units of code?
  • How will those pieces communicate with each other?
  • How will dependencies between components be expressed and managed while adhering to the principle of loose coupling?
  • How will components manifest themselves in the DOM? Do they need to?
  • How will we persist data across URL and page loads?
  • How will we manage communication with the server?
  • How will we make sure users only see the data they’re allowed to see?

At the risk of making a broad generalization, this isn’t the way today’s average JavaScripter learned to think. The mantra of jQuery, the most popular JavaScript library on the internets, is “get some elements, do something with them” — perfectly terrible preparation for analyzing an application from a perspective other than the DOM. And, IMHO, therein lies a tremendous problem.


As more and more application logic moves to the browser, I’m eager to see the JavaScript community rise to the challenge, but instead it feels like the opposite is happening. People with little understanding or appreciation of these questions are taking on projects that demand these questions be answered. The result is a land of fragile code that gets the job done while giving the finger to the next developer; a land of code so tightly coupled, so deeply beholden to the DOM, so blatantly not reusable or extensible or maintainable as to render every subsequent commit a complete crapshoot, as liable to cripple the application as not. The viability of the project is threatened, and so is the reputation of JavaScript.

We are better than this. JavaScript, even that old-fashioned browser kind, is a language worthy of respect, not a thing to be dreaded. But — and here’s the sentence I have struggled 10 months to realize and an hour to write: in order to prove that we are better than this, we must make abundantly clear to the budding developers, to the project managers, to the enterprises, to anyone intending to build a remotely complex JavaScript application, that there’s more to JavaScript than jQuery. The questions are bigger, the answers more complex, and the relevant skills, alas, a bit harder to come by.

We have to make clear that, in fact, jQuery is but a hammer. When it comes to building these intensively client-side applications, we’re talking about building skyscrapers, for god’s sake. The problems solved by a hammer are the least of our concerns.


It was just a few months ago that I gave a presentation on building large jQuery applications. I emphasized jQuery’s role as strictly a DOM and Ajax tool, and demonstrated a few other tools — John Resig’s simple inheritance, James Burke’s RequireJS dependency management and build tool, Jan Lenhardt’s mustache.js — that one would want to bring to the table for such an undertaking.

But to what end do we assemble said hodgepodge of tools? Is it just so we can continue to “use jQuery”?

jQuery’s API is, indeed, dead-simple, but we are smart people! We are building skyscrapers! When it’s time to write a complex application, and we need all of these things that jQuery doesn’t offer, can we not learn to use another hammer — learn that dojo.place('<div>I am new!</div>', oldDomElement, 'last') means the same thing as $('<div>I am new!</div>').appendTo(oldDomElement) — if learning it gives us access to legions more functionality than jQuery even aspires to provide?

Do we assemble this hodgepodge because finding jQuery developers is perceived as an easier task than finding practitioners of another library, even though someone saying they “know jQuery” is little indication that they will know how to work with the assembled solution?

Do we do it for the plugin ecosystem — full of code of varying quality and maintenance — even though many of the large application needs addressed by those plugins are addressed by other libraries as well, and sometimes better?

And when we do it, when we assemble this collection of tools ourselves, what risks are we accepting? What price will we pay down the road to maintain three or five or 10 different pieces from three or five or 10 different authors, with different release cycles, no guarantee of compatibility or maintenance, and no central project thoughtfully considering their future?


I’ve wrestled with these questions for months, agonizing during sleepless early-morning hours over how to advise clients on the answers. I’m the co-host of yayQuery, a contributor to the jQuery Cookbook, and, I’ll venture to say, a decently respected member of the jQuery community. I did not arrive at this conclusion lightly, and I have few illusions it will be well-received, or even heeded.

But I’ve grown weary of people championing a tool that simply does not answer the big questions I see in project after intensively client-side project. I’ve grown weary of those same people dismissing tools that answer those questions handily and have been answering them for a while now. I cringe when clients tell me they’ve chosen jQuery because it was “easy,” and then watch them predictably struggle with all of the questions it does not answer. And I’ve found I can’t continue to bite my tongue when people recommend jQuery as an enterprise-grade solution while failing to acknowledge these questions, let alone answer them*.


I do not want to see jQuery go away. The simplicity of its API was undeniably instrumental in the rise of JavaScript as a language these last few years. It is a perfect gateway drug, and I greatly enjoy watching people transition from “get some elements, do something with them” to the elegant patterns of JavaScript itself.

jQuery is an entirely appropriate answer to so many questions, but it falls so short for large applications, forcing you to assemble such a tenuous toolkit of your own, that it simply isn’t a viable answer — or, in my opinion, part of an answer — for large applications. If we hope to continue to gain respect as a community, we ought to admire jQuery’s immense contributions, but we must not be afraid to accept and make very clear its limitations. We do otherwise at our peril.


*An aside: To its credit, JupiterIT has put forward JavaScriptMVC, the only substantive attempt I’ve seen at answering these large application questions using jQuery. I applaud them, but fear their efforts will continue to be somewhat isolated without the support and endorsement of the wider jQuery community. If you have read this far and still have your heart set on a jQuery-centric large application solution, you should by all means take a look at JavaScriptMVC.

Loading mentions Retweet

Filed under  //  jquery   large-applications  
Comments (53)
Posted 24 days ago

I need to say a few things.

Over the weekend, there was a tweet announcing that Google was going to provide "scholarships" to qualified women to attend JSConf.eu. There was then a tweet by another person calling this "disgusting" and "illegal." Nicole Sullivan has a level-headed and well-articulated roundup of the back-and-forth and some of the surrounding issues, and I suggest you read it.

I take no position on the scholarships. I question whether they will have any meaningful or lasting effect. I fear the availability of the scholarships will lead to ill feelings about the women who do attend. Simultaneously, I yearn to discover, against hope, that they make it possible for some highly qualified but unknown woman to gain access to the JavaScript community. Whatever. Smarter people than me have a better idea than I do as to how effective they will be, and lawyers can tell you whether they're illegal. I'll stand firmly in the "no" camp on the disgusting count.

You know what's disgusting? Being groped at a conference after-party by a drunk married man. Opening your hotel door to discover said drunk married man stumbling down the hall, asking himself into your room, and literally having to slam the door in his face. Having a video of you posted on the internet, suggesting that you were engaged in a sexual act with the yayQuery logo. Seeing someone ask, publicly, on Twitter, if anyone knows the name of the hot conference chick. That, dear reader, is disgusting.

I adore my male friends in the tech community. They have encouraged and supported me and welcomed me into their inner circles. But even they can act like 12-year-old boys sometimes, and while I don't begrudge them that, it is hard, because it's at those moments that I realize how much I am not them, how much I long to have more than the barest assembly of female peers who have any idea what this is like. And then I remember: those peers I long for will have to put up with so much shit to be in that cool kid's club, and you know what? If Google wants to pay them a measly few hundred bucks to put up with it, maybe that's OK. Hell, maybe they ought to pay them more. Perhaps, as ham-handed and questionably productive as the scholarships may be, it's only fair to pay women to look the other way when some asshole treats them like a thing instead of a person.

I am angry. I have been angry since Saturday, when this all started. I have spent the last year trying to be the thing that I want to see: the woman on stage. I have formed groups to encourage other women to do the same. I have reached out to women who show potential and tried to give them the encouraging nudge they need that no one really gave me. And right this very moment, I feel incredibly selfish. This weekend reminded me what I am asking those women to enter into: a world that presents no tangible barriers, but that will objectify them every step of the way. And if these women have the guts -- well, let's be community-appropriate here -- if they have the balls to speak up and say that it is hard to be a woman in this field, that it takes a thick skin and determination and a willingness to be one of the boys even when that's the last thing in the world they want to do, then they should brace for a chorus of men to rise and tell them they are wrong.

Men, guys, boys: I am not asking you to give up Star Wars and The Matrix. I'm not even asking you to give up gratuitous phallic references and #twss jokes, though I hope we're all grown-up enough to know that there's a time and a place. And you know what? If you want to DM your friend about trying to hook up with that hot conference chick, well, good luck with that. We're all human. But for the love of all that is good: this being a woman in your world thing, it's not easy, OK? Maybe you can't understand it, and I even believe it when you say you don't mean it. But when you deny it, you just look like an ass.

Loading mentions Retweet

Filed under  //  speaking   thoughts  
Comments (45)
Posted 1 month ago

Patterns for DRY-er JavaScript

I came across a little code the other day that reminded me I've been meaning to write about JavaScript patterns I take for granted. The code in question was intended to set the value of some fields in a form when a checkbox was selected; when it was deselected, the same fields were to be emptied. It looked not unlike this:

// config is defined outside of this snippet,
// and may contain more than the properties
// we care about 
$('#myCheckbox').click(function() {         
  if (this.checked) {                 
    $('#field_foo').val(config.foo);                 
    $('#field_bar').val(config.bar);                 
    $('#field_baz').val(config.baz);         
  } else {                 
    $('#field_foo').val('');                 
    $('#field_bar').val('');                 
    $('#field_baz').val('');         
  } 
});

This is a wholly readable bit of code -- there's almost no question what's going on here. On the other hand, it's pretty easy to see the rampant repetition; this code isn't interested in "don't repeat yourself" (DRY). We're calling the same method on every selection we make, and our selections are repeated in both the if and else block. When I saw this code, I had an immediate inclination to rewrite it. Here's what I came up with first:

// config is defined outside of this snippet,
// and may contain more than the properties
// we care about

$('#myCheckbox').click(function() {
        // note whether the checkbox is checked
        var checked = this.checked;

        // iterate over the keys we care about
        $.each(['foo', 'bar', 'baz'], function(i,v) {
                // find the field for the given key
                $('#field_' + v)
                        // and set its value either to the string
                        // stored for the key, or to an empty string,
                        // depending on whether the checkbox was checked
                        .val(checked ? config[v] : '');
        });
});

This looks approximately nothing like the initial code, and without the comments, the code itself would be substantially less readable than the original. The idealistic part of me -- the part that believes people who write JavaScript should understand JavaScript -- says this is an acceptable price to pay. And besides, there's something to be said for explaining the code in a comment that can be stripped by a minifier, rather than explaining the code via the code. In this iteration, we've introduced two patterns for DRY-er code: iterating over an array literal (or, alternately, an object) to achieve repetition without repeating ourselves, and using the ternary operator in place of an if/else statement when the simplicity of our logic allows it. The array literal serves as a list of the fields we care about. When our checkbox is clicked, we iterate over this list, build up a selector for each item in the list, make our selection, and then set the field value using a ternary operator. We've gone from 11 lines of code to six, with the added bonus that we have to do a lot less typing if we need our checkbox to affect more fields. (A side note: Is this premature optimization? I'd argue no, if you've learn to see these patterns before you start writing code. Once you learn how to spot these patterns in a requirement, writing code that embraces them can actually be easier than writing code that takes a more "literal" approach to the problem. For example, imagine if the checkbox affected 20 other fields instead of one? You'd undoubtedly find yourself copying and pasting code if you took the more "literal" approach to the problem, and that would be your first clue that you were doing something inefficiently.) The great thing about using a pattern like this is that it rapidly exposes the actual meat of what you're doing, and makes refactoring far less painful. I also find that it helps me see opportunities for reuse that I might not have spotted in the more literal version of the code. Let's say we're feeling all proud of ourselves for DRYing out our code using clever JavaScript that only super-smart people can read. Now there's another checkbox that needs similar behavior, but it's going to use a different config object and a different list of fields. No problem! You've already written this code, so you can just copy and paste it and then change what's different. Sweet. Er ... suddenly you're not looking so DRY after all. This is when another pattern comes into play: creating a function that returns another function with certain variables already baked in (that is, creating a closure). We'll execute this creator function and then use the function it returns in place of the anonymous function we were using previously when we bound to the click event.

// handleClick accepts a config object
// and a makeSelector function; it returns
// a function that can be bound to 
// a click event, using the config object
// and the makeSelector function to react
// appropriately to the click
var handleClick = function(fields, config, makeSelector) {
        return function() {
                var checked = this.checked;

                fields && $.each(fields, function(i, v) {
                        // build the selector using the provided
                        // makeSelector function
                        $(makeSelector(v))
                                // set the value using the
                                // config object, depending
                                // on whether the checkbox
                                // is checked
                                .val(checked ? config[v]: '');
                });
        };
};

$('#myCheckbox').click(
        // use handleClick to create a function
        // that has these variables baked in;
        // pass the created function as the
        // click handling function
        handleClick(
                ['foo','bar','baz'],
                myCheckboxConfig, 
                function(field) {
                        return '#field_' + field;
                }
        )
);

$('#myOtherCheckbox').click(
        handleClick(
                ['bim','bar','bop'],
                myOtherCheckboxConfig, 
                function(field) {
                        return 'input[name="' + field + '"]';
                }
        )
);

By creating a function that returns a function, we can isolate what's different about the two different handlers while centralizing the pieces that are the same. If your event handling function was slightly less trivial than this one, or if you were binding to five different checkboxes instead of two, the benefit of consolidating the code would be even more substantial. JavaScript offers plenty of patterns for writing DRY-er code; it's important to learn to both recognize and use them. It's also important to recognize when you're writing un-DRY code in the first place -- copying and pasting code is one crystal-clear indicator, but others are more subtle and you may not identify them on the first go-round. For example, take these two functions; each receives a list item as its only argument and returns either the next or previous list item, returning to the beginning or end of the list if there is no next or previous item.

var getNextItem = function($item) {
        return $item.next().length ? 
                $item.next() : $items.first();
};

var getPrevItem = function($item) {
        return $item.prev().length ?
                $item.prev() : $items.last();
};

This felt repetitive when I first wrote it, but I couldn't quickly come up with a single function that would work. A little thinking about it, though, led me to this single function which gets a second argument: direction. That argument is used to decide whether to run the item's next or previous method, and then whether to run the item's first or last method. Besides combining two functions into one, it also eliminates calling next or prev twice inside each function.

var getItem = function($item, direction) {
        var $returnItem = $item[direction]();
        return $returnItem.length ? 
                $returnItem : 
                $items[(direction == 'next') ? 'first' : 'last']();
};

Learning about patterns and then discovering opportunities to use them is one of the more pleasing parts of my job. I hope this helps you identify some of those opportunities for yourself :)

Loading mentions Retweet

Filed under  //  front-end development   howto   javascript  
Comments (24)
Posted 1 month ago