What should Mozilla look for in an automated review system?

In last week's All Hands when talking about possible process improvements, Mike Shaver asked if there was any interest in some sort of automated review system.  Google's Mondrian is probably the most well known review system.  Review Board seems to be the best known open source review system.  I've never used Review Board, but as an ex-Googler, I have used Mondrian.

I think Mozilla would really benefit from a good review system.  My review system experience is limited to Mondrian, which is, of course, proprietary to Google.  I don't know how Review Board and the other open source systems measure up, and, as I'm about to get to, I think Mondrian itself has some notable deficiencies.  My overall point is that if we decide to adopt a review system, we should choose carefully.  I'll try to offer some guidance about how to do that.

Quick Overview of Mondrian

Mondrian has a dashboard view for outstanding changelists but to me the essence of Mondrian is its UI for reviewing a single changelist, and that's what I'm going to talk about here.  At the highest level you have a list of files modified in the changelist.  You can click on each file and get a diff of that file against the baseline in a side-by-side view.  You can easily see which lines were added, modified, or deleted.  OK, everybody is familiar with side-by-side diffs these days.  Here's the cool part though: A reviewer can click on any line and leave an inline note or comment.  Afterwards, the reviewee can go through the diff and respond to the comments.  The way this often works in practice is the reviewer leaves an instruction in the comment and the reviewee responds by making the requested change and replying to the comment with "Done."  In fact, there's a "Done" button as well as a "Reply" button on the comment just to make this last part easy.

Once the reviewee has updated the changelist to the reviewer's satisfaction, the reviewer will approve the change and the reviewee can submit it to the source control system.

What's not to like?

Mondrian's review UI is great for simple line-by-line reviews, things like:
  • "You don't need to check for null here."
  • "You should check for an error here."
  • "Fix indentation" 
Sometimes this level of line-by-line scrutiny is really useful.  For example, exception-free C++ code often requires the programmer to check virtually every single function call for errors.  This is hard for even the best programmers to get 100% right.  But let's be clear here.  What Mondrian is really good for, all the time, is line-by-line nitpicking of code.  And frankly, line-by-line nitpicking of code is already pretty easy without some fancy tool like Mondrian to make it extra easy.

Mondrian's review comment system really seemed to encourage a style where there was a one-way flow of instructions from the reviewer to the reviewee: "Do this.  Do this.  Do this." and the reviewee replies with "Done.  Done.  Done."  Sometimes this is appropriate, but oftentimes it isn't.

Of course the reviewee always has the option of clicking "Reply" instead of "Done".  You could have a whole thread of comments and replies if you wanted to.  But given the limitations of the UI, that would be kind of like communicating with short messages written on post-it notes.  And not regular sized post-it notes either, but rather those extra tiny ones.

So Mondrian not only encouraged a review focus on individiual lines, it also tended to encourage a one-way flow of information from reviewer to reviewee which could easily degrade into a one-way flow of commands.

What would I want in a "good" review system?

It may seem like I'm arguing that a review system should actively discourage line-by-line review, and that's not actually the case.  I think that review style is often useful, and pretty much any review system, good or bad, will support it.

There are really two fundamental things that I do want out of a review system.

  • The system should go out of its way to support a bi-directional flow of information between the reviewer and the reviewee.  In the extreme, it should provide a means of carrying on an actual conversation.  This could be supported within the review system itself, but even a simple means of escalating a conversation to email (or even IRC) might be a big help.
  • The system should support higher level discussions about the code under review.  Actually I think it should go so far as to encourage this kind of information flow.  You can sort of do this with Mondrian, but you are usually better off just going to email.

Some general guidance

I've put a fair amount of thought into how I'd like an ideal review system to work.  Mostly I've been thinking in terms of concrete features, but that's of limited utility if what you want to do is choose between existing review systems rather than writing a review system yourself.

So I'm trying to figure out some general guidance.  I think what I'm trying to say in this post more than anything is that affordances matter.  Mondrian, for example, seems to afford the line-by-line scrutinizing, nitpicking approach to code reviews.  It also seems to afford a model where the reviewer simply gives instructions to the reviewee and the reviewee just automatically carries them out.

Mondrian offers some minimal affordance for discussing (as opposed to simply commenting on) a particular line of code, but it could do a lot more.  Notably it does not seem to offer any real affordance for discussion at the design level, which has always seemed to me like a serious omission.

A simple concrete example

Here's one simple way that Mondrian could be improved which I hope will illustrate my point about affordances.  As described above, Mondrian comments have two buttons, "Reply" and "Done".  It could offer other choices as well, so you might have:

"Reply", "Done", "Done w/comment", "Defend", etc.

These latter two functions could easily be done with "Reply", but if you give them their own buttons, you explicitly tell the reviewee that there are other options that can be considered here.  In particular, in this case, they give the reviewee permission to say "I had a reason for doing this the way I did, would you please consider my reasoning?".

