TurboGears vs JBoss Seam: Part 1 (of 1)

NOTE: This is a repost of an old entry from my previous blog that I wanted to preserve.

TurboGears and JBoss Seam, two web frameworks claiming to provide the tools for rapid application development. For the sake of investigating the experience of working with both (spawned from a big debate at work) I'm going to do a little comparison to examine the barrier to entry with both and the initial speed of development. I've used neither framework for anything substantial. I investigated Seam in the past on a one-day a week prototype at a previous job. I've never used Turbogears but have built small applications with Ruby on Rails and played a little bit with Django, a similar Python framework. For further background I've been coding Java for about ten years, usually in the context of web applications and mainly with struts. I've been using Python for about three years mainly for personal projects including Wuja (a Gnome application for Google Calendar integration), Rounder (an in-development open source poker server/client), and various system scripts.

I should explicitly state at the outset that I'm aware how drastically different these tools are. The world of Java is a beast unto itself, an immensely powerful and yet very large and complicated beast especially when you get into the world of JEE and EJB. TurboGears on the other hand is a lightweight Python framework with drastically less functionality. I'm comparing the two because we need to choose a direction and despite several departments involved in the debate at work, no one seems to have spent significant time with both frameworks.

Unfortunately I'm only able/willing to contribute a certain amount of time to this research. As such the following article is somewhat light on the details and heavy on my personal opinions. I accomplished only a bit of what I had hoped and barely a fraction of what each framework can do. Someday I hope to expand the article or publish a part 2 but between coding at work and on my existing personal projects, free time where I actually feel like coding is scarce.

My goal is to develop a small database schema (which ended up being a single table), setup each framework on my system, and create a small web application with a single page, just to display the contents of my table. Fedora 7 will be used for all development and deployment.

The Database Schema

My lame single table:


