My Pages

Thursday, November 22, 2012

Lift, a developers introspective

I've been using Lift for about a six months now; we used it to rewrite one of our internal C/Gtk applications. This is an introspection into our usages of Lift in enterprise software. For this post, I'm going to try and answer some general questions that I had going in as well as just some general questions that have come up from others working on the project.
  • Was it a new technology? How was the adoption of it?
  • How is view first for large systems?
  • How do snippets work out?
  • Did you keep mapper or switch?
  • How did you do UnitTests
  • Did you end up using the RESTful framework?
  • How did sitemap hold up with authentication?
So buckle up and let's get started into some of these questions.

Was it a new technology? How was the adoption of it?

Well, Lift itself had already been around for a little bit and Scala for a bit more than that. I got started into Scala during my M.S. at Depaul and was fascinated by the functional aspect of it. By that time, Scala had already achieved a version 2.8.x so again, it had been around for a bit. Both Lift and Scala were new technologies that we added to our stack.
I had added one small application in Scala previously; it was important because I was able to make changes with very minimal work. My boss at the time loved this, mainly because he could ask for something and I could pump out the work in a few minutes. I had spoken with him before (and his boss) about rewriting our entire C/Gtk application base into Web Applications. This ended up being my way in; I offered to do a simple rewrite using this framework and language. I then went in and did about 40% of the work and came back to him with it. Showing him that we could rewrite it with ease. He then agreed and had me write up some documentation to ask the team who would eventually take the product over from us if Lift + Scala were ok.
I got a chance to work with some of the people on the team taking the product before the team made its final decision. Each person told me that they wished they could work in Scala all the time. Not only that, but each of them have found it wonderful working in Lift. We had to adopt using Maven (it was either this or go with ant/ivy itself) since sbt was ruled out. It was great how quickly our project (utilizing Maven) plugged into IntelliJ. We started in ScalaIDE until we found that an index would be performed evertime you hit save. And this caused Eclipse to eventually run out of threads to generate these indexes. It was a known bug, but we didn't have a choice at this point and I switched us over to IntelliJ. Of course, IntelliJ has it's own issues; but for the most part I haven't seen many of them.
Overall, the adoption has been fantastic. The RestHelper is just mind bogglingly simple; and using pattern matching to create understandable RESTful resources. My co-workers came from a Spring background; and so this was a very different way of looking at services, but once they began to understand how it was setup; it is so much simpler and much easier. As I'll mention later, we switched to Squeryl for the ORM; and everyone freaked out about how SQL-ish the commands were. Making it easy to write the SQL statements while keeping type safety. The XML being a native datatype was just so nice for creating the services. Now the one downside that I had with this was that Record did NOT have an .asXml method; which meant that if you wanted to serialize Objects from the database you would have to manually create the XML. I figured that this would be a pain; and so I decided that I would extend Record to do this for me (by using the same functionality that .asJson does). I submitted a bug for this to the Lift group but haven't heard anything back.

How is view first for large systems?