My larger point here is that a review system's UI strongly shapes the code review process, and it can shape it in good ways or bad ways.  As a result, we want to think not just about what we want out of a code review system, but also what we want for the code review process itself.

Super-short Summary

  1. A good review system needs to support two-way information flow, and it should probably go so far as to actively encourage it.
  2. A good review system should support review at a higher level than simply line-by-line, and it should probably go so far as to actively encourage it.
  3. Affordances matter.

Notes

  • This post describes Mondrian as of about nine months ago when I last used it.  It may have received a major upgrade in that time, I don't know.  Mondrian may also have had useful features that I didn't know about -- not all of its features had good discoverability.
  • Probably the most common code review case at Google is a reviewer and reviewee who are peers, have known each other for months if not longer, and who sit near each other, often in the same room.  Mondrian's limitations are a lot less important in this scenario, since a lot of out-of-band communication can happen the old fashioned way, by talking face-to-face.
  • In some circumstances you can have reviewers and reviewees who work in different locations and who have never met in person.  This is not uncommon at Google, and it is in fact very common at Mozilla.  In this scenario, the way the review system works becomes much more important.  
  • The obvious way to get around Mondrian limitations is to fall back to email.  I ultimately started emailing concerned parties requesting informal reviews before requesting formal reviews through Mondrian.  Mondrian can still be used in this case -- it can see pretty much any outstanding changelist.  Nevertheless, by making an informal request in email, you could get a high-level review of a changelist without getting mired in low-level details.  And since this was through email rather than Mondrian comments, you could hold an actual conversation about it.  It turned out my team's superstar intern had independently started doing the same thing.  I jokingly referred to this as "doing a review before the review".
  • This post might lead you to believe that I'm a Mondrian-hater.  Actually, I think Mondrian is a very good tool, I just feel like they quit working on it before they were done.

Comments [7]

The Firebug tabs-on-top UI refactoring has landed

Note: Since I was getting lots of comment spam I've closed comments here.  If you have any comments or suggestions, feel free to file them on the Firebug Issues page or drop us a line in the Firebug discussion group in the Tabs on Top thread.

The Firebug tabs-on-top UI refactoring has finally landed in Firebug 1.4 alpha.  You can download it as firebug-1.4.0a17.xpi (or later) from http://getfirebug.com/releases/firebug/1.4.  This change is pretty close to the one I described and prototyped in February (see Improving the Firebug UI) and which in turn follows my original proposal from late last year (see Firebug UI: Tabs on the Top).  These blog posts describe the reasoning behind the change so I won't rehash it in full.

The old layout had a toolbar at the top of the Firebug UI, and a tabbed "panel bar" below it.  Sometimes a tabbed "side panel bar" would show up to the right of the main panel bar.  This change essentially takes the toolbar and the side panel bar (when it appears) and puts them inside the active panel.  This puts the panel tabs at the top of the Firebug UI (hence the name "tabs-on-top") and panel specific controls underneath.  Several controls that are not panel-specific (the main Firebug menu, the search box, and the detach window and close window buttons) have been moved to the tab strip, so they are effectively in the same location as before the change.  The idea is that UI elements that are specific to a panel look like they are inside that panel.  This description probably makes the change sound more complicated that it really is.  A screenshot will better communicate how it looks.


Firebug UI with the tabs-on-top layout.  The Net panel is selected.

Even the screenshot is a poor substitute for actually downloading the extension and trying it out, so let me encourage you to do that.

There are still some outstanding issues, before this change can really be called complete.

  • The location of the main panel Options menu is less than ideal.  I think the right thing to do here is to merge the panel options with the menus on the panel tabs, but I haven't had time to prototype it yet.
  • The Inspect button really belongs on the top toolbar.  I've held off on relocating it because I think it will look too much like the label of a panel tab.  There are a couple of options here.  We could change the styling to make it look more like a button.  We could replace the label with an icon, or we could change the tab styling so even unselected tabs show a tab outline.  Probably any of these solutions would work, we just need to figure out what the best one is.
  • The position of the debugger buttons can jump drastically under some conditions.  Normally the debugger buttons only appear when the Script panel is active.  However, if JavaScript execution is paused, the debugger buttons always appear, regardless of the tab.  With the new layout this means their position can jump if you switch to another tab which doesn't have a side panel bar.  I think it might make sense to move them to the left side of the toolbar, which will eliminate this problem.  This seems like it might be a fairly controversial change, so we really need to explore it separately.

Comments [1]

What are "futures", and why should you care?

Motivation

Last week we were discussing, among many other things, ways to speed up Firefox during startup.  One obvious option was to move more of our I/O off of the main thread.  This in turn involves making more code asynchronous, and asynchronous code is simply harder to manage.  Mike Shaver mentioned something about "futures" as a possible way to handle the extra complexity, and then the discussion moved on to something else.

I'm not exactly an expert, but I've not just used futures, I've written my own implementations in JavaScript and even Object Pascal (in hindsight I'm not sure the latter was a good idea, but it was certainly an interesting exercise).  Futures seem esoteric, but they really shouldn't be -- the idea is really quite simple.  In this post I'll try to explain what futures are and how they can be used to make asynchronous programming easier.


What exactly is a future anyway?

In the simplest form, a future works like an IOU.  I can't give you the money you've asked for right now, but I can give you this IOU.  At some point in the future, you can give me the IOU and I'll give you the money -- if I have it.  If I don't have it yet, then you can wait until I do.  I get paid on Friday.

Alternatively there's the dry cleaner metaphor.  You drop your clothes off on Monday and the clerk gives you a ticket that you can use later to reclaim your clothes after they've been cleaned.  The clothes will be ready on Tuesday morning, but if you show up too early, you'll have to wait.  On the other hand, if there's no hurry, you can just do other stuff on Tuesday and show up on Wednesday with a reasonable expectation that they'll be ready when you arrive.  You'll just hand your ticket over, collect your clothes, and be on your way.

A future is similar to the IOU (or the dry cleaning ticket).  It gives you a way to represent the result of a computation that has not yet completed, and it allows you to access that result once it becomes available.  So you can call a function which starts some asynchronous process but doesn't wait for it to finish.  Nevertheless the function can return you a useful result: a future which can be used to claim the real result later.

Of course if you ask for the result too soon, you'll have to wait.  On the other hand, if the result becomes available before you want it, then it will wait for you.


A simple example

Here's an example of what this might look like in pseudo-JavaScript:

function doStuff() {
  var cleanClothesFuture = dryCleaner.dropOff(dirtyClothes);
  runErrands();
  work();
  eat();
  watchTv();
  sleep();
  var cleanClothes = cleanClothesFuture.get();  // block if the result is not ready yet
}

Compare this to the traditional way we'd handled this in JavaScript, using a callback:

var cleanClothes = null;

function doStuff() {
  dryCleaner.dropOff(dirtyClothes, function (clothes) { cleanClothes = clothes; });
  runErrands();
  work();
  eat();
  watchTv();
  sleep();
}

These examples are not one hundred percent semantically identical, but they should be close enough to illustrate the point.  I contend that the first function is easier to write, easier to read, and easier to reason about.  I also contend that the difference isn't enough to get excited about.  It's when things get more complicated that futures become really useful.


A more complicated example

Imagine that I have a web page that sends an AJAX request to a server and then displays the results in an IFRAME -- and furthermore does it automatically on page load.  I have to wait for both the AJAX request to return data and for the IFRAME to finish loading -- only then can I display the results.  This can be done fairly simply using callbacks:

function showData(dataUrl, iframeUrl) {
  var data = null;
  var iframeBody = null;
 
tryToShowData { if (data && iframeBody) { showDataInIframe(data, iframeBody); } }
  requestDataFromServer(dataUrl, function (response) {data = response.data;  tryToShowData() });
  insertIframeBody(iframeUrl, function (iframeDoc) {iframeBody = iframeDoc.body; tryToShowData() });
}

Now, imagine the same thing done with futures:

function showData(dataUrl, iframeUrl) {
  var dataFuture = requestDataFromServer(dataUrl);
  var iframeBodyFuture = insertIframeBody(iframeUrl);
  showDataInIframe(dataFuture.get(), iframeBodyFuture.get());
}

Again, these two examples are not semantically equivalent -- notably there's no blocking in the first example.  Now let's imagine that we had a way to turn an ordinary function into a new function which takes futures as arguments and which returns a future in turn.  As soon as all the future arguments became available, the base function would be called automatically -- and once the base function completed, its result would be accessible through the future returned earlier.  I'll call this capability "callAsap": call a function as soon as possible after all of its future arguments become available.  Using callAsap(), the previous example might be rewritten as:

function showData(dataUrl, iframeUrl) {
  var dataFuture = requestDataFromServer(dataUrl);
  var iframeBodyFuture = insertIframeBody(iframeUrl);
  showDataInIframe.callAsap(dataFuture, iframeBodyFuture);
}

In this case we don't care about the return value for showDataInFrame.  This example is much closer in behavior to the earlier callback-based example.  In fact, the callAsap() method would be implemented with callbacks underneath, but they would all be nicely abstracted away under the hood.

One of the nice things about callAsap() is that it can nicely handle cases where you are waiting on more than one future.  Imagine that you've asynchronously requested data from two different servers:

function showData(dataUrl1, dataUrl2, iframeUrl) {
    var dataFuture1 = requestDataFromServer(dataUrl1);
    var dataFuture2 = requestDataFromServer(dataUrl2);
    showDataInIframe.callAsap(dataFuture1, dataFuture2, iframeBodyFuture);
}

