Skip to main content

XML to Swing and the Gradual API

Posted by joshy on December 7, 2004 at 6:15 AM PST

I know it's been a while since I've posted, and sadly it's going to be a while until I do again. Work, my opensource projects, and my book are keeping me slammed. I've lots of good stuff cooking, so stay tuned.

I would like to mention one thing. I've been thinking a lot about APIs. For any given task there seem to be a great many APIs that solve it, especially in the opensource world. And yet so few get used. Great technology but none of it ever matures, and even when it does it takes ages to see widespread adoption.

I think the problem is that when we come up with new technology we create it to work in an ideal world, always forgetting that most developers have to deal with legacy code, old data, and ancient requirements. Its very difficult to adopt a new solution if the solution requires you to change everything you do all at once. I think the most sucessful APIs are ones that you can adopt gradually. They let you use just the parts you need and nothing more. They help you with the boring parts and let you focus on the good stuff.

Let me show you the example that got me thinking along this road.

There are a slew of XML languages out there for building Swing GUIs. Tons! Metric Tonnes!! And yet few get used. Most of these systems require you to convert a large portion of your program over. Even when you can use it just one part of the program you still have to redesign your GUI bindings, move your event handlers, etc. There are new interfaces to be implemented. Classes to initalize. And once that's done you are locked in to that language, which may make long term maintainence a headache.

Here is a simple XML language that solves most of these problems and I think highlights what I've learned over the years about writing sucessful APIs (mostly by writing lots of unsucessful ones)

This creates a panel with two buttons, one with an icon.

<panel layout="row">
    <button id="quit" text="Quit" icon="quit.png"/>
    <button id="start" text="Start"/>
</panel>

Be Familiar. The markup above looks very simple but a lot of
thought went into it. The XML elements map directly to the real Swing
components and have the same names (minus the leading Js). The text and
icon fields match getter/setter methods on the real objects. The layout is
a row, which doesn't map directly to a RowLayout object but it's
conceptually unabiguous what a row is so it will still make sense to the
developer. (It's actually a BoxLayout set to X_AXIS). All pretty
straightforward because it maps directly to what the system replaces; to
what the developer is expecting.

Here's how you call it from code:

import org.joshy.guibuilder.*;

public class TestProg extends JPanel {

    public JButton quit;
    public JButton start;
   
    public static void main(String[] args) {
        TestProg prog = new TestProg();
        GuiBuilder.build("layout.xml"),prog);
        prog.createEvents();
    }
   
    public void createEvents() {       
        quit.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                System.out.println("quitting");
                System.exit(0);
            }
        });
    }
   
}

That's it. The GuiBuilder class creates all of the declared components
from the XML and assigns them through reflection to the fields in
the TestProg class. Very simple and efficent.

Automate the boring bits When you design a layout API keep it simple. Don't dynamically create
java code. Don't bind events. Just create some layout. The XML now replaces
some standard boilerplate code that I hate writing anyway. It doesn't
replace the event code that is more complicated, and usually more
important. I've taken out probably 8 lines of code and replaced it with the
one call to the GuiBuilder, but I didn't have to add anything else. I
didn't change the TestProg class to implement a new interface. It didn't
force me to do much of anything except delete unwanted code.

Be forgiving. Another feature of this system is that it's very
forgiving. Since I'm not using a compiler on the XML I don't have the same
type checking I would otherwise. It's going to be very easy to accidentally
mistype a letter or use uppercase when I meant lower. I want the parser to
be very forgiving. If I try to set a label to a button then skip it, but
print a warning. Don't bomb out. Don't continue on without an explanation.
If I type 'quit' in the xml and created a "Quit' field, or forgot to create
the field all together, then print a warning but display the component
anyway. This is also handy for prototyping since you can see your screen
before you create the code to support it. Always degrade gracefully with
descriptive warnings.

Don't make your system more complicated than it needs to be. Now
I know what you're thinking. Sure the XML is simple and elegant. That's
because you haven't done anything tricky. Here's the key: don't do
anything tricky
. The XML layer should only do layout. Avoid any
temptation to add conditionals, looping, binding to events, binding to data, scripting,
variable scoping, or any of the other advanced features that many languages
attempt. If you try to build these you will fail. (trust me, I've tried it
before). XML is for data transport and declarative knowledge. Don't make it
into a programming language. Only pain will follow. Just create easy ways
to hook into existing systems. You're building on top of a great dynamic
strongly typed programming language: Java. Use it!

After fifty years of software, integration is the single most expensive part of any system. Most companies spend more on integrating new software with their old than they do on actually purchasing the software. (In fact my entire day job is devoted to integrating new software with old). If your new software system can be integrated gradually then you've lowered the cost of transition tremendously and will see widespread adoption.

Be gradual. The xml system I've described is very gradual. You can use it for part of your program and code as normal for the rest. This design philosophy is especially important for opensource projects because they often start off quite immature and only able to do a few things. If a new user must adopt the entire system at once then the barrier to entry is high. If they can just pull in the few things that work right now, and see an immediate benefit, then they are likely to stick around and help out. Gradual adoption is the key..

I chose an XML gui layer as my example just because it's one that I see so often, and often done so wrong. Overly ambitious systems that fail miserably, despite having great technology. For a system like this I really feel that being lightweight is the key. Make it easy on your developers to get started and they will stick around for the long haul.

(and it's not that hard. I spent less time writing the code for this blog than the blog itself)

What other examples of gradual APIs do you know of? What are some you would like to see?

Related Topics >>