This is an interesting question and I'm still not totally sure about this one. I've seen some really awesome abilities with performing multiple layers of embeds. But I've also seen some necessity to put out XML (XHTML) within the snippet calls. This is actually really awesome stuff where you get verified XML that will be embedded as it gets substituted. One thing that I've done in a newer project was to call into a snippet with a template XHTML section; I can then (since Scala does not modify the actual original XML on a Bind call) recall bind for each of my records that I want to apply my template to. It's really amazing what can be accomplished when you start realizing that Lift tries to keep the immutable variable idea.
Regardless, having multiple levels of embeds, and not having any business logic within the views themselves means that modifying layouts is simple. We then reduce the business logic back to the snippets to handle. One of the things that we did was to use a "loggedin" snippet call; at first I was thinking "oh man, I'm introducing business logic into the view." But actually I'm not, because the business logic of how "loggedin" is processed is kept in the Snippet. Now some people may use snippets like this in things like PHP or Grails or Rails by using something like below. And that might be fine; but eventually session.user.loggedIn becomes session.user.loggedIn || session.user.isAdmin.
<% if(session.user.loggedIn) { %>

How do snippets work out?

Snippets end up working the same way that taglibs work in Grails. They seem to work out really nicely. I find it really useful to treat them as template fillers. I find it useful in some instances to generate other XHTML (for example I have some code that decides when to send certain javascript functions because it's optional based on the user logging in) but on the whole I use it to populate my pages themselves. In some instances I'm using it to actually do Lift-y things and do lift callbacks for Javascript executions. When we started this project we all came from an MVC background which meant that we created snippets such as "*Show" or "*Index." If I could go back, I would've treated the snippets as truly encapsulated pieces. If I had to give anyone advice about using Lift it would be encapsulate the calls into snippets rather than treating each one as instead of doing one per page!

Did you keep mapper or switch?

We started with mapper until we found a composite key record. Mapper fought with me a bit and I finally wrangled it. Then I ran into another DB type where we had a composite key and we had an auto increment field that was NOT part of the PK. This is a completely insane concept and I wish I could change it; however, it is not within my power to change it. As such, Mapper just completely failed at this (and rightly so, if you have an AI field it should be your PK :( ). So I went through and looked at a couple of different ORM choices. The first was, obviously, hibernate (we already used this as our organization); I put it on the background mainly because I've heard some pains with hibernate and transactions/sessions as well as it wasn't pure Scala. So I started looking at pure Scala options. The first I came across was Squeryl; I checked it out, seemed pretty easy to get embedded into Lift but ran across some issues with defining AI fields that are not part of the primary key. However, it was much simpler to use than Mapper and since we were not doing CRUD style applications it made more sense especially since it had it's own DSL that was reminiscent of SQL itself. The final one that I looked at was Circumflex. I really liked the syntax, especially the definitions of objects and how they looked exactly like SQL create statements.
Regardless, we switched to Squeryl which took a little bit of work to accomplish; but on the whole it ended up being really awesome to work with. The ability to write queries that actually felt like queries but were type safe and still utilized prepared statements. My one complaint, as I mentioned above, was using Record meant that we did not get an ".asXml" component much like there is an ".asJson" option. So I went in and created it myself as a trait. It was really nice having the ability to do an ".map(_ asXml)" which I could then send back as a RestHelper response. I had created a github pull request for this and also pinged the Lift Google Group to see if it could be added. Hopefully they do; I think it would be a great compliment to the RestHelper to be used for XML Rest Services.

How did you do UnitTests

We actually ended up using ScalaTest. We did incorporate Cobertura as well for code coverage. However, we, as with anyone using Cobertura in Scala appears to see, you cannot get > 50% branch coverage. We have > 90% line coverage and about 850 UnitTests which is just awesome for the small amount of code we've actually written for our application itself. We had to use the JRunner interface since the maven-scalatest-plugin was not available at the time and is still kind of in a beta of sorts. My suggestion is just to go ahead and stick with ScalaTest using the JRunner interface; this way you can actually plug into tools like Jenkins and get UnitTest information into your reports.

Did you end up using the RESTful framework?

We did; as a matter of fact we ended up using the jqGrid plugin quite a bit; so we ended up making massive use in the RestHelper RESTful frameworks. It was fantastic how easy it was to create new resources and more specifically how simple it was to add resources. We actually ended up creating a list in our Boot class that contained all of the Rest objects; we then did a foreach on that list and added them with our guard (to protect our rest services from unauthenticated users) to the stateful dispatch. This would be something I would suggest to everyone if they are looking to do statefulDispatch rest services that require authentication. Setup a list of them and do a foreach on them to add them to the dispatch and do the guard. This way adding a new object is just adding it to a list.

How did sitemap hold up with authentication?

The sitemap itself was a little bit awkward at first to understand. Once you get the hang of "oh, after the slash is the filename without the .html appended" then it's pretty straight forward. The interesting thing about the SiteMap is that if you create the SiteMap manually you can specify a partial function to perform a check for users. I will say; if you do this, make sure to remember that there are a few different pages that shouldn't require authentication! Your login page, a logout page, your primary error page, your primary page missing page. Make sure in your partial function you are checking for that!

Summary

If I had to do it again here is a list of things that I would've done differently.
  • Converted to Squeryl.
  • Proper encapsulation in my snippets.
  • Used the HTML5 parser rather than the XHTML parser.
  • Done less in pure JS and did a bit more Lift-ing.
  • More Lazy Loading and Parallel Loading
  • Do not use as much Scala shorthand (this is merely for other users coming in)
I'm probably forgetting some, but these are the immediate ones that stand out to me as lessons that I learned writing a Lift Web Application. I hope others can see this and maybe take something away from it as things that will make a transition to Lift a bit easier. If you have questions I can do my best to answer them if I've run across them in the past; or if you have any experiences of your own let me know!
I would like to say thanks to the Lift Google group for being open with me when I had questions!

No comments: