Why Test Engineers Should Learn Scala

Technical testers are often in a role where they have to utilize a programming language in order to build their own tools. Many testers will focus on languages like Ruby and Python for those solutions. The reason for that is because in the open source testing community, those languages do tend to be the focus of test solutions, the usual reason being given that they are “dynamic” languages. I’ve been in that same camp for a long time now. But there are cool alternatives worth exploring.

It will surprise no one that a lot of places these days are using Java as their primary development language. Sometimes those development shops will also want to develop their test solutions in Java as well, if for no other reason than to get developers involved. A lot of testers resist that, preferring the dynamic languages for the perceived flexibility that those languages allow. The thought often being that Java or C# simply can’t do what those languages can do. To be sure, there is a lot of truth to that and I showed one example of that when I wrote a simple dynamic test language.

Java has a reputation among many developers as a language that has gotten a little (or a lot) bloated and has not evolved quite as well as its younger cousin, C#. Many test solution developers dislike even the thought of working in Java. To be sure, it’s certainly tempting to prefer the relative simplicity of dynamically typed languages. Yet this simplicity can be deceptive. In a dynamically typed language, it’s often necessary to use metaprogramming features to implement advanced designs. Metaprogramming is no doubt powerful and it certainly gives you a little street cred, using it effectively takes a good deal of experience. Projects that rely on a lot of metaprogramming “magic” can be hard to understand, maintain, and debug. (I can vouch for that with some aspects of my own programming projects Symbiont and Lucid.)

What changed my thinking was you can consider the Java Virtual Machine (JVM) as your test execution platform without necessarily using Java as your test development language. In the development world, many developers believe that using the JVM with new languages is the path forward and I think testers should also embrace that kind of thinking. Certainly I was aware of all this since the implementations of JRuby and Jython — JVM ports of Ruby and Python, respectively — have been around for awhile.

But then I came across Scala. Scala is a statically-typed, mixed-paradigm language. Scala also happens to be a language that runs on the JVM. So if you find yourself often constrained by Java — or wary of its bloat — but needing to use it to craft test solutions, consider Scala. It’s what I ended up doing and I was pleasantly surprised. To make that point, I’ll use the rest of this article to bring up the basics of Scala and show a little of the language so that you can compare it with languages you might know.

Incidentally, in case you were wondering, Scala is meant to be a contraction of SCAlable LAnguage. That might lead you to logically conclude that you pronounce it as scale-ah. Nope. The creators actually pronounce it scah-lah.

The Paradigms of Scala

Scala focuses on two “paradigms” of development: object-oriented programming (OOP) and functional programming (FP).

Most test developers are aware of what OOP is but perhaps not so much what FP is. Basically, FP is an approach that treats computation as the evaluation of mathematical functions and avoids state and mutable data. Obviously I’m generalizing and simplifying there but it will do for now.

Java already does OOP, so why turn to Scala for that? Mainly because Scala improves Java’s support for OOP with the addition of a feature known as traits. Essentially this is a way of implementing classes using the technique of mixin composition. If you’ve used Ruby, you’ll find that Scala’s traits work much like Ruby’s modules. If your focus is Java or C#, you can think of traits as a mechanism that unifies interfaces with their implementations. What this approach does is put a lot of emphasis on composability, which is a bit too large of a topic to go into now. But essentially what you can note is that Scala uses a pure object-oriented model where every value is an object and every operation is a message send. That means that this expression

2 - 1

is interpreted this way by the Scala compiler:

2.-(1)

Ruby programmers will recognize that right away; it means you’re invoking a – operation on an integer object (in this case, 2) by passing 1 as a parameter.

Java doesn’t do FP. But if you’ve used languages like Erlang, F#, or Haskell you’ll know that a core idea of FP is that functions are “first-class” citizens. Scala agrees and implements them as such. What this means is that functions can be assigned to variables, passed to other functions, and returned from functions, just like other values can. This means that you can assign the following function to a value identified as subtract:

val subtract = (x: Int) => x - 1

You can then use subtract to invoke that function:

subtract(1)

So you can see that this feature also promotes composition of advanced behavior by using primitive operations. Again, Scala provides all of that. Incidentally, because Scala adheres to the dictum that “everything is an object” — in a way that Java doesn’t — functions are themselves objects in Scala.

Scala Uses Both FP and OOP

The point here is that Scala uses FP and OOP together. The reason these are different paradigms is because they have different approaches. For example, in FP, functions have no side effects and variables are immutable. In OOP, on the other hand, mutable state and side effects are common, if not encouraged by certain design patterns. Scala lets you choose the approach that best fits the problem you are designing a solution for. That matters for test developers just as much as it does for any other developers. Functional programming is especially useful for concurrency, since it eliminates the need to synchronize access to mutable state. However, “pure” FP can be restrictive. Some design problems are easier to solve with mutable objects. So, again, Scala lets you have both and decide how and when to implement them.

Scala also offers closures, a feature that dynamic languages like Python and Ruby have adopted from the functional programming world. Closures are functions that reference variables from the scope that encloses the function definition. So the idea here is that the variables aren’t passed in as arguments or defined as local variables within the function. Instead, a closure “closes around” these references, so that the function invocation can safely refer to the variables even when the variables have gone out of scope.

Scala on the JVM … and the CLR

While Scala is primarily known as a JVM language, meaning that Scala generates JVM bytecode, a .NET version of Scala that generates Common Language Runtime (CLR) bytecode exists as well. (I’m not sure how good it is at this point since I haven’t played with it yet.) Scala compiles to Java bytecode, and at the bytecode level you can’t distinguish between Java code and Scala code. Part of the reason this works is that the Scala compiler uses various techniques to map Scala extensions to valid bytecode idioms. What that means is that from Scala, you can easily invoke byte code that originated as Java source (for the JVM) or C# source (for .NET). Conversely, you can invoke Scala code from Java, C#, etc.

Whether running on the JVM or the CLR, the importance of this is that it allows the Scala developer to leverage available libraries and to interoperate with other languages hosted on those runtimes.

Scala — It Can Be Your Ruby or Your Python

So going back to the dynamic languages that many test developers prefer, in a language like Scala, many of the same design goals can be achieved — but in a type-safe manner by exploiting the sophisticated type system as well as using mixin composition via traits. If you’re not certain of the term, a mixin is a class that provides certain functionality to be inherited by a subclass and isn’t meant for instantiation by itself. A mixin could also be viewed as an interface with implemented methods.

Scala is type-inferred language and thus takes care of most of the boilerplate code for you, removing a lot of the concerns test developers have over working with statically typed languages. The technique of type inference takes you close to a dynamically typed language, but with all the benefits of a statically typed language.

So while I promoted Ruby in my previous post — and will always enjoy the language — what I want to make clear here is that you don’t give up as much as you think by going from a dynamic language to something that runs on the JVM. I was of this mistaken opinion and I’m learning now that my viewpoint was limited.

Some Example Scala

I know when I come across a new language — at least new to me — I need to pretty quickly be able to see how it is and is not like other languages I have used. So here I’ll use a really simple example written in Scala and break it down a bit. If you want to play along and you have Scala installed, create a file called myfirst.scala and put the following in it:

You can see that Scala can use single line comments (like C++) or multi-line comments (like C). Obviously these comment styles are used in many languages, like Java, C#, PHP, and Perl as well.

The Person class begins with the class keyword. The class body is inside the outermost curly braces ({…}). That’s obviously like Java, C++, and C# and any other language that uses curly braces to designate blocks.

The info method definition begins on the second line with the def keyword. That makes it like Ruby or Python, which also use def to define a method. The method name is provided (info) and then an argument list in parentheses. A colon is used to show the end of the parameter lists and the start of further information, which is sort of like Python. Next the return type of the method is listed. Finally there’s an equals sign, and then the method body.