This segues nicely into the next topic: Arrays of futures.


Arrays of futures

Imagine if you have not one, or two, or three futures, but rather an arbitrary number of futures.  What we'd really like to have is a way to take an array of futures and produce from it a single future for an array of concrete values.  Something like:

function showData(dataUrlArray, iframeUrls) {

  // The "dataFutureArray" is a concrete array of futures.
  var dataFutureArray = requestDataFromServers(dataUrlArray);

  // The "dataArrayFuture" is a future for a concrete array of concrete values.
  var dataArrayFuture =
Future.createArrayFuture(dataFutureArray);

  showDataInIframe.callAsap(dataArrayFuture, iframeBodyFuture);
}

What this example might look like rewritten in callback style is left as an exercise to the reader.


An advanced example

OK, now for a more elaborate example.  Imagine a function which retrieves the first page of Google search results for a particular query, and then goes through and re-orders the results based on its own ranking system.  Furthermore, imagine that this ranking is computed based on the contents of each web page.  We'll need to to make requests to many different servers for many different web pages.  This will be fastest if we issue all the requests at once.

function search(query) {

  // Take a concrete search result and return a future to a
  // [searchResult, ranking] pair.

  function requestWebPageAndRanking(searchResult) {
    var webPageFuture = requestWebPage(searchResult.url);
    var rankingFuture = computeRankingFromContent.callAsap(webPageFuture);
    return Future.createArrayFuture([webPageFuture, relevanceFuture]);

  }

  // Take a concrete array of search results and return a future to
  // an array of [searchResult, ranking] pairs, sorted by ranking.

  function requestSearchResultsSortedByRanking(searchResultArray) {

    var
rankingArrayFuture = Future.createArrayFuture(
      [requestWebPageAndRanking(searchResult) for (searchResult in searchResultArray)]
    );
    return sortArraysByKeyIndex.callAsap(
rankingArrayFuture, 1);
  }

  // Request search results, re-rank them, and then display them.
  var searchResultArrayFuture = requestGoogleResults(query);
  var sortedRankingArrayFuture =
     
requestSearchResultsSortedByRanking.callAsap(searchResultArrayFuture);
  showSearchResults
.callAsap(sortedRankingArrayFuture);
}

In all fairness, this is not as simple as a synchronous blocking implementation.  Keeping your arrays of futures and futures of arrays straight is a little bit taxing.  Imagine what a callback model might look like, however, with callbacks inside callbacks.  One advantage of using futures is that you can often write traditional blocking code and then in straightforward fashion translate that code into asynchronous code using futures.

 

Notes, in no particular order

  • The examples may look like JavaScript, but they are, in fact, pseudo-code.  The implementation of some of the helper methods, psuedo-code or otherwise, are left to the imagination.
  • I have completely glossed over error handling, including such interesting topics as exception tunneling, fallback values (nulls, empty arrays, NullObjects), not to mention timeouts and retries.  If this sound scary, it's because error handling in any kind of async code is a difficult topic.  Futures don't make the situation any worse, and might make it better.
  • The name "callAsap" is my invention, although I'm certain the underlying idea has been invented independently many times.  Also note that callAsap() and Future.createArrayFuture() are fundamentally quite similar.
  • Java futures (java.util.concurrent.future) use a blocking get() method like the one in the first example.  I don't actually know how you could do a blocking get in conventional single-threaded JavaScript, which is the whole genesis of callAsap().  Practical JavaScript futures need to be "listenable futures" which raise events when they resolve.  The methods callAsap() and Future.createArrayFuture() can then be implemented using this capability.  Client code can then use these methods to avoid writing explicit callbacks.
  • The re-ranking Google search results example is contrived, but it's based on a similar project I did a few years ago.  In that project I used callbacks, and it was quite painful.

Comments [14]

Improving the Firebug UI

 

Refactoring the Firebug UI

My main project for the last few weeks has been doing some Firebug UI work that I’ve been thinking about for a while.  Since I’ve just been moving UI elements around (to make the layout more logical), I’ve been referring to this effort as “UI refactoring”.

So here’s the deal.  It’s not enough that I think this redesign is an improvement, or even that the Firebug working group has been supportive.  We need to know what you, the Firebug user, think.

Before I get started, I should let you know that I’ve been working on the Firebug 1.4 branch, which is still undergoing active development.  The changes I’m proposing are fairly simple in the sense that they are really only a reorganization of existing UI elements.  However, if you have not yet seen 1.4, be aware that there are other significant UI changes, notably John J. Barton’s work on the activation UI, kpdecker’s multi-file search capability, and Hans Hillen’s work on accessibility.

What’s wrong with the current Firebug UI?

