Play vs. Lift Pain Points
Asked Answered
N

2

12

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 with DELETE /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?

Nieberg answered 14/11, 2012 at 21:23 Comment(1)
This problem seems to be non-existant for our team. We use POST for creation where no ID exist yet and PUT for updates where you have an ID. So PUT and DELETE on /foo/bar/:id does work. POST would be on /for/bar .Fructose
D
24

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.

Dacca answered 15/11, 2012 at 18:46 Comment(5)
+1, comprehensive, insightful, but no pain! I don't believe it, Lift can't be thaaat good ;-) The "#table #> { ..." bit is fairly hideous at first glance. In the view I actually have no issue with html markup, prefer it actually, as that is what I'm looking at in firebug. Anyway, sounds at minimum like Lift offers a snappier experience due to fewer moving parts/things to compile. Curious, will give Lift a shot when I come up for air from current Play 2.1 project (that is ripping away in production, man, the JVM is absurdly fast)Nieberg
I guess you did ask about Lift's pain points, I may have gotten a bit wrapped up with your specific issues and rebutting the other response :) Anyway, I think that Lift has 2 major pain points compared to Play: (1) You can get fairly immediate feedback on changes, but it does require more configuration (JRebel) and (2) the documentation isn't nearly as well organized. The Wiki, Cookbook, etc, are all great resources, but it would be nice to have all that information in one place. The Google Group is second to none though, and it makes up for the documentation issues in my opinionDacca
@DaveWhittaker when I said Scala complexity I meant the source code (will make it more clear), I rely a lot on framework source code to understand what's going on. Lift one, when I tried (2 years ago) was nightmare to follow for a Scala beginner :)Addition
Didn't you mean to use value as class name for the second table cell in your example?Disentwine
Just a small note. Starting from Lift-2.5 the expression: "#table" #> { "tr" #> {... can be shortened to : "#table tr" #> tuples.map{...} And, in general, all the transformation selectors are very much like CSS selectors, which is very convenient.Strep
A
8

First I beleive it's fair to address some of your points:

  • On 1 and 4: Scala 2.10 has relevant gains in compilation speed, this should not be a problem anymore
  • On 2: Never saw any conflict with GET/POST, but I did not try DELETE. Could be a bug in Play or in your code (open a new question including the full routes definition, including method)
  • On 3: IntelliJ 12 supports Play 2. And generics are supported in templates AFAIK (if by generic you mean passing a generic parameter of type X[A] or A)

My experience with lift is from several years ago, so some of the points may not apply:

  • The codebase and syntax (of the source of Lift) was really high-level Scala. This made really hard for someone starting in Scala to grasp what the code was doing when looking at the framework code.
  • The view-first approach was a mess, mixing code in "controllers" (returning HTML), it broke the separation of concerns and made following code a bit harder

But most importantly:

  • Stateful. Since I moved out of Java EE world and started working with stateless servers, the amount of issues that have gone away is astonishing. Not having to worry about sessions and other clutter seems irrelevant, but it does make a difference. Specially in the era of cloud computing :)
Addition answered 15/11, 2012 at 10:1 Comment(4)
+1 nice, thanks for the run down. scala 2.10 + sbt 13 should help, hopefully in not too long stable releases will be available. re: REST routing, yeah, could be an edge case with DELETE, not sure. Did not know that about IntelliJ, on Linux though, and last I checked the IDE looks like a dog's breakfast, tough on the eyes. By generics I mean "@[T <: Foo](bar: T)"; without full generics, you wind up having to create more types and scala.html files to handle the various scenarios, which means longer build times.Nieberg
@Nieberg inline methods like that may not work, but try to create tham as tags. They should solve the issueAddition
I have the opposite experience with statefullness: it's absolutely typesafe in Lift and it helps a_lot. I never had any issues with it (1 year with Lift, 1,5 years with Scala now).Strep
"The view-first approach was a mess, mixing code in "controllers" (returning HTML)" -- yes, I also returned HTML in controllers for a few months, until I found out that you can be much more happy without that.:) And yes, after that I had no HTML in controllers and it works great. The "view-first" approach became the thing I like very much.Strep

© 2022 - 2024 — McMap. All rights reserved.