Speaking to the arguments first, note that explicit type information for variables is provided with colons after the variable name. This is very much like how Pascal does things. So instead of Java and C#’s “type name” convention, Pascal’s “name: type” convention is used. So, for example, the variable named ‘name’ is of type String, the variable named ‘age’ is of type Int. The variable ‘action’ is actually a variable-length argument list of the type String. That’s indicated by the String* type following the colon. This means you can pass in as many comma-separated strings as you want. These strings will be stored in the argument named action. This is basically the varargs concepts and is similar to using an argument name like *args in Ruby or Python or using the ellipsis (…) in Java (versions 5 and up).

Note that the the return type is Seq[String]. Here Seq (meaning “sequence”) is a particular kind of collection, sort of like an Array. The reason for the format is that Seq is a parameterized type, just like a generic type in Java. Here the type is parameterized with String and you’ll note that Scala uses square brackets ([…]) for parameterized types, whereas Java uses angle brackets (<...>).

The body of the info method comes after the equals sign (=) and the reason for using this and not curly braces is because the braces themselves can be omitted in various situations. The equals sign also shows that even methods — which are basically functions attached to an object — are values in Scala. This is also a bit like JavaScript such as when you create object literals:

The method body of my info method calls the map method on the action variable. The map method takes a function literal as an argument. Function literals are “anonymous” functions. They are similar to lambdas, closures, blocks, or procs in other languages. The function literal here is:

This takes an argument list with a single String argument named s. The body of the function literal is after the => operator and it calls the toUpperCase() method on s. The result of this action is returned by the function literal.

It’s important to note that in Scala, the last expression in a function is the return value, which is just like how Ruby does things. And, as with Ruby, you can certainly use explicit return statements as well.

To actually use this class, I create a new Person instance and assign it to a variable named person. As in Java, C#, and similar languages, the new operator creates a new instance. The person variable is declared as a read-only value using the val keyword. I could have done this:

The difference here is that val defines a fixed value whereas var (as in JavaScript or C#) defines a variable. Although do note that in C#, var is used to support anonymous types. In JavaScript, the use of var is to determine scope aspects.

Finally, at the end, I call the info method on a set of data and then print out the result with Console.println(), which is equivalent to Java’s System.out.println(…).

Running Scala … as a Script

This script has to be passed through Scala via this command:

scala myfirst.scala

So note here that you are running a Scala script just as you would a Ruby, Python, or Groovy script. You are not compiling anything. No class files are going to be generated. If all goes well, you’ll see output like this:

ArrayBuffer(TESTING SCALA)

Simplifying Scala

You can probably see that the ‘name’ and ‘age’ values are not really being used at all here and should probably be removed. Before I do that, let’s consider how the above code could be simplified:

Before explaining this change, this even more clearly starts to call out that my name and age variables aren’t used. So getting rid of these gets me this:

Here Person is now declared as an object, which is a singleton. I’m declaring a class, but the Scala runtime will only ever create one instance of Person. Scala uses objects for situations where other languages would use class level members, such as adding the qualifier ‘static’ to a class in Java.

The implementation of the info method has changed quite a bit. Scala can usually infer the return type of the method so here I dropped the explicit declaration. Do note that Scala will not infer the types of the method arguments. Also, because there is only one expression in the method body, I’ve gotten rid of the curly braces and put the entire method definition on one line. The equals sign before the method body tells Scala where the method body begins. I’ve also used a shorthand for the function literal. Previously I wrote it like this:

Now I’m writing it like this:

That’s a fairly big change, or so it appears, right? Because the map method takes one argument, which will be a function, I can use the “placeholder” indicator _ instead of a named parameter. So what this means is that the _ acts like an anonymous variable, to which each string will be assigned before the toUpperCase method is called. This is perhaps a tiny bit like how you might use $ when using jQuery and perhaps similar to using the * in Java when importing packages. Note that the String type is inferred as well. The _ placeholder can be used in various places in Scala and it will mean different things depending on context. This is an area of controversy among those who play around in Scala. Just know that you don’t have to use it; you can be more explicit.

On the last line of the changed code, note that I’m using an object rather than a class and that can help simplify the code. Instead of creating an instance with “new Person”, I just call the info method on the Person object directly. This looks like the syntax you would use when calling static methods in a Java class or class methods in a Ruby or Python class.

Finally, as a last little change, Scala automatically imports many methods for input/output activities. That means I don’t need to call Console.println() but, rather, can simply refer to the method println().

Compiled Scala

The script above runs by being interpreted. I can make a compiled version of this script by changing mscript.scala to this:

Now the info method has been renamed main. Because Person is an object, this main method works exactly like a static main method in a Java class, serving as the entry point to the Person application. In Scala, main must be a method in an object and you can contrast that with Java, where main must be a static method in a class. In this case, the command line arguments for the application are passed to main in an array of strings, which will be stored in the args variable.

The first line inside the main method uses the same shorthand notation for map that I just went through with the placeholder:

The call to map returns a new collection. I iterate through that collection with foreach. Note that I’m using a _ placeholder shortcut again in another function literal that gets passed to foreach. In this case, each string in the collection is passed as an argument to printf:

These two uses of the _ placeholder are completely independent of each other. Method chaining and function-literal shorthands, as I’m doing in this example, can take some getting used to, but you can probably see why this is an area of implementation controversy within the Scala development community. Once you get used to the idiom, the placeholders can yield readable code with minimal use of temporary variables.

To get the logic to work, you must first compile the code to a JVM .class file using scalac:

scalac myfirst.scala

You should now have a file named Person.class, just as if you had just compiled a Java class. You will also have some other class files that were generated based on the structure of the code. Now, you can execute this command for any list of strings, like this:

scala -cp . Person testing scala

The -cp . option adds the current directory to the search class path, just as you would do with a Java program.

You may have noticed that the compiler did not complain when the file was named myfirst.scala but the object was named Person. Unlike Java, the file name doesn’t have to match the name of the type with public scope. In fact, unlike Java, you can have as many public types in a single file as you want. Also note that the directory location of the program file does not have to match the package declaration, although you can use a package namespace concept with Scala if you want to.

So … Scrap Ruby, Go With Scala?

This post was not intended to sell you on Scala except insofar as to show you that you might want to give it a chance. I did and I’m massively impressed with it. I’m still learning but I’m finding there is a lot of expressive power with Scala and, as I hope I showed in this post, Scala uses many idioms from various languages that make it somewhat easy to pick up, particularly if you fashion yourself a polygot programmer.

This post also did nothing at all for convincing you that Scala would be a better language to craft test solutions in. I don’t think it is “better” in some categorical sense. But, at least for me, Scala is proving to be a fascinating middle ground where I can apply my knowledge and desire for Ruby-type logic and code constructs while also gaining the benefits of a Java-like language with the help that static typing affords as well as the ability to use the JVM as my execution platform.

I expect I’ll be posting more on Scala in the months to come. In the meantime, happy exploring!

Share

About Jeff Nyman

Anything I put here is an approximation of the truth. You’re getting a particular view of myself … and it’s the view I’m choosing to present to you. If you’ve never met me before in person, please realize I’m not the same in person as I am in writing. That’s because I can only put part of myself down into words.

If you have met me before in person then I’d ask you to consider that the view you’ve formed that way and the view you come to by reading what I say here may, in fact, both be true. I’d advise that you not automatically discard either viewpoint when they conflict or accept either as truth when they agree.

This entry was posted in Career, Learning. Bookmark the permalink.

2 Responses to Why Test Engineers Should Learn Scala

  1. Peter says:

    I think Not just test engineers, Instead Java dev should now look to Scala. This article has covered some difference between Scala and Java and also shared few resources to learn Scala.

    • Jeff Nyman says:

      I agree, Peter: those who want to write apps for the JVM should learn Scala. That said, I think such learners should devote as much time to Groovy and Clojure as well. Scala does have some peculiarities that can be good, but can also be a bit off-putting if you don’t need a lot of the functional features.

      For example, for test engineers writing test solutions, I would still say Groovy offers a better alternative in many cases.

      That said, I will say I personally find Scala to be a very elegant language and it does teach you how to think in a functional paradigm in slightly easier way than, say, Clojure or Haskell.

Leave a Reply

Your email address will not be published. Required fields are marked *