When JavaScript Attacks, errrr, Hacks
I've been doing a lot of JavaScript coding in my recent work on Launchpad. I mean, a lot! We're pushing to get every aspect of a bug page editable within the page itself, hopefully making it easier to manage bugs without being directed to another web page. Everyone on the Launchpad bugs team is working on some part of this. I haven't previously done any JavaScript coding like this, and now I'm sitting with a 1400 line JavaScript file that has grown unwieldy and needs to be tamed. I'm starting on that refactor this morning and thinking on the things I've learned as this file has grown seemingly with a mind of its own.
I should note some of the conditions that led to this. I wrote that I haven't done JavaScript like this before, but it's not as if I lack experience with js. I've done a lot of JavaScript coding both in previous jobs and for fun, everything from minor usability improvments to extensive page functionality in JavaScript. I've taught conference tutorials on AJAX and was even working on a book on Google's use of JavaScript in it's apps. (Yes, I'm a failed tech book author at this point, but the point is still valid, I think.) But all the work I've done previously either started in JavaScript and added server components as needed, or started with the server-side and added JavaScript in targeted areas. This work we're doing on Launchpad bugs has an existing, sophisticated server component -- the bug tracker -- and now needs an extensive JavaScript application built on top of that. Adding complexity is that the JavaScript component is being built piece-by-piece in small branches, rather than with a cohesive architecture. And by several developers at once.
It's this part about building an extensive JavaScript application in pieces that is really the new part for me, and I've learned some things I'll carry foward in terms of how to build a nice JavaScript module in small bites.
Global Module vars
Sticking variables into the global namespace of a module (so multiple functions have access to the variables) is now my sure sign that I need to refactor. From here on, I'll create an object rather than doing this.
This seems obvious but we're using YUI3 where each module is akin to an object itself, so it wasn't that clear to me. I would avoid module-level globals, even inside the module pattern itself, and create distinct objects the moment I begin to need state across objects or functions.
Closures
Again, YUI's module pattern and the way our Launchpad API is designed encourage callbacks via anonymous function closures, especially when dealing with XMLHttpRequest. And really this is a fine thing, and a common pattern when doing async js coding. But it's easy to let the closures get out of hand, which makes the code harder to read and maintain and makes debugging a bit harder, too. So I'm trying to use closures only as I have to.
Custom Events
Given the previous point, I think it's good to fire custom events to signal when to do some work. A custom event when an XHR has completed, or a custom event when it's time to update the DOM. A custom event when some state is initialized, and so on. Custom events are my new mantra going forward.
Perhaps I'll look back after this refactor and feel I've abused this pattern as well, but I think it will be cleaner and will be easier to test.
Patterns for Reuse
And finally, the next time I get into some extended bit of JavaScript work, I'm going to think about the patterns I'll be using and about the overall architecture earlier. Even though I'm sure I'll still be doing small branches that add small bits of functionality, I'll try to look ahead more to where this code might be reused across Launchpad, where this pattern of functionality or interaction might be repeated, and where the code I'm working in is likely to go over the next two cycles.
Link | Posted by deryck on June 26, 2009 | 0 comments

