Having worked on the FreeIPA GUI from inception through GA (well, RC3, soon to be GA) here’s what I’ve learned about the writing a web application using today’s technologies.
Use JSON for remoting to your server
Use CURL to talk to your server
Since the JSON marshaling is just another web technology, liberal usage of cURL or other HTTP based command line tools let you determine exactly what your RPC requests and responses should and will look like. We use CURL to fetch sample data, to test new features, and bulk upload data.
Make it work without a server
Fetching JSON from the server can be mocked out by capturing static snapshots of the JSON. Our JSON mechanism has everything go through one URL, with a method field that determines which RPC gets called. We stubbed this out in development to fetch a comparable named static file from the test data directory, and then expanded the scheme a little bit to allow the unit tests to fetch different files on context. But to do WebUI development, we do not need to talk back to a server, and that simplified things greatly.
Java Script Lint
We have a simple configuration file for the jsl command line utility. It tells us if we are straying from our coding standards.
Use QUnit for unit testing
Write the CLI first
All applications have a tendency to absorb business logic over time. In FreeIPA, we had the advantage of a really strong CLI that was written first, and that is the preferred tool of administrators. Thus, we could make the rule that it the WebUI can’t do anything that the CLI can’t do first, and we pretty much have stuck to it; the only exception is batch process, and even that can be done from the command line using curl. It also gives us a path. I see the WebUI as being for tasks that are done infrequently, that are complex enough that the user requires hand holding, and for bringing new people into the system. With a good CLI, they have something that they can graduate to, to script, and to integrate with other systems.
Since IPA is a security product, I didn’t want to find out that the web UI had some flaw that turned it into a major security hole. By using the same mechanism as the CLI, I feel confident that we have in no way weakened the security of the application. We’ve managed to keep the window into the server as small and protected as possible.
Internationalize on the Server
FreeIPA is written in Python in a mod_wsgi application. Since the browser already sends internationalization information to the web server, we let the server tell us what language to display, and what strings to use. It does mean that we have to extract strings out of our ui, and explicitly put them into a server side component, but the end result is very easy to work with.
Use JQuery or a comparable toolkit
As I compare the features we have implemented with those provided by Dojo, I am struck by their similarity, and can’t help but wonder if we should have used it instead of JQuery. I think that we made the right choice, though, because we really had to customize our application, and I think that for Dojo, we would have been fighting the framework, whereas with JQuery, it provided just enough framework to let us design the application the way our User Experience Team designed it. We did use JQuery UI, and probably benefited somewhat from using ThemeRoller, but I’d have to say that by now we probably work around the JQuery UI code as much as we use it. Not as a slight on JQuery UI, it is a great toolkit, but our look and feel is very customized and JQueryUI again provides a fixed way to do things like buttons. With JQuery, we have to potential to use someone a table widget from somewhere else, or just build one our self. It is the degree of brainshare that JQuery has that makes it so compelling.
Use The BBQ approach for navigation
You don’t want to submit forms, or have links make additional GET requests back to your server that will require the complete redrawing of the page. The BBQ plugin makes a much cleaner interface by using the #url technology used to link to a different portion of the same page. It takes some getting used to, and the entire state of your application can end up in your URL, but it handles Back button and history without doing additional HTTP requests.
Use Selenium for Functional Testing
This is an effort we are just starting. Selenium allows you to record and playback interactions with the WebUI. Knowing what I know now, I wish we had started with it sooner, as I think it would have given us an even better battery of pre-checkin tests, and allowed us to automate development of features that had tricky interactions with the server.
How did I ever survive without Git? I’ll admit, there was a learning curve, but there are just so many benefits to a distributed revision control system that I just have to put a plug for it in here. Really, this is not specific to WebUI development, but I think it is safe to say that all development benefits from the advance made in distributed version control. If you are coding, use Git (I’m sure that Mercurial or Bazaar are really good, too, just can’t speak from experience there.)
It also is certainly true that the more of a framework you build, the more you find yourself refactoring to account for things outside your initial design. Things that area easy to code as a one off are trickier to make happen if you have to keep from breaking a framework. But the resulting code is certainly cleaner and more maintainable if you take the time to do it right.
There are many more lessons learned from this past half-year. I’m glad I have had this chance to work along these lines. I think it has proven a fast, light, and robust approach.
Special thanks to Endi Dewata, both for being such a great partner on the project and for proofreading this article.