The Difficulty of Scala
In my last project I tried to use scalatra with slick, and while I really liked scalatra, slick made me go nuts. I had to jump over so many hoops that it was just a pain.
One of the Scala issues I had was that the error was the compiler throwing up a stream of sigils because some generic requirement didn't hold and it was very very difficult to search for, let alone understand what was wrong. Granted, it's been almost 6 years since I stopped using Scala. The experience that broke me back then was trying to use Slick, a typesafe Scala ORM. I forgot the details but I remember it was astonishingly hard to use back then and I couldn't for the life of me tell what was wrong because the compiler error message was so cryptic.
Another large part of the problems I had were an unbelievable terrible documentation. Sometimes, in order to do even the simplest things, I had to look into particular unit tests deep within the sources of the project, or follow stackoverflow discussions with multiple proposals, only one of which actually worked. Oftentimes this was for things which I considered granted and implemented. The certainly best example is getting an object by id. I would have thought that this, being the most basic operation, should be possible through some kind of default operation like "get" or "getById" or "objectById" or something else. Instead, you have stackoverflow answers like this:
def findById(userId: Int)(implicit session: Session): Option[User] =
http://stackoverflow.com/questions/16461260/select-single-row-based-on-id-in-slick
However, that's not even the brink of the iceberg. Try finding out how to update multiple fields in an object. Say you retrieve a User object, and you want to set a new email, zip, and address. I'd suppose, this would work with simple getters and setters, i.e.:
user = Users.get(user_id)
user.email = new_mail
user.zip = new_zip
user.address = new_address
Instead, you have to do this:
val map = Query(User)
.filter(_.id === user_id) .map(ab => ab.email ~ ab.zip ~ ab.address)
map.update( )
And even that only works with updateable result sets:
- http://stackoverflow.com/questions/16757368/how-do-you-update-multiple-columns-using-slick-lifted-embedding
- https://groups.google.com/forum/#!msg/scalaquery/ML56aZAfy3g/nx-PPV1y2dEJ
Or, to quote from the stackoverflow answer above:
"Typesafe, why your documentation is so bad ? I have to Google pretty much every silly thing or dig through unit-tests for hours. Please improve it. Thanks."
Now, after a lot of searching, I found solutions to all of my problems, but it took a long time, lots of Google, and almost nothing came out of their awful documentation.
I'm currently working on a new project (still research phase) where I was pondering going with Spray and a lightweight Postgresql wrapper because I primarily need to read data from a database, do some transformations on it, and write it out as JSON as fast as possible. I had it working in Spray, but I had issues with server crashes and the speed wasn't as I'd have expected. I fiddled with it for one day, and then, out of frustration, decided to give openresty a try. I've never written much Lua in my life, but after only a couple of hours, I had it working, and it was far, far faster than the Spray implementation. I did some research there, and it seems that the database stuff took a whole lot longer in Scala/Spray than in Lua. Now, of course, I loose type safety, so there may be hidden issues in there, but since I'm really just doing simple data transformations, I think I'm fine with lua / openresty.
As a first verdict, I really, really like what I've seen of Openresty so far.