Friday, 21 January 2011

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.

8 comments:

  1. Some of the front end code that Google's tools produce is very poo and this isn't the only thing.

    Be relieved you don't do .Net. Some of the front-end stuff Visual Studio produces is *revolting* which is why I always do most of it manually when I can. Mind you, I haven't been using the more recent versions of VS so maybe they've improved it some.

    (This is Sophie btw, I realise the name 'Me' is highly ambiguous!)

    ReplyDelete
  2. @Sophie! Aha! Suddenly all makes sense :) Yes in my experience lots of IDEs generate crappy code. The thing about GWT is you don't have any control over it, you write it in Java and then it creates the HTML from that. It's one step removed from your ability to manually tweak it. When I'm writing JSPs I always did it by hand but you don't get that option with GWT.

    ReplyDelete
  3. Nice Article, saved my ass big time, vertical panel wasn't rendering widgets after certain level of nesting.
    Thanks

    ReplyDelete
  4. Thanks for the tip! I just started using GWT recently, and your advise has made me really think about which Layouts to use.

    Thanks!
    Mick

    ReplyDelete
  5. Thanks for nice article. I'm too a fresh GWT developer and VerticalPanel was first natural choice until I found this post.

    Peter

    ReplyDelete
    Replies
    1. No problem! I wrote it because that's exactly the same thing we did.

      Delete
  6. +1. I can't believe how many layout problems you just solved. I had tried a lot of different layouts - down to LayoutPanel and was still having issues. TY TY TY.

    ReplyDelete