The basic UI layout for Firebug today consists of a toolbar across the top, a main “panel bar” underneath, and an optional “side panel bar” to the right.  Each panel bar consists of a set of tabbed panels, only one of which is visible at a time.

 

This is a simple design, and seems pretty logical.  There’s a problem, however.  The contents of the toolbar can change substantially depending on which panel is selected in the main panel bar.  For some panels this is maybe not such a big deal.  At the other extreme, consider the Net panel.  When the Net Panel is selected, it adds seven buttons to the toolbar which control what information is displayed inside the Net panel’s content area.

For me, using these buttons, with this placement, feels even weirder than the screenshot looks.  They would feel much more natural if they were adjacent to the content area that they affect.

Furthermore, the side panel bar is only visible when either the HTML tab or the Script tab is selected.  And, of course, it’s a different set of panels that show up in the side panel bar depending on whether it’s the HTML panel, or the Script panel.  Logically, you could think of the HTML panel as having a smaller panel bar embedded inside it which in turn contains several sub-panels specific to the HTML view.  You can think of the Script panel similarly.  The other panels simply don’t have any sub-panels they need to display.

Basically, the problem is that clicking a tab changes not only the main panel below the tab strip, but also the toolbar above it, and oftentimes the side panel bar to the right as well.  You click on a tab, and the whole UI mutates around it.  Even though the current UI layout makes superficial sense, I contend that the toolbar – or at least a big chunk of it – belongs inside the main panel bar.  I also think you can make an argument that the side panel bar, when it appears, should look like it’s inside the currently selected panel.

Another way to think of it: The tabs – Console, HTML, CSS, Script, DOM, and Net – should appear at the top of the Firebug UI where the panel-specific toolbar elements appear now.  Since these main panels are the major organizing principle of the Firebug UI, it makes sense that they should be more prominent.

I’m clearly not the first person to come to this conclusion since Firebug Issue 222 makes a similar argument.

This is the layout I have working now.  I’ve been referring to this as the “tabs-on-top” layout.

In this design, not all of the toolbar has been relocated.  The main Firebug menu that hangs off the Firebug button is in the top-left just as it always has, and the search elements and Firebug window control elements are still at the top right.  Although the side panel bar doesn’t really appear to be inside the main panel, it does at least appear subservient. 

There are some smaller changes as well.  Notably the tabs are now “stand-up” style –

, rather than “hanging” style –
.

The handling of the main panel Options button and the Inspect button still leave something to be desired.  Nevertheless, I think this is a more logical layout, although you probably have to use it to really appreciate the improvement.

What now?

As I mentioned above, you really need to try the out the new layout to see if it’s really does work better.  To that end, I’ve attached an experimental version of the Firebug extension to the post, so you can download it and try it out.  I’ve tested it fairly thoroughly on Windows and to a lesser extent on Mac and Linux.  Also, since it’s built on top of the 1.4 branch, which is still under active development, you probably won’t want to leave it installed for too long.  However, it should be good enough for you to take it for a test drive.

 

Click here to download:
firebug-1.4XJ.0a12-tabs-v5.xpi (513 KB)

Comments [19]

Green Trees, Information Radiators, and Photo Frames

One of the first things you learn about as a Mozilla developer is Tinderbox, Mozilla's automated build and test system.  Mozilla's Tinderbox hosts a number of "trees", specific software projects that are built and tested independently.  Tinderbox has a page that displays the current status of whatever tree you might be interested in.   For example, the display for the Firefox 3.1 tree is here.  If everything is wonderful, the top of each column on the web page is green, indicating that the most recent build and test run on that machine was successful.  This is called a "green tree".

In reality, the tree is rarely one hundred percent green.  Developers with patches ready for checkin (ready to "land" in Mozilla parlance) are constantly checking to see if the tree is green.  This can get old.  Justin Dolske, in a fit of Wallian laziness, developed isthetreegreen.com to simplify the process.

It's an unfortunate fact that lately the tree has rarely been green and it's become more a matter of "Is the tree green enough?".  I discovered that if I had the tree status page open in Firefox, I could essentially see the entire width of page if I stretched the window to the full width of my screen and made the text as small as possible.  This way I could get a feel for how green the tree was at a glance.

The problem with this approach is that most of the time the browser window was obscured by other windows.  The other problem was that I kept accidentally clicking on it, or accidentally opening other pages in the really wide window, or hiding it and forgetting about it.  It would have worked better if I had a second monitor configured, but frankly, if I had a second monitor I'd want to use all the screen real estate for active work anyway.

What I'm really looking for is some kind of ambient information display.  I want to be able to catch a high level view of the tree status with just a glance, but without it being in my way as I try to work.  This is similar to Alistair Cockburn's concept of an Information Radiator.  That's it, I want my own personal information radiator.

