 |
XML to Swing and the Gradual API
Posted by joshy on December 07, 2004 at 06:15 AM | Comments (15)
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?
Bookmark blog post: del.icio.us Digg DZone Furl Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment
-
Have you looked at SwiXML? It looks nearly identical to your ad hoc grammar and is quite easy to use. Before your gradually roll your own XUL dialect, you really ought to give it a go.
Posted by: javaben on December 07, 2004 at 08:14 AM
-
Hi Daniel,
Great post. It's often tempting to come up with a grand-unified solution which addresses problems
with an existing system by completely replacing it.
However, this strategy often results in a large number of incompatible solutions to the same
problem - witness the scores of Java Web frameworks. I hope that people take your advice and try
to gradually improve existing systems rather than reinventing the wheel.
The leafcutter project fits your description of a gradual API.
It allows you to gradually replace proprietary code with calls to equivalent Ant tasks (which tend to be more functional,
better tested, and more platform-independent). It can also be used to replace Ant scripts with Java code (which tends to be more
flexible and reusable, see your point about XML programming languages!).
The familiarity requirement is satisfied; leafcutter uses a close analogue of the Ant syntax. It also automates boring tasks, like writing large
Ant buildfiles and writing filesystem-manipulating code in Java.
Posted by: martinpllu on December 07, 2004 at 01:05 PM
-
I've written a small class to parse an XML Element (using JDOM) and return GridBagConstraints, which allows you to seperate out layout data from the code.
For example, using :
<gridbaglayout>
<component name="x.label">
<grid x="0" y="0" width="1" height="1" />
<resize fill="NONE" anchor="EAST" weightx="0" weighty="0.0" />
<insets top="2" left="2" right="2" bottom="2" />
<ipad x="0" y="0" />
</component>
<component name="x.field">
....
....
</component>
</gridbaglayout>
You initialise a parser by :
GridBagParser parser = new GridBagParser(Element e);
and use it by
gridbag.setConstraints(new JLabel("X coordinate:"), parser.parse("x.label"));
At the moment, I'm currently working to build this into an extension of GridBagLayout and to write a DTD for the layout.
Posted by: luggypm on December 08, 2004 at 01:42 AM
-
I won't mention any names, but I just had this experience while working on what I thought would be a nice and easy JTree implementation. As the requirements expanded, I found I had to remove all the wrapper code and go back to plain old swing. In the end, the plain old swing was a lot easier to maintain and customize.
Maybe it's just me, and it probably is, but the whole problem I have with these 'wrapper' api's is maintainance. At some point, if your application grows to any level of complication, then most of these nice cutesy wrappers will hit a wall, and then they're not so cutesy and nice anymore.
Posted by: marke on December 08, 2004 at 08:59 AM
-
Most of GuiBuilders are run time, so form will be build runtime with all side affects, like you have to carry additional JAR, user can change your xml form without your consent, and so.
An only one solution I have seen so far is UIBuilder.
It generates a base class from given XML (in a build time), after you extend this generated class and add your business logic. So you are not depend on any other libraries, and with a time you still can maintain your code even when library will get obsolete.
So I belive that GUI code generation is a way to go, instead of runtime GUI creation.
Posted by: ivanlatysh on December 08, 2004 at 10:13 AM
-
ivanlatysh: UIBuilder is not the only one, UICompiler does this same thing; convert from XML to a classfile on build-time.
In fact; all the ideas in this blog are present in UICompiler, we just don't suggest you write the XML yourself, but use an excellent GUI builder for that.
The concept of gradual APIs is a really powerful one, and one I fully agree and fully practice in my projects as well.
Posted by: zander on December 08, 2004 at 12:51 PM
-
Hi zander.
My mistake, I mean UICompiler.
I support an idea with all my 5 hands.
And I think that we can continue this discussion into another topic. User preference manager that would save/restore widgets states, sizes, etc.
Posted by: ivanlatysh on December 08, 2004 at 01:09 PM
-
Hmm... millions of other XML UI building frameworks not being used, and you think the problem is... what?
The problem is that XML is a horrible language to do programming in. Its hard to read, verbose in a bad way (ie the extra verbosity doesn't add extra useful information), and missing all the good bits of a modern programming language.
A good UI is going to make *heavy* use of a couple of the features which are conspicuously lacking (or so difficult you wish they were missing) in XML. One of those would be subclassing.
For instance, your whole quit button thing is bad, evil, and wrong (tm). That sounds harsh, but dude, its not '97 anymore. We *should not* be writing our UIs like that anymore.
How should we be doing it? Using the magic of subclassing, make yourself a subclass of javax.swing.AbstractAction. Now, anywhere you need to use a quit button, just pull out that class and slap it in. Compare this with the reuse potential of the quit button xml... practically none. Oh sure, you might be able to (if you can find it) cut and paste the xml fragment out of the definition. Problem is, that hasn't really won you much. You still need to write the code for the quit method.
Another great thing the Action has going for it is that you can use it in more than one place at the same time. Need a quit button? Just pass your Action into its constructor. Need a quit item in the menu? Just pass the same Action into the constructor for your JMenuItem. Now if you want to disable quitting, just disable the ction, and both the button and the menu item will be disabled. Fantastic.
What about layouts? Isn't that an area where XML should be good? After all, HTML is a layout language. Turns out the answer is *still* no. The way to do layouts is to go back to the magic of subclassing.
Your arty design people demand a gui where the labels are above (or below) the component they label? No problem, just whip up a panel/layout compound class that does that for you, and apply liberally. Labels are always in a strange font/colour/boldness combination? Just use ... you guessed it ... the magic of subclassing to whip up your very own label.
I note that you could do something like the way Struts lets you define hierarchies of tiles, eg provide a default button XML, and then put the properties you want to override, that would be kind of subclassy
From a user of frameworks point of view, XML is a problem. Everybody and their dog wants to put out their framework based on XML because that lets them avoid a lot of tough decisions (mainly around configuration), such as providing intelligent defaults. But by not providing good defaults, the user has to spend a lot of time configuring the framework before they can actually do anything, let alone anything useful. This is a very poor out of the box experience. It also puts a lot of hurdles in the way of the programmer, so that even after they've invested the time to learn the ins and outs of that frameworks configuration language, its still hard work to get anything done.
Posted by: rickcarson on December 08, 2004 at 03:57 PM
-
check out sulu at http://sulu.sourceforge.net. Its an LGPL implementation of Mozilla XUL for java
Posted by: sonwh98 on December 08, 2004 at 07:04 PM
-
The advantage to this sort of approach is code higene. If you don't want users changing the xml, sign it with a hash or something. Also your XML could just be a constant in a class or an oddly codified file.. a good API should let you pass in a Reader or InputStream.
Posted by: dog on December 08, 2004 at 09:27 PM
-
You might also look at XUI (http://xui.sourceforge.net) that does much of what you recommend and then some more.
Posted by: luano on December 09, 2004 at 12:13 AM
-
I have to agree with most posts. I was trying to use Swixml and ran into MANY hurdles with doing anything advanced with components. It is also very cumbersome in my opinion to try to mix swixml (or other xml UI attempts) and more advanced Swing code. Even worse, imagine the poor sap that has to maintain my code and has not yet figured out Swixml. You can bring in advanced Swing developers with no Swixml experience, and while it is fairly easy to understand, it is much more time consuming to learn and then dig in to the code and figure out how someone used it.
It is also the fact that there are so many now, that it's difficult to consider which way to go. Swixml seems very good, and I suppose the XUI from netscape and whoever else is becoming a defacto, but there are still too many people that want to roll their own creation. Makes it difficult if I learned XUI and Swixml already, and now I gotta learn yet another which in the end does nothing more than what every other one does.. it kind of gets annoying, fast.
All of these are nothing more than ways of trying to "ease" the GUI experience that apparently Swing doesn't provide. It's true, there are some things that Swing is not good at making easy. But in all my years of coding, I have not found ANY GUI that was "easy". MFC and win32API sure as heck wasn't. GTK+ was not exactly easy to work with. Even drag/drop GUI's with property editors are not the best solution because of how much bloat they put in and how limited you are with them. To me, Swing has been the easiest to work with, with the exception of learning about layout managers, and dealing with the event dispatch thread and threading. But once you learn these, the rest is pretty simple. Oh, yeah, 2D/3D graphics are not easy, but then I am no math major ;)
Posted by: buckman1 on December 12, 2004 at 12:23 PM
-
I feel sorry for Buckman and other who did not get out of Swixml what they originally had expected and think it may be helpful to explain why and what-for Swixml was created.
Two years ago we were looking into converting a Web application into a Java based rich client application but didn't like to write all that Swing code needed to setup the initial UI. We found that even HTML/JavaScript did a better job separating layout from action logic than most of the Swing code we looked at. After evaluating Thinlet and some other XUL approaches I started developing Swixml.
Just like nib files for OSX, Swixml descriptors allow us to build an initial GUI and link it with Actions (or ActionHandlers) written in Java, therefore separating the layout for the action logic.
Buckman mentions having difficulties mixing Swixml with more advanced Swing-code, which I find hard to believe. Swixml instantiates Swing widgets like JPanels, JButtons, etc. and puts them into an hierarchy. After this initial step, Swixml's work is basically done. The widgets can be accessed directly or by looking up references in a map etc.
"..imagine the poor sap that has to maintain my code and has not yet figured out Swixml.." Well, Swixml was created to make maintenance of Swing Code easier. Many developers with an HTML background pick up Swixml in the matter of hours. The number of lines of (swing related-) code that needs to be written and maintained is reduced significantly. But don't take my word for it, read what other developers like Rick Jelliffe, CTO of Topologi are saying: http://www.swixml.org/opinion.html
Posted by: wolfpaulus on December 27, 2004 at 12:44 PM
-
Where can I get the java code?
.V
Posted by: netsql on February 03, 2005 at 03:21 PM
-
Check out XAMJ, a language deployed on an XML UI Browser/Platform. It does away with Javascript -- uses Java instead.
Posted by: xamjadmin on August 25, 2005 at 11:28 AM
|