Sunday, January 4, 2009

Moving to TG2, Part 1

This is the start of a series on the work we're doing upgrading BandRadar's components. BandRadar's development started in 2006, and used the default components of TurboGears at the time: SQLObject for ORM, kid for templating, tgwidgets for widgeting, mochikit for js library, and CherryPy as appserver.

Basically all of these components are now obsolete, or at least no longer recommended for new TG/TG2 projects. But they still work fine, so why change?

Good question. I'm hoping that re-examining the choices we made in implementing BandRadar version 1 will bear dividends in terms of simplifying the code or making it easier to add new functionality, but honestly it's not clear at this point whether time spent on this work will have more value than spending it on extending the current code. It also depends on how hard moving to the new components is. Thankfully, TurboGears will let us transition to new components in stages, instead of all at once.

The plan:
  1. SQLObject to SQLAlchemy (Elixir)
  2. kid to Genshi
  3. tg.widgets to ToscaWidgets
  4. CherryPy to Pylons/mod_wsgi
Currently working on #1. Converting classes derived from class SQLObject to class Entity and defining the relationships has been relatively painless. All our table names are not what Elixir is expecting, but it's easy to tell it what they should be. The first little bit of trouble is that SQLObject did not create db constraints for required fields, it keeps track of these itself and throws an error if a required field is omitted when creating an object. SA appears to rely on the database for this (which makes sense) but our existing db schema (originally created by SO) will need to be updated by hand for the new not-NULL constraints. We've also added a fair number of additional methods to the objects on model.py, and these will need to be reimplemented in SA-ese. Finally, our SO model includes a feature where all modifications to some tables are logged to a separate table (so we could recover from vandalism if necessary)... this will need to be reimplemented in SA, or we need to jump to versioned objects. I'd prefer the former, frankly, but I don't know if SA has a feature equivalent to sqlobject.events, or if I could just override __setattr__() in my model objects.

2 comments:

Chris Perkins said...

This is indeed a great start to a series that will be exceptionally valuable to the TG community. To answer your blog question about logging your entries: One way to solve the problem is with mapper extensions. Here is a link for you:
http://www.sqlalchemy.org/docs/05/reference/orm/interfaces.html#sqlalchemy.orm.interfaces.MapperExtension

hope that helps.
-chris

mae said...

Really nice we sure need more examples like this. Some comments on your migration.

1- I'll suggest going to TG1.1 first, this will take care of SO-SA and kid-genshi.
2- JS and toscawidgets next.
3- TG2 code base (IE pylons)

From all those steps you are probably starting with the most complex one SO->SA

As a side note you may way to check out SA declaratives (default as 0.5) IMO it's as good as Elixir for the most common cases so it should cover 80% of the use cases without the extra dependency.