We recently implemented a small, mostly static content site (http://
www.goldenfrog.com/) using Lift.  Thought I'd offer up a postmortem on
what worked well and what didn't, in case it's useful to anyone
considering Lift.  We're a small team with essentially no prior Scala
experience, so take this with a grain of salt & feel free to offer
suggestions.

The good:

We went with Lift mainly because we wanted: 1. clean separation of
code from html; 2. easy localization.  With a few minor caveats (see
below), we got that.

An html designer was able to work on templates & commit directly to
our repo without touching any scala code.  When he broke things, it
was usually immediately obvious because the xml stopped parsing
correctly and the page would no longer render (even though it usually
took a programmer to interpret the stacktrace & fix the xml).

Regarding localization, the use of separate templates (instead of e.g.
java properties file references for every single sentence) was a big
help.  Because everything in templates is well-formed xml, I was able
to write less than 100 lines of code to automatically extract
translatable text and generate a translated version of all the
templates.  This is done during build, so essentially duplicate html
doesn't get into our repo, until some point when translated templates
need to actually be structurally different.

The bad:

Dreamweaver doesn't deal with head merge, it will automatically move
the head tags outside of the lift:surround.  Not really a lift issue.

PCDataXmlParser converts entity references to actual utf-8
characters.  This means templates with entity references won't round-
trip correctly through view source, nor through localization
properties files / gettext files.

Jetty seems to do questionable things with filehandles, opening
multiple copies of the same template file and keeping them open too
long.  Setting ulimit "fixes" the issue of "Too many open files"
exceptions & failed requests, but it still seems like at most
templates should need 1 access to check mtime.  Not really a lift
issue, and not a deal breaker for us to switch to a different servlet
container, but I am curious to see what the eventual solution for
comet performance is.

Lift doesn't seem to have any central place to handle URL issues
related to servlet context paths and domains / subdomains.  We're
currently running lift as a root servlet to avoid forcing context path
to be visible in urls; this is fine for us but I can see it being
useful for lift to know that the frontend proxy is taking care of
mapping foo.com/ to the context /foo-lift-app/, instead of always
adding the context path to urls.  Similarly, we're running multiple
subdomains from a single lift instance, because it's all basically
common code and templates.  The way we ended up making this work was
to have 1 folder per subdomain, and subclass Link so that it knows how
to createLink correctly based on headers the frontend is sending; e.g.
the link for http://foo.bar.com/baz is put into the sitemap as /
foo.bar/baz and will be rendered as /baz if the request is already in
the foo subdomain, or fully qualified http://foo.bar.com/baz
otherwise.  In one sense, it was nice that we were even able to do
this without modifying Lift.  However, we already ran into the issue
of default form redirects wanting to go to /foo.bar/baz, not just /
baz, and there doesnt seem to be a clean place to handle that.

The public face of 1.0 vs snapshot could be handled a little better,
in terms of website / liftbook / documentation.  If the intention is
for all users to track snapshot for now, that should be made explicit
and the docs updated.

The ugly:

There are aspects of the API that are frankly quite difficult for
developers to take seriously -
"object User extends User with MetaMegaProtoUser[User]" is a common
whipping boy around the office, and leads to jokes about giant robots.

Similarly, there are a number of places that seem to force syntactic
overhead instead of catering to concise default usage, eg the first
time I saw the liftbook example of

case RewriteRequest(
ParsePath(List("account",acctName),_,_,_),_,_) =>
RewriteResponse("viewAcct" :: Nil, Map("name" -> acctName))

I thought how often are you actually going to fill in those
underscores?  One of the things we did as part of our link subclass
was an implicit conversion to allow writing links in the sitemap as
"foo.bar/baz/quux/*" rather than ("foo.bar" :: "baz" :: "quux" :: Nil)
-> true.  I don't know if that's bad style or not, but it certainly
makes the sitemap more scannable as a list of urls.  I know
conciseness isn't this framework's top priority, but it seems like
some judicious use of implicits would help.


Thanks to the devs for writing lift, and like I said, please offer any
suggestions or counterpoints.

--

You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en.


Reply via email to