EDIT
Slow compile times are now largely mitigated by sub project enabled builds, a huge win.
Have switched away from Play's built-in asset generators (i.e. for Coffeescript and LESS) and moved over to 3rd party Grunt JS; now code changes during incremental builds are limited only by scalac compilation time and not also the overhead of Play's relatively slow assets generation.
ORIGINAL
Overall pretty happy with Play 2.1 Scala (the 9/14/2012 release, just prior to switch to Scala 2.10); however, there are some development pain points:
1) routing: on route change, one's entire route-controller structure
can
be re-compiled: not good.2) REST appears to not be directly supported since route
POST /foo/bar/:id
conflicts withDELETE /foo/bar/:id
; i.e. route paths must be unique, presumably for reverse routing.3) views: with a scala.html file per foo action, the file count grows quickly, which means slower build times, more to compile; generics not supported and blind coding due to lack of IDE support (of course no scala template engine has IDE support to-date, AFAIK) are particularly tough areas.
4) incremental builds work, but nothing in the process can be called "snappy", even a simple change to a scala.html file will in reality take @2 seconds, which is a long time when you're wanting that instant code-change browser-refresh feedback cycle.
I know some of the above issues are being worked on by Play devs, and slow-ish build times are also directly related to sbt, scala version, and one's own code structure. Again, overall, Play has been an enjoyable development experience. This is about pain, however, and I want to know what Lift brings to the table in this regard...
Lift seems to take a different approach. Do Lift-ers suffer from the above items? Assume not since MVC, Lift is not, and the xml-style snippets approach may not incur the same compile time hit that some of Play's behind the scenes build machinery does.
What are the pain points in Lift?
My own personal viewpoint as someone who has been using Lift for about 2 years now:
1) routing: on route change, one's entire route-controller structure can be re-compiled: not good
With Lift there is no routing. I would think the closest related concept would be the SiteMap, and personally I've never had any issues related to it's compilation.
2) REST appears to not be directly supported since route POST /foo/bar/:id conflicts with DELETE /foo/bar/:id; i.e. route paths must be unique, presumably for reverse routing.
Having done quite a bit of REST with Lift, I can tell you that this is definitely not a problem. Lift's REST support is really nice, and is based on Scala's pattern matching which gives you a really powerful, type safe way to design your web services
3) views: with a scala.html file per foo action, the file count grows quickly, which means slower build times, more to compile; generics not supported and blind coding due to lack of IDE support (of course no scala template engine has IDE support to-date, AFAIK) are particularly tough areas.
With Lift, the HTML code is just HTML (no special symbols), so it doesn't factor into compile time at all. The HTML, known as Templates, is processed by Snippets that transform NodeSeq => NodeSeq. That may sound complex, but Lift has a DSL to make it really easy. Want to add a users name to a span? If it looked like:
<span id="user-name">User name goes here</span>
You'd have code like this in your snippet:
"#user-name *" #> user.name
You can also repeat items in your template, like a table or a list:
<table id="table"><tr><td class="name"></td><td class="value"></td></tr></table>
With this applied:
val tuples = List(("Lift", "Is great"), ("Other web frameworks", "Eh"))
"#table" #> {
"tr" #> {
tuples map { case(name, value) =>
".name" #> name &
".value" #> value
}
}
}
Would result in a table with 2 rows, each respresenting the name/value of an element in the list.
This I think is really one of Lift's greatest strengths. Templates are just HTML, no symbols or markup included. You can work with what your designer puts together as-is and even give them direct access to make updates (in some cases anyway).
Snippets, on the other hand, are pure Scala, not some templating language. Whatever you can do with Scala, you can do in a Snippet, and it's all checked by the compiler.
It's also possible (and encouraged) to use a Snippet on multiple pages, so you don't necessarily need a Snippet per page. You can even configure the Sitemap to use the same template for multiple pages, and pass type safe parameters to the Snippets the page contains based on the request.
4) incremental builds work, but nothing in the process can be called "snappy", even a simple change to a scala.html file will in reality take @2 seconds, which is a long time when you're wanting that instant code-change browser-refresh feedback cycle.
I don't think that Lift hurts in this respect, but unfortunately it doesn't help much either. It's good to hear that Scala 2.10 will include some improvements in this area, because I think they will have to come from the compiler.
To answer some of the Lift criticisms...
Is high level Scala required? No, I don't believe it is. This is kind of subjective, but you can see from what I've posted that creating a template and applying a snippet to it is pretty straight forward. You have to be familiar with concepts like "map", but what good is using a Scala web framework if you aren't? The Scala doc on some of the methods you'll use might look kind of hairy to first-timers, but much like Scala collections the complexity is there to make the library easier to use. For folks who are new to Scala, they are probably better off following examples in the Wiki the Cookbook and Simply Lift and not the API doc, but I think that's a Scala idiom, not a Lift one.
Do you have to mix markup in "controllers"? Absolutely not. I'm going to look past the fact that Lift is not an MVC framework and assume that the poster is talking about Snippets. Outputting HTML from a Snippet is by no means necessary, and in most cases is a complete anti-pattern. CSS Selectors like the ones I've posted allow you to keep all of your HTML in template files, and all of your logic in your Snippets.
Does Lift require too much state? This is the number one complaint I run across, and not once have I seen it accompanied by a real world issue. The fact of the matter is that with Lift you have a choice about whether you want to be stateful or not. If you are using Lift to write a web service, and you don't want a Session created when your URLs are accessed, you register the service with LiftRules.statelessDispatchTable. This fits with the Lift philosophy that state is neither good nor bad, but it's necessary to fulfill some needs, and not necsessary for others. It's important to be explicit about when it's used and let the developer decide. If you're interested in more detail about that, David Pollack has a better explanation.