Then the other day, I noticed digital photo frames at Fred Meyer.  These have been around for awhile, but it's the first time I noticed them on the shelves at the local discount market (most likely because I haven't been paying attention).  I thought, hey wouldn't that be cool if you could set one up to display the tree?  But are there any that can run a web browser?

It turns out there is.  Sony has a digital photo frame that runs Opera.  However, it looks like it's only available in Japan.  On the other hand, Samsung now has photo frames that support UbiSync, which is their USB video technology.  So technically, you'd just be using photo frames as a more less standard multiple monitor setup.  The upside is that UbiSync doesn't require video card support, and you can daisy chain multiple UbiSync photo frames -- apparently as many as five or six.  An UbiSync monitor doesn't have the raw performance of a regular monitor running off of a video card, but for displaying slow-changing information like the Tinderbox tree, it would be plenty fast enough.  Of course if you were going to go this route, it would probably make sense to get your hands on a Samsung 22 inch UbiSync monitor, rather than one of the 10 inch photo frames.

Comments [7]

Creating Icons with JavaScript and SVG

I'm a programmer, not an artist.  Nevertheless on occasion I find myself thinking about icons.  Worse yet, sometimes I find myself thinking about designing new icons from scratch.  I've got neither the patience nor the skill to build an icon one pixel at a time.  Instead, I've been using JavaScript to dynamically build icons in SVG.  This may be the hard way to build a single icon; however, if you're doing a bunch of variations on a theme, then it can be a definite win.  That's basically the situation I'm in now -- I have a basic arrow design in a variety of orientations and with a couple of possible decorations.  I'm also generating icons in a range of sizes since I don't what the optimal size will be.

I'm not far enough along to really talk about the icon design itself.  I can, however, address one important but mundane issue with this technique, namely: How do you render SVG into a transparent PNG?  Now, if you've got a garden variety SVG file, you can simply load it into Inkscape and export it to PNG, no problem.  If, on the other hand, you've got an SVG file that contains embedded JavaScript, this won't work, since Inkscape won't run the JavaScript.

Instead I've been using a two step process where I use Firefox to run the JavaScript, and Inkscape to generate the PNG.

1. Load your SVG file (which, remember, must run some JavaScript) into Firefox.
2. Right-click and choose Select All from the context menu.
3. Right-click and choose View Selection Source from the context menu.
4. Type Ctrl-S/Cmd-S to save the SVG to a new file.
5. Load the new file into Inkscape.
6. In Inkscape, select File >> Export Bitmap

There are probably better ways of doing this, especially if you find yourself doing it repeatedly.  For example, Vlad suggests that an entirely JavaScript-based solution is possible using the <canvas> element and the drawWindow() method.  That, as they say, is left as an exercise to the reader.

Comments [7]

A better history command

The Bash history command lists your numbered command history -- all of it by default.  Other than limiting the output to the most recent N commands, it doesn't give you any real control over the output.  As a consequence I often find myself typing things like

 history | grep find

or even (I use find a lot)

 history | grep find | grep cpp

I found myself doing this so much that I eventually bit the bullet and wrote a better history command provides built in grep-like filtering.  So now I can type things like

 hist find
 hist find cpp
 hist find cpp viewsource

The last command corresponds to something like

 history | grep -i find | grep -i cpp | grep -i viewsource

which is a pain to type in full.

I've been using hist for a while now, and I've found it very useful, so I thought I'd share it in case there are other Bash users out there who might find it handy.  If you want to use it just paste the following into your .bash_profile:

 # Quick and dirty case-insensitive filtered history command.
 # "hist" ==> "history"
 # "hist foo" ==> "history | grep -i foo"
 # "hist foo bar" ==> "history | grep -i foo | grep -i bar"
 # etc.
 # Note that quotes are ignored, e.g.
 #   <<<hist "foo bar">>> is equivalent to <<<hist foo bar>>>
 hist()
 {
     HISTORYCMD="history $@"             # "foo bar" ==> "history foo bar"
     HISTORYCMD="${HISTORYCMD% }"        # "history " ==> "history" (no trailing space)
     eval "${HISTORYCMD// / | grep -i }" # "history foo bar" ==>
                                         #   "history | grep -i foo | grep -i bar"
 }

Comments [5]

A handy bash function for creating "file://" URLs