CREATE TABLE IF NOT EXISTS `user` (
`id` int(10) unsigned NOT NULL auto_increment,
`login` varchar(25) NOT NULL,
`password` varchar(256) NOT NULL,
`firstName` varchar(25) default NULL,
`lastName` varchar(25) default NULL,
`phone` varchar(25) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;

Turbogears

Installation

While packaged for Fedora, the TG website recommends using their tgsetup.py script for installation which will pull down the more current 1.0.3 release. Script executed within a couple minutes without incident.

Database Connectivity

TG installation instructions links to instructions for working with three common open source databases, in my case I'm using MySQL. On Fedora 7 this can be installed with:

yum install MySQL-python

Creating a Project

TG's 20 Minutes Wiki seems to be the preferred initial tutorial, also available as a screencast similar to Ruby on Rails. (although ultimately I found this tutorial much more useful)


(dev@kramer)[~/src/tg-vs-seam] % tg-admin quickstart

Enter project name: trogdor

Enter package name [trogdor]: trogdor

Do you need Identity (usernames/passwords) in this project? [no] no

As promised after executing tg-admin quickstart I now have a trogdor directory with a blank canvas application. A start-trogdor.py script has been created in the root of the application directory and fires up the skeleton application in about 5 seconds. Visiting http://localhost:8080 shows me:

It took about 20 minutes of setup to get to this point. Project directory contains just 656kb of data.

At this point I configured my database connectivity in trogdor/dev.cfg and restarted the skeleton application, which they claim will be one of the few times when you're actually required to restart.

Listing Users

The TG tutorial references SQLObject, an ORM library for Python. TG also supports the more feature rich SQLAlchemy, but judging from their comparison of the two it sounds like SQLObject will be a little easier and a little better supported at this time. Despite the fact that I'm anxious to play with SQLAlchemy, I'll stick with SQLObject for now.

I set out to define a simple model representation of my “user” table. TG offers a very powerful management console accessible by running tg-admin toolbox. This presents you with a new browser window offering a bunch of powerful management tools including an interactive web based interpreter linked to you application, a tool for defining model classes and their relationships, and managing your I18N strings. I used CatWalk (the tool for defining and generating model classes) to start my User class and made some slight modifications by hand from there as I've used SQLObject previously and realized I'd made some mistakes in the web UI.

To get started I figured I'd try to get a handle on modifying the default page and having it point to a new template, one that will list each “user” in the database. I copied trogdor/template/welcome.kid (the template that displays the page in the above screenshot) to listUsers.kid and gutted it leaving just enough for a simple hello world application).

Next big step is to figure out how to work with the model from that controller to list the users existing in the database. A simple import in the controller and some basic SQLObject syntax to query all entries in a table (User.select()) and I was able to print to the cherrypy console all the users in the database each time I reloaded the listUsers page.

Found a really neat way to play with the model using interactive Python code. From the root of your project dir:


(dev@kramer)[~/src/tg-vs-seam/trogdor] % tg-admin shell
Python 2.5 (r25:51908, Apr 10 2007, 10:27:40)
Type "copyright", "credits" or "license" for more information.

IPython 0.7.2 -- An enhanced Interactive Python.
? -> Introduction to IPython's features.
%magic -> Information about IPython's 'magic' % functions.
help -> Python's own help system.
object? -> Details about 'object'. ?object also works, ?? prints more.

In [1]: User.select()
Out[1]:

In [2]: list(User.select())
Out[2]: []

I assume the above will use iPython (an incredibly useful enhanced Python shell with tab completion among many many other goodies) if you have it installed, and default to the standard Python interactive shell otherwise. This could be used for all sorts of things as it looks like you have access to all your model/controller objects immediately. I absolutely love it.

So, now for displaying that list of users on the page. Turns out I just have to set the list of user objects in the return dict coming out of the controller's index method and voila, I'm looking at a list pulled back from the database.

My model class: (note: this probably needs some work to rigidly agree with the actual database restrictions)


from turbogears.database import PackageHub
from sqlobject import *
from turbogears import identity

hub = PackageHub("trogdor")
__connection__ = hub

class User(SQLObject):
class sqlmeta:
table ='user'
idName ='id'
login = StringCol(length=25, varchar=True, title="login",
unique=True, notNone=True, dbName='login')
password = StringCol(length=255, varchar=True, title="password",
notNone=True, dbName='password')
firstName = StringCol(length=50, varchar=True, title="firstName",
dbName='firstName')
lastName = StringCol(length=50, varchar=True, title="lastName",
dbName='lastName')
phone = StringCol(length=25, varchar=True, title="phone", dbName='phone')

My controller:


from turbogears import controllers, expose, flash
from model import *

class Root(controllers.RootController):

@expose(template="trogdor.templates.listUsers")
def index(self):

print("Hello world!")
allUsers = User.select()
allUsers = list(allUsers)
print("Found %s users in the db." % len(allUsers))
for user in allUsers:
print(user)

return dict(users=allUsers)

And finally my view template: (note how similar this looks to standard XHTML)

User List

User List

  1. ${user.login}

Seam

Installation

The JBoss Seam Getting Started Instructions recommend installing the JBoss Application Server via the JEMS installer. JEMS is a jarfile you download and launch with java -jar jems-installer-1.2.0.GA.jar. It doesn't look particularly great, and seemed a little buggy with one crash and some kind of problem when selecting the profile to install where clicking the options did nothing visually. I'm hoping I actually got it selected... Aside from this and the large download sizes (72mb for the GEMS installer (which I think includes the 68mb JBoss Application Server), and eventually another 73mb for Seam itself) this worked quite well. JBoss AS launched successfully in about a minute.

Database Connectivity

Unlike with Python, MySQL database connectivity is supplied by a jarfile rather than a package you'd install on your system. The MySQL JDBC driver can be found here.

Creating a Project

Seam comes with a variety of examples to help you poke around and understand. Installing and playing with any of them is as simple as editing the build.properties in your top level Seam directory and pointing it to your JBoss AS installation directory, then running ant deploy in any of the example directories. This worked well, the application server picked up the new app immediately and started it within a few seconds, no restart of the server was required.

In my case I'm less interested in modifying an existing application (of any real size) and instead more interested in generating a skeleton project as with TG. Seam-gen is a tool for just that, and some great getting started instructions can be found here. The tool is included with the Seam download from earlier. According to the docs I'm instructed to create a new Eclipse project, which I'm not exactly thrilled about as I'd rather not have to download and install another 80mb monster application on this system. Regardless I'll jump through their hoops in the hopes I can get by with just a text editor.

While running seam setup (note seam is a shell script found in the root of your Seam directory, and at the time of writing it wasn't executable by default) you'll be prompted with a number of questions for your new project, most of which are very straightforward. I selected ear deployment as the Seam docs themselves already had me download AS with EJB.

Once through these questions we run seam new-project, cd to the newly created project directory and run seam explode. (note the seam executable is still in your Seam download directory) Visiting http://localhost:8080/trogdor2 shows me:

It took about 80 minutes of setup to get to this point. The project directory contains 46mb of data, but almost all of this is required jarfiles of which there are several, including dozens of JBoss and Apache Commons jars.

Listing Users

seam new-action creates several classes in my projects src directory, and an xhtml in the view directory. Another seam explode and I can view my new userList page at http://localhost:8080/trogdor2/userList.seam. Not bad at all.

Now to define a model class, I believe this is referred to as an entity bean in Seam or EJB3. It looks like this comes in the form of a class with Java Persistence API annotations, somewhat cleaner and less difficult than the traditional Hibernate XML mapping files. (although not as powerful, JPA is a spec that includes most but not all of traditional Hibernate's functionality) I can't see anything in the seam-gen or seam docs for generating model classes, so I wrote one by hand.

Even with substantial Hibernate experience this took me almost an hour, mainly browsing the Seam reference documentation looking for an example entity bean and adapting it, as well as the Seam API (for Seam annotations) and the EJB3 API (for standard EJB annotations).

Once I had a model class compiling and deploying, it was time to get the user list displayed. With TG I started by querying and printing the results to the console from my controller. I noticed a Seam shortcut whereby I could just display the results on my userList page. (see Seam Reference Documentation on Query Objects) Despite the apparent simplicity of this, it took me some time to get it working. The Seam documentation has an obnoxious habit of referencing classes or XML elements without including the namespaces, and thus you need to go digging to find the actual location. Combined with an even more obnoxious tendency to see 5-10 page stack traces spewed out which may or (quite often) may not contain useful information somewhere, it took me just over two hours to get my model class working and my user list displayed.

My model User class ended up as follows: (getters and setters really are obnoxious, but the annotations are quite nice when you're used to dealing with Hibernate XML mappings)


package com.dangerouslyinc.trogdor2;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Entity;

import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.ScopeType;

@Entity
@Table(name="user")
@Scope(ScopeType.SESSION)
@Name("user")
public class User implements Serializable
{
private static final long serialVersionUID = 1881413500711441951L;

private Integer id;
private String login;
private String password;
private String firstName;
private String lastName;
private String phone;

public User(String login, String password, String firstName,
String lastName, String phone)
{
this.login = login;
this.password = password;
this.firstName = firstName;
this.lastName = lastName;
this.phone = phone;
}

public User() {}

@Id
public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

@Column(length=25, nullable=false, unique=true)
public String getLogin() {
return login;
}

public void setLogin(String login) {
this.login = login;
}

@Column(length=256, nullable=false)
public String getPassword()
{
return password;
}

public void setPassword(String password)
{
this.password = password;
}

@Column(length=25, nullable=true)
public String getFirstName()
{
return firstName;
}

public void setFirstName(String firstName)
{
this.firstName = firstName;
}

@Column(length=25, nullable=true)
public String getLastName()
{
return lastName;
}

public void setLastName(String lastName)
{
this.lastName = lastName;
}

@Column(length=25, nullable=true)
public String getPhone()
{
return phone;
}

public void setPhone(String phone)
{
this.phone = phone;
}
}

I generated a controller (I think, in Seam I believe this is referred to as an action bean?), but didn't modify it's contents to get my user list displayed. Instead I added a query to my components.xml, a practice that I'm not particularly fond of but still. It was as follows:

And finally my jsf view:

userList

List of people

Results

Setup time with TG: approx 20 minutes
Setup time with Seam: approx 1 hour 20 minutes

Coding/exploring/tinkering time in TG: approx 45 minutes
Coding/exploring/tinkering time in Seam: approx 2 hours and 5 minutes

Impressions so far:

TurboGears:

  • VERY quick to get the initial project off the ground.
  • Templates extremely nice to look at. Syntax is almost spot on with standard XHTML and thus you get much better editor support.
  • Automatic restarts on changes to the model or controller classes is very handy.
  • Nice to have a lightweight script to launch the application right in the project directory.
  • Interactive shell is an incredibly handy tool for developers looking to tinker with model/controller code live.
  • Error messages when I made mistakes with my code were concise and informative and in every instance pointed me immediately to the problem.
  • Appears to be only 5 configuration files, none of them using XML.
  • Learning the framework and exploring was generally a pleasant experience, rarely was I in a situation where I didn't know what to do or where to turn to accomplish my next task.

Seam:

  • Seam-gen is a nice addition. I've worked on Java web applications for a long time and creating the project and all it's associated configuration is daunting to say the least.
  • Seam-gen generated 34 XML configuration files. While nice to have them auto-generated, I have no idea what they all do and I can only imagine the amount of effort required to come to grips with that information.
  • Hot deployment is nice. I'm used to working with an application deployed with Tomcat which virtually always requires a restart. It's not quite as elegant as TG as you must run a command to deploy, but it's still not bad.
  • Documentation was very hard to work with. Seam introduces a number of new concepts which I've never seen or heard of elsewhere. At times they also just refer to things by different names. Additionally it only scratches the surface. From what I gather, to use Seam you also need to be familiar with a number of other Java technology such as Hibernate, JPA, EJB3, and JSF. I had about ten reference pages open at all times working with Seam.
  • JSF is not pretty or intuitive. It adds yet another technology you must learn to get moving.
  • At times you'll encounter 5-10 page stack traces which may or may not contain useful information somewhere inside. Debugging errors is not fun.
  • The general experience of exploring Seam was confusing and most often I was spending my time trying to get an idea where to go next and how to get there. The tools provided are nice but there's a massive amount going on in the background I just don't understand. The experience is drastically different than with TG.

Conclusions

This is part 1 and I honestly don't know if I'll make it to a part 2, there's a lot of work involved. I've barely touched the surface of either and would love to compare them on some other merits. How are they in day to day life when making changes, debugging errors, writing unit tests? Most importantly can TG hold it's own with scalability? Can it match some of the advanced features of Seam? Perhaps I will someday spend some time modifying the projects I've set up here to do more of what I was hoping to accomplish at the outset. In case I don't however, here are some of my conclusions, assuming I can extrapolate the experience so far to the long term. (which is a bad assumption, I apologize)

Seam has done a remarkable job at bridging the gap between the rapid development frameworks and the complicated beasts of the Java world. Setting up a Java web application is traditionally a very unpleasant task. In many ways it isn't fair to compare the two considering the amount of technology in JEE and the Java world. Take a look at the JEE Tutorial table of contents to get some idea what I'm talking about. Seam and it's associated technology can do all sorts of crazy things, TG and the frameworks like it focus on the core things and doing them extremely well.

Despite what Seam offers you, the end result is still a complicated bloated Java application full of XML files I don't understand, verbose classes, and dozens of Java technologies often defined by specifications very few people can tolerate taking the time to learn. Ultimately the technologies feel bloated, they're powerful and full of features, but most projects tap into a terribly small percentage of them. I consider myself a reasonably competent developer (although so do lots of terrible programmers so take that with a grain of salt) and yet I find JEE extremely intimidating.

On average, tasks took about three times as long with Seam. This is only at initial project outset so it may be unfair to extrapolate to the long term. A developer truly knowledgeable in either framework would obviously work much faster. It seems clear however that TG offers better tools and drastically more concise and readable syntax.

It's not a question of Java vs Python/Ruby/whatever. These languages some benefits over Java, but you can also write some truly evil hacks in dynamic languages. There's also the question of performance. The issue in this case is the framework, with Java the frameworks seem to frequently be accompanied by a massive overcomplicated specification, whereas the rapid development frameworks are free from this and can focus on doing one thing and doing it extremely well. It would be entirely possible to do this in the Java language, outside of the open source Java issues that are slowly disappearing and the differences in dealing with .jar's and such.

So far my conclusion is this: I loved working with TG, it was fast, easy and logical. It's incredibly refreshing when you're used to working on Java webapps. I worry and don't yet understand how well it would hold up to heavy load, either concurrent users or huge datasets or complex queries. Seam however is powerful and backed by some proven technology. While I'm not pleased about the fact that to use it I'd need to also know my way around JSF, JPA/Hibernate, jBPM, EJB3, JBoss AS/Tomcat, and perhaps JEE, I can't deny it looks like they have some really great features in there. (context/state management in particular has my eye I just haven't gotten to play with it yet) It was however very confusing to work with and really isn't in the same league as TG when you're doing the things you spend most of your time doing when working on a webapp.

It's still a matter of what your project needs, and if a lightweight framework will meet those needs then in my opinion, TG is the clear choice.

I apologize to any advocates/developers/zealots if I've offended your preferred language or framework. I spent very little time both frameworks, so feel free to leave comments on your viewpoints on their strengths, weaknesses, or inaccuracies in what I've written. Please include some indication of your experience with both or either framework.

Comments

Would it be okay with you if

Would it be okay with you if I linked to this page from my website? Just asking since some people don't allow linking to their sites if you don't take their permission.

Engineers who would like to have careers in management positions should seriously think about getting the PMP certification so that they can learn how to manage projects effectively. Getting the certification is a matter of passing the PMP exam which can be done with a bit of online PMP certification training.

Post new comment

The content of this field is kept private and will not be shown publicly.
Type the characters you see in this picture. (verify using audio)
Type the characters you see in the picture above; if you can't read them, submit the form and a new image will be generated. Not case sensitive.