Scalalala - journeys from Java to Scala
This blog has move to wordpress: http://scalalala.wordpress.com
Wednesday, March 12, 2014
Tuesday, March 11, 2014
Slicker than most
Let's start with a song from my college days
So as my Scala journey progressed it was time to pick a persistent engine. I looked at Anorm and decided on Slick. Mostly because its supported by TypeSafe which I would assume with their bankroll and influence is a safe option. Technically, I like that I can still fall back on raw sql if I need to, because my experience with every Java ORM is that you need that option at one point or another.
So the first thing to do was get my model going. I quickly discovered something called case classes.
So that is sorta like an immutable POJO in the Java world, but in one line! It comes with hashcode(), equals(), toString(), all built in. Already I was digging things, that would have probably need like 50 lines of code in Java, albeit my IDE would have vomited most of it out for me, but still, its very concise, me likes.
Based on patterns I found googling around, the next business was to create the Meetings class. This guy is sorta like what you might do with an hbm file or annotations to describe how columns map to your model.
So most of that is probably pretty obvious until you get to
Ok so now we have our DAO which might look something like this:
That's all pretty straight forward, other than the implicit parameters and Option junk right ? Ok, so Option I first found annoying, but now I think its awesome. Option basically eliminates NPE's and null checks from your code. Its a way to type that something can have a value or not. To access the real value you do someOptionVar.get, and you can test if it has a value with someOptionVar.isEmpty. All the extra .get calls annoyed me at first, but then when I saw how all the null checks disappeared, but my code was still safe, I had a different opinion.
What else is going on there? Oh, query.firstOption. So in Scala a List is called a Seq. query here is a Seq. To get the first element as an Option, you can call firstOption. Then back in my calling code I can make the "null" check using the Option.
So as my Scala journey progressed it was time to pick a persistent engine. I looked at Anorm and decided on Slick. Mostly because its supported by TypeSafe which I would assume with their bankroll and influence is a safe option. Technically, I like that I can still fall back on raw sql if I need to, because my experience with every Java ORM is that you need that option at one point or another.
So the first thing to do was get my model going. I quickly discovered something called case classes.
1: case class Meeting (id: Option[Long], meetingEid: String, name: String,
2: var host: Option[String], var hostSalt:Option[String],
3: welcomeMessage:Option[String],dialNumber:Option[String],
4: voiceBridge:Option[String],startTime:DateTime,duration:Int)
So that is sorta like an immutable POJO in the Java world, but in one line! It comes with hashcode(), equals(), toString(), all built in. Already I was digging things, that would have probably need like 50 lines of code in Java, albeit my IDE would have vomited most of it out for me, but still, its very concise, me likes.
Based on patterns I found googling around, the next business was to create the Meetings class. This guy is sorta like what you might do with an hbm file or annotations to describe how columns map to your model.
1: class Meetings extends Table[Meeting]("MEETING") {
2: def id = column[Long]("ID", O.PrimaryKey, O.AutoInc)
3: def meetingEid = column[String]("MEETING_EID", O.NotNull)
4: def name = column[String]("NAME", O.NotNull)
5: def host = column[String]("HOST", O.Nullable)
6: def hostSalt = column[String]("HOST_SALT", O.Nullable)
7: def welcomeMessage = column[String]("WELCOME_MSG", O.Nullable)
8: def dialNumber = column[String]("DIAL_NUMBER", O.Nullable)
9: def voiceBridge = column[String]("VOICE_BRIDGE", O.Nullable)
10: def startTime = column[DateTime]("START_TIME", O.NotNull)
11: def duration = column[Int]("DURATION", O.NotNull)
12: def uniqueName = index("IDX_MEETING_EID", meetingEid, unique = true)
13: def newMeeting = meetingEid ~ name
14: def * = id.? ~ meetingEid ~ name ~ host.? ~ hostSalt.? ~ welcomeMessage.? ~ dialNumber.? ~
15: voiceBridge.? ~ startTime ~ duration <> (Meeting.apply _, Meeting.unapply _)
16: }
So most of that is probably pretty obvious until you get to
1: def * = id.? ~ meetingEid ~ name ~ host.? ~ hostSalt.? ~ welcomeMessage.? ~ dialNumber.? ~
2: voiceBridge.? ~ startTime ~ duration <> (Meeting.apply _, Meeting.unapply _)
What the hell is that crap ? Yeah, I didn't know either. What does <> mean ? What about def * ? Eventually (like hours later) I came across this, http://stackoverflow.com/questions/13906684/scala-slick-method-i-can-not-understand-so-far which explains about Mapped Projections and Comprehensions. If you want to understand it read that post, does a much better job than I can, that guy should write a book. Basically it comes down to, that is how you map a row into your backing object and vice versa. Its amazing concise and powerful. Think about all the really verbose ways you've seen that done before, and it will really stop you in your tracks. On the flip side try googling for "<>" or "_" or "def *". Once you understand it, its awesome and super easy, but trying to find the information to explain it, that was sorta hard for me. I thought I was a pretty good goolge user, sheeshOk so now we have our DAO which might look something like this:
1: object MeetingDAO {
2: val table = new Meetings
3: def createMeeting(meeting: Meeting): Long = DB.withSession { implicit session: Session =>
4: table.insert(meeting)
5: }
6: def listMeetings: List[Meeting] = DB.withSession { implicit session: Session =>
7: Query(table).list
8: }
9: def deleteMeeting(meetingId: Long): Option[Meeting] = DB.withSession {
10: implicit session: Session =>
11: val query = for {
12: meeting <- table if meeting.id === meetingId
13: } yield meeting
14: val retVal = query.firstOption
15: query.delete
16: retVal
17: }
18: }
That's all pretty straight forward, other than the implicit parameters and Option junk right ? Ok, so Option I first found annoying, but now I think its awesome. Option basically eliminates NPE's and null checks from your code. Its a way to type that something can have a value or not. To access the real value you do someOptionVar.get, and you can test if it has a value with someOptionVar.isEmpty. All the extra .get calls annoyed me at first, but then when I saw how all the null checks disappeared, but my code was still safe, I had a different opinion.
What else is going on there? Oh, query.firstOption. So in Scala a List is called a Seq. query here is a Seq. To get the first element as an Option, you can call firstOption. Then back in my calling code I can make the "null" check using the Option.
1: val entity = MeetingDAO.deleteMeeting(meetingId.toLong)
2: if (entity.isEmpty) {
3: Home.flashing("warning" -> s"Meeting '${meetingId}' was not found.")
4: } else {
5: Home.flashing("success" -> s"Meeting '${entity.get.name}' has been deleted.")
6: }</span>
I've just begun to touch the service with Slick, I haven't tried doing complicated queries or even relationships yet, so I suspect will have some more posts about that, when I get to it. I'll save implicit parameters and implicit methods for another time as well.
First Project With Scala
So I started my first project with Scala about six months ago. I had hired a new guy to build some automated testing out for our main application, and I figured that was a fairly low risk type of project to kick the tires out on. I knew I was going to be using Web Driver to do most of the work, so it seemed largely irrelevant to me what language was actually pushing the commands out, they are probably all roughly the same. Also, the resource I hired was still in school, so this would be a chance to see how quickly someone with limited coding experience, could pick up Scala and use it for something. This project wasn't going to have to have any fancy design or be overly complicated, so we could ease into it without getting too sophisticated in the functional world yet.
The project is here: https://github.com/johntbush/sakai-test-suite. I wanted to use cucumber because our application is pretty large and complex and I had another tester guy who already knew the functional aspects of the application, so I figured he could write cucumber tests and feed them to my automation Scala newbie to implement. We stuck with maven for building, junit, and other tools we were familiar with. This was a classic ease into Scala type of project.
Within a few days I had the basic skeleton working. I actually struggled more with getting cucumber to work with scala and junit, more than anything else. Really the stupid phantomjs driver (nice idea, not a fan) and getting everything pulled into jenkins was much harder than anything to do with the Scala language. Just basic Selenium funkiness, especially with the iframes in our app too some time to figure out, the dsl in Scala was really nice to work with. This lead me to my first conclusion, the frameworks matter. You can have all the nails in the world, but without a hammer to drive them in, you are screwed. The nails being power of Scala, hammer the frameworks... ok you get the idea. You weren't expecting a fucking poet here were you ?
Now I had a nice Config object, defaulted by a properties file, overridable by system properties. I could call from anywhere else and not worry about injection or any of that business. Nothing fancy, quick and dirty, does the job:
The project is here: https://github.com/johntbush/sakai-test-suite. I wanted to use cucumber because our application is pretty large and complex and I had another tester guy who already knew the functional aspects of the application, so I figured he could write cucumber tests and feed them to my automation Scala newbie to implement. We stuck with maven for building, junit, and other tools we were familiar with. This was a classic ease into Scala type of project.
Within a few days I had the basic skeleton working. I actually struggled more with getting cucumber to work with scala and junit, more than anything else. Really the stupid phantomjs driver (nice idea, not a fan) and getting everything pulled into jenkins was much harder than anything to do with the Scala language. Just basic Selenium funkiness, especially with the iframes in our app too some time to figure out, the dsl in Scala was really nice to work with. This lead me to my first conclusion, the frameworks matter. You can have all the nails in the world, but without a hammer to drive them in, you are screwed. The nails being power of Scala, hammer the frameworks... ok you get the idea. You weren't expecting a fucking poet here were you ?
Singletons Are Built In
So the first cool thing I discovered was that Scala has built in singletons. If you come from Java world, that was like a big deal to me. Because its either dependency injection (I really didn't need to be that fancy in this app), or having to create a whole class with single instance of itself with static method and all that. Yeah, its not hard, and yeah I've done it a million times, but it sure was nice to just go:1: object Config extends Config
2: class Config {
3: val systemProperties = System.getProperties()
4: val targetServer: String = loadProperty ("target.server","https://nightly.cle.rsmart.com/portal")
5: val sakaiVersion : String = loadProperty("sakai.version", "2.9.1")
6: val sakaiDistro : String = loadProperty("sakai.distro", "ani")
7: val defaultAdminEid : String = loadProperty("sakai.admin.eid", "admin")
8: val defaultAdminPassword : String = loadProperty("sakai.admin.pwd", "admin")
9: def defaultCourseSiteId = "course-test-1"
10: def defaultCourseSiteTitle = "Course Site Test 1"
11: def defaultInstructorEid = "instructor1"
12: def defaultStudentEid = "student01"
13: def defaultInstructorPassword = "password"
14: def defaultStudentPassword = "password"
15: def loadProperty (name : String, defaultValue : String) = {
16: if (!StringUtils.isEmpty(systemProperties.getProperty(name))) {
17: systemProperties.getProperty(name)
18: } else {
19: defaultValue
20: }
21: }
22: }
Now I had a nice Config object, defaulted by a properties file, overridable by system properties. I could call from anywhere else and not worry about injection or any of that business. Nothing fancy, quick and dirty, does the job:
Portal.navigateToPage(Config.targetServer)
You can pass functions around?!
So this is something every language but Java seems to have, but when you've been living without it for a long time... its like a conjugal visit. I had one piece of code that was basically the same as this other piece of code except for a block in the middle. So I move the two blocks into functions, and then invoked the surrounding method by passing that in and applying it at the right spot. Its too much code to share here, if you can see: https://github.com/johntbush/sakai-test-suite/blob/master/src/test/scala/com/anisakai/test/pageobjects/SiteManageTool.scala, look at the createProjectSite() and createCourseSite(). I think there is a better way to do that now that I know more, but whatever this is part of my journey.
More bad language, unfiltered opinions, and voodoo coming
Ok, all for now, next post I'll talk about my new project with Play! and emberjs, where we learn about implicit parameters, and implicit methods and all kinds of awesome voodoo that makes for some really concise and powerful code. Stay tuned more coming....
Let's get started
Ok first business first, the name was inspired by this guy, one of my heros.
So a bit about my background. I've been a software engineer for about 16 years. I started out in Perl, and then went to PHP, and then picked up Java in 2001'ish and have been doing that ever since. I'm not any kind of technology nazi. I learned Java for two reasons: #1 is was growing like crazy and there were jobs, jobs, jobs, #2 I had been bitten by dynamically typed languages and spaghetti soup and I wanted something safer.
Since then I've come to appreciate static typing, mostly because of the tooling it makes possible. Things like refactoring, instrumentation for profiling and root cause detection, auto completion, and all that good stuff are really hard to come by in dynamically typed languages. Hitting ctrl-space and getting every method every known to man, doesn't really help me. I view the compiler as my friend not enemy, especially when it comes to long build cycles, complicated unit testing, and hard to reproduce integration issues, its just another tool in my toolbox.
I've dynamically generated Java, and compiled it from a webapp (don't ask), I've instrumented it, I've used reflection to access private methods when I've needed to, I've generated byte code on the fly, I wrote a classloader than could load vendor provided classes over the wire so client code didn't have to include them, I even once modified java.lang.String to solve a problem until I read that was a violation of the Sun license. Having taken Java as far as I think a person possibly can, it was time to branch out.
I tried out Ruby. There's a lot of things I really like about Ruby. They are probably more related to Rails, then the language. I like how when they find a good way of doing something they make it the Ruby way (with the exception of package management, there seems to be a new way every time I turn around). They found a nice medium between strong typing and dynamic typing. But in the end, Ruby dependency nightmares, dynamic typing, weird threading model (maybe that is better now?), and the fact that it is interpreted, just don't do it for me. I feel like I've been there already with Php and Perl. Yes, the language has some really nice constructs, and Rails is a really good framework. But I'm thinking 5 years out, and it just isn't enough for me.
Groovy just makes no sense to me. Its like people took some of the best things about Java threw them out the window, because they wanted things to be less verbose. Great so you can not define types and pass hashmaps all over the place, and mysteriously pull things out of them using key names that I guess your mother in law has written down on some piece of paper tucked under her pillow. I just don't really get it. A lot of the grails plugins are half ass maintained. I read somewhere that if the creator of Groovy knew about Scala he would have never have written it. Which I don't really understand either because Groovy seems nothing like Scala, other than it runs on JVM and shares some syntax. Maybe he just realized he created a big steaming piece of poo and feels bad about it now. To me, it seems like Groovy has had its hey day, at this point if you like what Groovy is about, why wouldn't you just pick up Ruby?
A co-worker dropped Scala on my lap, and it made me curious, I started reading more, and starting really liking a lot of what I discovered. It runs on the JVM, operationally, that is great. You can call Java apis from it, awesome, I can re-use what I know. Multi-threaded, performant, garbage collection, monitoring, root cause detection tools, thread dumps, heap dumps, and the operational good stuff that I've come to rely on, are right there for me. A lot less verbosity than Java, lambas, multiple inheritance, built in singletons, and lots of mysterious functional goodness intrigued me.
My exposure to functional languages has been quite minimal. In school we learned ML for like a few weeks. I think things like XSL and SQL are functional in nature, and I've got those under my belt. I've always had a code style of trying to break things into smaller pieces. My favorite feature of IntelliJ is the refactor->extract method option. Every time a method starts taking up a large part of my screen, I know its time to invoke that thing. So with the naive perspective, I started my journey.
I had no idea my whole world was going to be challenged. We will get to that in time...
Subscribe to:
Posts (Atom)