Why I Chose Scala Over Java
I recently watched a “comment tennis match” between 2 people here on DZone where each was entrenched in their view of the Scala versus Java debate. I thought that I should give my reasons to make the switch since I recently did the “cross-over” to Scala after many years on the Java EE side.
Join the DZone community and get the full member experience.Join For Free
About 2.5 years ago, I made the switch from being a Java EE developer to being a Scala developer. I had worked with many Java EE codes bases from JBoss and Orion “EARs” to many Spring-based Tomcat "WARs" with Hibernate fronting the RDBMS of choice.
I recently watched a “comment tennis match” between 2 people here on DZone where each was entrenched in their view of the Scala versus Java debate. I very intentionally stayed out of the conversation since it was clear each of them was set in their opinions. That, however, sparked a thought that I should give my reasons to make the switch since I recently did the “cross-over” to Scala after many years on the Java EE side.
My main reasons for moving to Scala are:
- Time to Market; Speed of development and delivery to production.
- Total lines of code to maintain is far less in Scala.
- The need for 3rd-party libraries is much reduced, even eliminated in some cases.
- Built-in asynchronous threading and non-blocking IO throughout the language.
Time to Market; Speed of Development:
If you are getting paid to write software, then you probably have a time-to-market constraint on the software you write. This is where the power of Scala really shines over Java. In Scala, you are not limited to just OO patterns to implement your code; you can bring in functional paradigms as well. By utilizing the best parts of functional and the best parts of OO—with a little bit of Pattern Matching in the middle—you can write very concise, very readable, and very expressive code in a small number of lines. This results in tasks that are completed in hours instead of days with full units tests. The power of Scala has changed how we calculate expectations on velocity and throughput.
Once I got up to speed with Scala, its Monads, and the Functional paradigm it employs, I find myself writing, testing, and deploying code at a much faster rate than I did when I was writing in Java. But getting up to speed with Scala had been a challenge. It is not as simple as "read a few docs and then code" just like you did in Java. Good Scala requires a change in thinking about how to approach problems and thus code their solutions. Even though the learning curve has been a challenge, the rewards are paying off in big ways. What used to require 100s of lines of Java code across multiple files can now be done in as few as 10 lines in a single Scala file. The testing of the Scala code is also much simpler with the use of built-in higher-order functions that reduce the scope of what needs to be tested. All this is leading to ideas going from Whiteboard to Production in days, not weeks or months as was usual in Java code bases.
At my present company, we still have some code in a Tomcat app. When I have to go in to fix something there, the slow down in development is very apparent. It will simply take me longer get things coded, tested, and deployed in that environment. Even with the code generation refactoring tools of my IDE, there is so much extra verbiage to be typed that it demands more time to code and test the new functionality.
It has become clear that Scala is a positive ROI to our development effort.
Total Lines of Code
The power of a single line of Scala is impressive. In many cases I have found this to be in excess of 10 times less than in similar functioning Java code. In Java, a solution that contains 100 lines of code would frequently require multiple class files and sometimes even multiple packages to logically organize all the pieces and parts to a subsystem. In Scala, a single package object can collect the same functionality in 50 lines or less of Scala. See the next section on 3rd party libraries for an example of a data access layer replacement that really drove this point home for me.
As a developer, when you need functionality you do not currently have, you have to make a decision on whether to build the functionality or find a third party library that will do what you need. It can be one of the most important decisions you have to make as a lead developer or architect. In Java, I would often look for libraries to help avoid the long development and testing cycles needed to design and build desired functionalities. It was a pretty simple argument: anything bigger than size X, you need to find a library to help out.
In Scala, this line is not so clear. This is mainly due to the power of the Scala language itself. With its built-in higher-order functions and "everything’s a Monad” mantra, the power you have at your fingertips is much greater than in Java—even with the Java 8 enhancements. For example, our legacy Tomcat app used to front an RDBMS using a JPA-based data access layer powered by an EclipseLink implementation. Over several months and with only 500 lines of base Scala code, we migrated the entire database to MongoDB and the ReactiveMongo Driver while maintaining the top-level JPA interface for all Entities. No third-party library needed other than the MongoDB driver itself. This Tomcat app uses Spring MVC and JAX-RS Resources and Managers, which remained in place and are now talking to a Scala data access layer without any changes required. Most of the Java code is unaware that its JPA implementation is no longer a relational database, with the only exceptions being where we “improved the schema” to “fix” schema issues from the past.
The net effect is that we remove the dependency on JPA, EclipseLink, and all the secondary JARs that came with it while simplifying the code and gaining a much-needed increase in speed and throughput for our legacy app.
Built-in asynchronous processing and non-blocking IO
In Scala, Futures and asynchronous behavior are first-class citizens in the language. In Java, the Future is a bolt-on, and a marginal one at that, since it is not composable, which really limits its functionality. That asynchronous behavior is not only in the Scala language but also in many of the frameworks that you can to web application like Akka and the Play! Framework. Both of these libraries are fully asynchronous in behavior and make it easy to write your code in an asynchronous manner. Conversely, Java Enterprise was designed and conceived to be synchronous in nature. For me, Java EE’s had two main benefits that attracted me to it many decades ago but seem to no longer apply to my current architecture needs.
First, Java EE allowed you to organize all your code into a single application for easier deployment and code organization. You put all your “code eggs” in the application container “basket.” At the time, this made deployments easier and really solved problems for many organizations, which I think was a big reason for its large adoption. Today, machine-to-machine communication is commonplace, so having all your code run in the same application is not necessary—and even problematic—since deployments are now handled by Continuous Integration/Continuous Delivery build/test/deploy pipelines.
Second, Java EE focused on a “one-thread-per-request” model where you wrote your code knowing there would be 1 thread executing all the code needed for each request. This greatly simplifies the code you have to write while still giving you a “form of multi-threadedness.” This is the reason why many annotations use Thread Local Variables to work correctly in Java EE containers and have become so popular in many big-name frameworks, like Spring MVC and Hibernate, for starters. Personally, I think these “Magic Annotations" and their thread local variables are a bad idea and have caused me and others much pain in having to debug weird behavior issues over the years. But I will concede that, in Java, many of the features that these Magic Annotations implement are needed badly because there is currently no other way to accomplish these types of tasks with the current imperative nature of the Java language (without explicit parameter passing everywhere). Today, in our multi-core architectures, true concurrency and threading are more important than ever. Moving away from Java EE’s synchronous nature allows our apps to achieve full asynchronous and non-blocking IO behaviors, which in turn allow them to get more performance out of the hardware they have and increases the ROI of machine costs.
The decision to go to Scala has been a good one for me and my career. While I am currently still coding some in Java, I am happy about my decision to migrate my main development over to Scala.
Opinions expressed by DZone contributors are their own.