GWT: Why VerticalPanel is Evil

At LMAX we adopted Google Web Toolkit pretty early on.  One of the motivations for using it was so we only had to worry about recruiting Java guys, and then we could all work on every part of the application including the web UI.  Sure, you can learn a bunch of different skills if you want to, but it reduced context-switching and kept the skill set we were hiring for to a nice short list.


The problem is that GWT does a very nice job of pretending to be Java whilst actually compiling down to HTML and JavaScript.  If you don’t have some understanding of the end result (the DOM the browser is going to be rendering) it’s going to be hard to get the performance you need from a low-latency trading application.

My number one bug-bear with GWT is VerticalPanel.  To the uninitiated developer, this seems like the sort of thing that will be useful everywhere.  You often want stuff stacked on top of each other - think menus, lists, the layout of a dialog.  What is not obvious is that it uses tables for layout under the covers, and I’ve mentioned in the past that Tables Should Not Be Used For Layout.

A much less obvious way of getting the same result with (usually) no extra effort is to use FlowPanel.  This is rendered as a div, and most of the time the elements that get inserted into it will render in a vertical stack.

VerticalPanel Code
VerticalPanel panel = new VerticalPanel();
panel.add(/* your widget /);
panel.add(/
your second widget /);
VerticalPanel Rendered As HTML
<table>
<tbody>
<tr>
<td>
<!– your widget here –>
</td>
<tr>
<tr>
<td>
<!– your second widget here –>
</td>
<tr>
</tbody>
<table>
FlowPanel Code
FlowPanel panel = new FlowPanel();
panel.add(/
your widget /);
panel.add(/
your second widget */);
FlowPanel Rendered As HTML
<div>
<!– your widget here –>
<!– your second widget here –>
</div>
You can see that the DOM generated for a very similar-looking 3 lines of code is much much smaller for FlowPanel.

Who Cares?
Right, but we’re only talking about a few more elements, and browsers are pretty smart about optimising these things.  Right?

Maybe.  But if you use VerticalPanel for all your containers, for every box which needs to be a slightly different colour, for every place you want to change the alignment slightly, things get very big very fast.  This is an example of real code from an early prototype, where we had several nested panels (not unheard of if you’ve got a complex dialog box with lots of elements in it.  Like, say, a deal ticket).  And I’ve stripped out a lot of the table attributes that made this even more heinous:

<table>
<tbody>
<tr>
<td align=“left”>
<table id=“panel1”>
<tbody>
<tr>
<td align=“left” style=“vertical-align: top;”>
<table class=“orders-input”>
<tbody>
<tr>
<td align=“left”>
<table class=“row”>
<tbody>
<tr>
<td align=“left”>
<table id=“container”>
<tbody>
<tr>
<table id=“panel2”>
<tbody>
<tr>
<td align=“left”>
<table class=“controls”>
<tbody>
<tr>
<td align=“left”>
<!– widget –>

For every table element and associated elements (tbody, tr, td), you would get a single div element instead if you simply replace every instance of VerticalPanel in this stack with a FlowPanel.

<div>
<div id=“panel1”>
<div class=“orders-input”>
<div class=“row”>
<div id=“container”>
<div id=“panel2”>
<div class=“controls”>
<!– widget –>

See? Much nicer.

This is exactly what we did do, and we saw a noticeable speed improvement across all browsers - noticeable to a real user, not just some millisecond improvement on a performance test.  Mind you, users’ brains are amazing things and your system has to react in less than 0.1 seconds for a user to perceive it as instantaneous.  So even in a browser, every millisecond counts.

In addition to improved performance, you get a nice bonus: now the layout is no longer controlled by tables, you can really easily shove stuff around and make things look pretty with the clever use of CSS.  If you’re really lucky, you can chuck that stuff over to your designers and not have to do another GWT compile when someone wants to move things 3 pixels to the left.  Which they will.