I often find myself loading test files from my local filesystem into Firefox with "file://" URLs.  Unfortunately Firefox on OS X (or at least my local build of 3.1) is maddeningly inconsistent about recognizing an argument as a filesystem path or a URL.  So for example "ffz test.html" ("ffz" is my launch script) usually opens "file:///Users/cbartley/Dev/mozilla/test.html" (which I want) but sometimes tries to open "http://www.test.html/" (which doesn't even make sense).

It seemed sensible to switch to simply supplying a full file URL on the command line so there's no confusion.  The downside is that file URLs need to be absolute and constructing an absolute file path on the fly is a pain.  Fortunately, I can make the computer do this work for me with a handy bash function.  The "fileurl" function below takes a path to a file (usually a relative path) and prints the corresponding "file://" URL for it.  So for example:
  fileurl ../test.html
might print
  file:///Users/cbartley/dev/mozilla/test.html

I can invoke my test build with something like
  ffz `fileurl ../test.html`
and have it reliably open the file every time.

I haven't yet rolled fileurl into the ffz script, but that's the logical next step.  I should also acknowledge that there may well be better ways to do this than the approach I've used -- I am no bash expert.  Finally, for all those other amateur bash programmers out there, the magical Google phrase for finding documentation on the weird things you can do with variables in bash is "variable mangling".

# Given a path to a file (relative or absolute), print a "file://" URL for
# that file.
fileurl()
{
  # Split the directory name out of the argument path.
  #   "/dir/subdir/file" ==> "/dir/subdir"
  #   "dir/subdir/file" ==> "dir/subdir"
  #   "subdir/file" ==> "subdir"
  #   "file" ==> "."
  TEMP="/$1"                            # Hack: Prepend a slash so there's at least one
  TEMP="${TEMP%/*}"                     # Chop off the trailing "/file"
  TEMP="${TEMP#/}"                      # Remove the leading slash if it's stil there
  DIRNAME="${TEMP:-.}"                  # If DIRNAME is empty, set it to "."

    # Get the base file name from the argument path.
  BASENAME="${1##*/}"                   # Remove everything up to the last slash, inclusive

    # Convert the directory name to an absolute path.
  ABSDIRNAME=$(cd "$DIRNAME"; pwd)

    # Echo the file URL built from the components.
  echo "file://$ABSDIRNAME/$BASENAME"
}

Comments [12]

Firebug UI: Tabs on the Top

In a previous post I explored the idea of moving Firebug's main panel bar tabs to the bottom of the UI.  One of my teammates pointed out that a common scenario in Firebug is to select a tab and then immediately click in the toolbar to make a panel specific adjustment.  For example, it's common to click on the Script tab and then to click the files drop down to select a specific JavaScript file.  With the current arrangement, the toolbar and the panel tabs are close together regardless of Firebug's window size.  If Firebug's window is opened to a large size, for example showing 40 or 50 lines of source code, then this two step usage scenario is going to be rather inconvenient for the user.

If this is a common scenario (and I suspect that it is), then this argues for a tabs-on-top design, which is what I'm going to look at in this post. 

There's a link to the prototype at the end of the post if you want to try it out.  In the meantime, here's a screenshot.


A screenshot of the Firebug UI with panel tabs at the top.  The Script panel is selected.

One of my goals with the previous tabs-on-the-bottom design was to reduce the "busyness" of having the toolbar and main panel tabs right next to each other.  This design doesn't do much to address the busyness angle, but it still seems cleaner than the current Firebug layout.  For example, in this design the tab strip for the main panel bar is at the top of Firebug's UI, and all it has on it is tabs, and the tabs are largely static -- the selected tab can change, but that's it.  It's a much simpler UI element than the toolbar.

The toolbar is placed such that it appears to be inside the currently selected panel, which seems logical since so many of the toolbar controls are dependent on which panel that is.  In this particular variation, the toolbar extends all the way across the window, so I call it the "long toolbar" version.  One negative of this design is that the side panel looses a line of vertical real estate.

There's another advantage of having the tabs on top.  In Firebug, the major functional units correspond to individual panels in the main panel bar.  In the tabs-on-top layout, the tabs for these panels is the most obvious thing you see.  I think that's probably a good thing.


Moving the Search Box


A mockup with the Search Box and window controls moved from the toolbar to the tab strip.

One possible variation on the tabs-on-top layout is to move the Search Box and adjacent window buttons from the toolbar to the right end of the tab strip.  Since the Search Box and window buttons don't change with the active panel, it makes sense to pull them "out" of the panel.  This clutters up the tab strip a little bit, but as long as there's some reasonable amount of blank space between the rightmost tab and the search box, it doesn't really seem to hurt that much.  One advantage is that it substantially reduces the clutter on the toolbar and another is that it frees up a lot of space for the "object path", which, unfortunately, you can't see in this screenshot.  (In the Script panel the object path is the call stack in horizontal layout.  In the HTML panel, the object path is the HTML containment hierarchy.)


The short toolbar version.

With the Search Box and window controls on the tab strip, we can also do a "short toolbar" layout as mentioned above.  In this layout, the toolbar is only as long as the left sub-panel.  The side panel bar (containing the Watch, Stack, and Breakpoints panels) now tops out just below the tab strip, reclaiming that line of vertical real estate that we'd lost in the first two layouts.  Of course the short toolbar reduces area available to the object path by quite a bit.

Conclusion

I think putting the tabs on top and above the toolbar makes for a much nicer UI.  Although I think my earlier tabs-on-the-bottom UI offered some advantage by completely separating the toolbar and the tab strip, I think the tabs-on-top design offers some clear advantages.

  • The tabs are the major organizational principle in the Firebug UI and putting them on top makes them stand out as the most prominent UI element. 
  • The toolbar appears like it belongs to the current tab page, almost like you're tabbing between different toolbars as well as different panels.  This seems logical since the toolbar changes with the panel anyway (The ever present Firebug-icon-menu and Inspect button do muddy the water a bit, though).
  • Selecting a tab and then selecting something on the toolbar (e.g. selecting the Script tab and then selecting a JavaScript file from the drop down) is still convenient.  It feels a little more natural to select something on the tab strip and then move down one line to carry out the next step.  In the current UI with the toolbar on top, the flow is up rather than down.
I haven't tested it in a prototype yet, but after looking at the mockups, I think moving the search box and window controls to the right end of the tab strip is a good idea.  I'm less certain about whether the long toolbar or the short toolbar is the best approach, although I feel like the short toolbar wins on simple aesthetics.

Try it out
A link to the Firebug "tabs-on-top" prototype extension is at the bottom of this post.  The standard disclaimer applies.  It's prototype code built on 1.3 pre-release code, so although it's OK to play around with, you probably don't want to leave it installed.

Click here to download:
firebug-1.3-tabs-on-top.xpi (456 KB)

Comments [0]

A Firebug User Interface Proposal

One of my biggest complaints about Firebug is the way its tabbed UI works.  Firebug organizes its features into six major functional units: Console, HTML, CSS, Script, DOM, and Net.  Each unit gets a "panel" and these panels are organized in a tabbed display called a "panel bar".  There's also a smaller panel bar that sometimes appears to the right of the main panel bar depending on which primary panel is selected.  The main Firebug toolbar appears just above the panel bars.  Below is a screenshot from Firebug and an annotated version of the same screenshot.

A screenshot from Firebug 1.2.1.  The Script panel is currently selected.


The same screenshot as above with the major UI components labeled.

One of the things I don't like about the current UI is just how busy it looks.  The toolbar is already pretty complex, and it's stacked right on top of the tabs for the two panel bars.  That's not the biggest problem however.  Take a look at this next screenshot.

A screenshot from Firebug 1.2.1.  The HTML panel is currently selected.

In this screenshot, the HTML panel has been selected.  Look carefully at the toolbar, and compare it with the first screenshot above where the Script panel was selected.  The Inspect button and the find textbox are the same, but everything in between has changed.  Now look at the side panel bar.  That's right, it's completely different.  Changing panels in the main panel bar essentially causes the whole Firebug UI to change, not just the main panel.

I think you can make a case that the toolbar and the side panel bar belong inside the current panel since they are so dependent on which panel that is.  The argument is stronger for the side panel bar since it is completely dependent on the main panel bar.  The argument is weaker for the toolbar since the toolbar doesn't completely change, but I think you can still make a case there.

Tabs on the bottom

So I have two problems that I'd like to solve.  I'd like to make the user interface less "busy", especially with regard to the toolbar.  I'd also like to promote the illusion that both the toolbar and the side panel bar are inside the currently selected main panel, since both those UI elements are so dependent on which panel that is.

I've built an experimental variant of Firebug to test out an alternative UI that I think addresses these issues.

To address the busyness issue I've moved the main panel tabs from the top of the panel bar to the bottom.  This also helps differentiate the main panel bar from the side panel bar, where I've retained the tabs on the top.  I think this helps a little bit with the illusion that the side panel bar is actually inside the main panel since the two panel bars now look different.  Then I've tweaked the UI so that the main panel bar tabs appear to extend all the way across the window and all the way around both panels and the toolbar.  This effect is perhaps more subtle than I'd like, but it still feels like an improvement.

Below is a screenshot of this alternative UI.

A screenshot from an experimental version of Firebug with the main panel bar tabs on the bottom.

It might also be useful to evaluate the design where the main panel bar tabs are moved above the toolbar.  This won't do anything for the busyness issue but it might make a stronger statement that the toolbar is dependent upon the currently selected panel.  (Firebug issue 222 suggests making exactly this change.)

Take it for a spin
I've attached the XPI file for my experimental Firebug build so you can try it out yourself.  That will give you a much better feel for the proposed change than just looking at static screenshots.  The experimental build is probably a little bit buggy, both due to my changes and the fact that it's built on Firebug 1.3 pre-release code.  It should be OK to take for a test-drive, but you probably don't want to leave it installed for a prolonged period of time.

Click here to download:
firebug-1.3XJ.0a2-experimental.xpi (456 KB)

Comments [0]

About