"The joy of Scala" - Maxim Novak / Wix
Around eight years ago I started my journey as a developer. Since then, I've played around with many languages and thought that C# offers the best developer productivity. After joining Wix two years ago, I was exposed to the amazing world of Scala and Functional Programming and never looked back.
In Scala the code is much more concise, less ceremonious, immutable by default, combines functional with object oriented, seamlessly interoperates with Java, and many software engineering patterns are already baked into the language. Most importantly - Scala is FUN! By the end of the session you too will, hopefully, convert to Scala and never look back.
Recording of the lecture (Hebrew) - https://youtu.be/TcnYTwff2xU
16. class Checkout(tax: Double) {
double total(final List<Product> products) {
return products
.stream()
.mapToDouble(Product::getPrice)
.sum() * tax
}
}
Return last statement by default
17. Return last statement by default
class Checkout(tax: Double) {
double total(final List<Product> products) {
products
.stream()
.mapToDouble(Product::getPrice)
.sum() * tax
}
}
18. class Checkout(tax: Double) {
double total(final List<Product> products) {
products
.stream()
.mapToDouble(Product::getPrice)
.sum() * tax
}
}
Method arguments are final by default
And the Name comes before the Type
19. Method arguments are final by default
And the Name comes before the Type
class Checkout(tax: Double) {
def total(products: Seq[Product]): Double = {
products
.stream()
.mapToDouble(Product::getPrice)
.sum() * tax
}
}
23. class Checkout(tax: Double) {
def total(products: Seq[Product]) =
products.map(_.getPrice).sum * tax
}
P P P P 1 3 7 4 15
.map(_.getPrice) .sum
Remove more boilerplate
27. Immutable by default
Prefer vals, immutable objects, and methods without side effects.
Reach for them first.
Use vars, mutable objects, and methods with side effects when
you have a specific need and justification for them.
- Programming in Scala By Martin Odersky, Lex Spoon, Bill Venners
“
”
http://www.yegor256.com/2014/06/0
9/objects-should-be-immutable.html
Easier to use = always thread safe = testable
28. Immutability
Set<Date> set = new HashSet<>();
Date date = new Date(2);
set.add(date);
date.setTime(4);
System.out.println(set.contains(date));
Easier to use = always thread safe = testable
http://www.yegor256.com/2014/06/09/
objects-should-be-immutable.html
HashCode Object
1
2
3
4
...
...
n
date
date
30. public class Product {
public Product(String name, double price) {
this.name = name;
this.price = price;
}
private String name;
private double price;
public double getPrice() {
return price;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Product{" +
"name='" + name + ''' +
", price=" + price +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass())
return false;
Product product = (Product) o;
if (Double.compare(product.price, price) != 0)
return false;
return name != null ?
name.equals(product.name) : product.name ==
null;
}
@Override
public int hashCode() {
int result;
long temp;
temp = Double.doubleToLongBits(price);
result = (int) (temp ^ (temp >>> 32));
result = 31 * result + (name != null ?
name.hashCode() : 0);
return result;
}
}
public void setPrice(double price) {
this.price = price;
}
public void setName(String name) {
this.name = name;
}
31. Case Classes
case class Product(name: String, price: Double)
Less code = Less bugs = Readable code = Easier to maintain
Indeed, the ratio of time spent reading versus writing is well over 10 to 1.
We are constantly reading old code as part of the effort to write new code.
...[Therefore,] making it easy to read makes it easier to write.
- Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship
“
”
32. Case Classes
case class Product(name: String, price: Double)
What else?
val book = Product("Book", 42)
val discountedBook = book.copy(price = 32)
33. Static Types Inference
Promotes better naming over type declaration
val i = 8
val s = "bar"
val withExplicitType: String = "baz"
val product = new Product(“name", 18)
val seq = Seq(1, 2, 3)
val withExplicitType: String = 8
Error:(4, 34) type mismatch;
found : Int(8)
required: String
val withExplicitType: String = 8
34. Static Types Inference
Promotes better naming over type declaration
val i = 8
val s = "bar"
val withExplicitType: String = "baz"
val product = new Product(“name", 18)
val seq = Seq(1, 2, 3)
def withString(s: String) = …
withString(i)
Error:(29, 16) type mismatch;
found : Int
required: String
withString(i)
^
35. private def add(a: Int, b: Int) = a + b
def add(a: Int, b: Int): Int = a + b
Static Types Inference
Promotes better naming over type declaration
47. def javaApi(): SomeType = ...
val result = Option(javaApi())
NullPointerException – Never Again
Java Libraries
Working with Java? Just wrap it with an Option
48. Meet Scala’s Try
The flow is clear when it comes to Exceptions
Try [ T ]
Failure Success [ T ]
49. Why I Scala
1. Use types to understand functions
2. Elegant flow
50. For Comprehension
case class Photo(url: String)
case class Product(name: String, photo: Photo)
def photoUrl(product: Product) = {
var url: String = null
if (product != null) {
if (product.photo != null) {
if (product.photo.url != null) {
url = product.photo.url
}
}
}
url
}
51. case class Photo(url: String)
case class Product(name: String, photo: Photo)
def photoUrl(product: Product) = {
var url: String = null
if (product != null) {
if (product.photo != null) {
if (product.photo.url != null) {
url = product.photo.url
}
}
} url
}
case class Photo(url: Option[String])
case class Product(name: String, photo: Option[Photo])
def photoUrl(productOpt: Option[Product]) =
for {
product <- productOpt
photo <- product.photo
url <- photo.url
} yield url
52. Why I Scala
1. Use types to understand functions
2. Elegant flow
3. Powerful Pattern matching
53. Pattern Matching
A more powerful switch/case
val x: Any = ...
x match {
case 1 => "It's an integer 1"
case "1" => "It's a String "1""
case b: Boolean => "It's the a boolean : " + b.toString
case i: Int if i > 0 => "It's a positive Integer : " + i
case _: String => "It's a String, don’t care the value"
case _: Float | _: Double => "Something numeric"
case _ => "Didn't match any condition"
}
54. val obj: AnyRef = ...
obj match {
case Product(_, 0) =>
println("FREE! Don’t care about the name")
case Product(name, price) =>
println(name + " cost" + price)
}
Pattern Matching
Extracting Case-Classes
case class Product(name: String, price: Double)
55. val url: java.net.URL = ...
url match {
case HTTP(address) => "HTTP! It’s : " + address
case _ => "Unknown protocol"
}
object HTTP {
def unapply(url: URL): Option[String] =
if (url.getProtocol == "http") Some(url.toString)
else None
}
Custom Extractors
Make your code cleaner by extracting the how to’s
56. val url: java.net.URL = ...
url match {
case HTTP(address) => "HTTP! It’s : " + address
case FTP(address) => "FTP! It’s : " + address
case File(path) => "File! It’s : " + path
case CustomProtocol(foo, bar) =>
"Custom! It’s : " + foo + "/" + bar
case _ => "Unknown protocol"
}
Custom Extractors
Make your code cleaner by extracting the how to’s
57. Why I Scala
1. Use types to understand functions
2. Elegant flow
3. Powerful Pattern matching
4. Awesome Parameters
69. Why I Scala
1. Use types to understand functions
2. Elegant flow
3. Powerful Pattern matching
4. Awesome Parameters
5. Easier Strings
70. String Interpolation
More readable, Use $ for variables
val name = "Max"
val lang = "Scala"
val desc = s"Hello $name. $lang is awesome!"
Hello Max. Scala is awesome!
71. Quotes & Multiline
More readable, Easier to implement
val withQuotes =
"""Now I can use "quotes" without escaping"""
val multiline =
"""{
"firstName": "John",
"lastName": "Smith",
"age": 25
}"""
72. Why I Scala
1. Use types to understand functions
2. Elegant flow
3. Powerful Pattern matching
4. Awesome Parameters
5. Easier Strings
6. DSLs
78. Infix Notation
val c = "foo" concat "bar"
“The binary operation E op E` is always interpreted as the
method call E.op(E`) “
-- Martin Odersky (Scala By Example)
https://www.scala-lang.org/old/sites/default/files/linuxsoft_archives/docu/files/ScalaByExample.pdf
80. DSL Made Easy
specs2 example
class SampleTest extends Specification {
"The 'Hello world' string" should {
"contain 11 characters" >> {
"Hello world" must haveSize(11)
}
}
}
87. Migrating from Java
You can do it! Things working for you:
All Java libraries that you know and love
work in Scala too
88. Migrating from Java
You can do it! Things working for you:
You can start imperative and
move to functional, decide
where you want to be
89. Migrating from Java
There are caveats. Things working against you:
(Too much?) freedom
in programming style
http://www.lihaoyi.com/post/StrategicScalaStylePrincipleofLeastPower.html
Hi, good afternoon!
Today you’ll get introduced to Scala, and I’ll explain to you why I think that it’s an awesome language. You really should follow this talk, because, seriously, it can really change your professional career.
After this talk you’ll think yourself - how did I spend all these years writing Java.
And even in the rare case that you won’t move to Scala it might change the way you think about your Java code anyway.
Just to get to know you -
Who already played with Scala?
My name is Maxim Novak. I’m in the software industry more than 9 years. Around 3 years ago I’ve joined Wix and since then I’m an avid Scala advocate.
In Wix we use Scala as our main language for backend development.
Today, I’ll share with you my experience with Scala and why I think that you should move.
So what’s Scala? Why do we actually need it? And why is it called the better Java?
It’s another programming language that works on the JVM.
It’s a modern language with many features that help to our productivity as developers
We enjoy from the rich and proven JVM ecosystem which includes tools, libraries, and reliable runtime
I believe that by the end of this session you’ll be convinced that you should at least give it a try.
...
This session will have 2 parts.
In the first part I’ll tell you about the benefits of Scala and why do I think that it’s the best programming language in terms of developer productivity.
In the second part we’ll talk about how do we move to Scala from Java or any other(JVM/Not) language.
We’ll have some time for questions in the end, but if you feel that you need to ask something during the talk feel free to do ask.
In this talk you’re going to see just a small portion of Scala’s features. We’ll cover some simple concepts that have a big impact on the way you develop software.
In most of the samples today I’ll show a comparison between Java to Scala code.
So we’ll start with conciseness.
To get some feeling of the language we’ll start with a Java sample and convert it to Scala step-by-step.
Java is great language, but the problem with it - tons of boilerplate and ceremony.
Scala help us with this matter. You concentrate on solving a business problem most of your time instead of just typing.
Let’s start with an example.
We see a `Checkout` class. It’s pretty straightforward, get a tax in the constructor and can calculate the price for a products list.
This is how it looks with Java7. I show you this because, there’s still a lot of Java7 code and many of us need to work with Java7 codebase. (45.5% as to 2016, same for java8, 9% java 6 - ohh .. these poor people)
Who works on the JVM? Who uses Java8?
When Java8 released some people said - now we don’t need Scala, Java8 solve the problems for us.
So we’ll transform this code to Java8 and then to Scala to see the gain of each change.
Few words about Java8 - it proves that Scala goes in the correct direction.
This sample does the same as the prev, but Java8.
As you can see, the change is not dramatic.
We can see the functional style of the total method (kind of similar to Scala).
Let’s start converting it to Scala
In Java the default access modifier is `package-private`, so in many of our classes we explicitly need to declare that they’re public.
In Scala the default is public.
We don’t really need the semicolon in end of any line.
In Scala the compiler is smart enough to understand. It uses a look ahead technique to understand the meaning on a new-line.
Actually you can keep it, sometimes new Java developers do, but there’s really no need.
The constructor and the field. All what we want to say here that we want to save the tax as a class member. A lot of boilerplate.
Another thing is the `return`. Also not necessary. You can use it but really no need to.
The last line will be used as the return value.
In java it’s considered as a bad practice to change the value of a parameter, so we can say `final`, but we don’t want to do it for all of our parameters. If we change it we’ll get a compilation warning. Therefore, in Scala it’s the default.
Moreover, we can see that we switched the order of the variable type and the name. There’re 2 reasons -
Scala consider the name as the more important part, so it’s first
It goes easier with `type inference` which we’ll see soon.
The compiler can understand that we’re summing a Seq on doubles and multiply it by a double so it can understand that the return type of this method is a double. So we can remove it as well.
Even more boilerplate. We don’t care about the `stream` part.
Just by coincidence the price is a double and we have `mapToDouble`, if it was `Dollar` or something else it would be harder.
That’s how it will look in Scala!
And I even have a cool animation here
Let’s see side-by-side comparison.
Anyone still not convinced?
Come on! It’s the same size of the java HelloWorld.
In imperative language like Java a computation is usually done by mutating variables and this way progress with the computation. On the other hand functional programming have pure functions that get input and return output without mutating variables.
The functional way in many cases is cleaner and simple.
So immutability fits well with functional programming style.
...
Why most people write mutable code in Java? Because this is the default and developers usually will do the default.
When using less mutable state and more functional style
Easier to read/understand/reason about the code (predictable, local reasoning)
Reduce bugs
Easier to test
Behaves better in multithreaded environment.
And yes, you can do it in Java, but in Scala it’s much easier, and that’s the default.
You want to see real life example, right
Just to illustrate how easily mutable state can cause bugs.
And this is a very simple example, even not multi-threaded
Domain objects is something we create a lot. Let’s see a Java sample.
In this example we see a class that describes a Product.
Mention that we don’t want setters
Do you think that this is a reasonable amount of code for what we get?
Would you be happy to write less code? What do you say about one line?
So with Scala you can!
This is how this looks with Scala!
Now, you probably say actually no one really write this code, the IDE generate it for us. So in Java not only that we have a complicated language, now we need a complicated IDE to manage it.
Quote by Uncle Bob - Most of the time we read code. We want our code to stay clean.
In Scala the compiler generate all this boilerplate for us.
You can create it without the `new` keyword, this is also reduce boilerplate and also cool because you can just pass it as a function.
Another thing, because it’s immutable, we get the `copy` method on any case-class. This allows us to create new case-classes from existing ones.
Extractors - We’ll talk about them later when we get to pattern matching
With Scala you don’t have to declare the TYPE of the field. You can if you want to.
We alrady saw this before, the order of the decleration (type/name) is reversed from Java.
More emphasis on the name then on the type.
It’s important to notice that the language is statically typed, so if we break the rules - we’ll get a compilation error.
With Scala you don’t have to declare the TYPE of the field. You can if you want to.
We alrady saw this before, the order of the decleration (type/name) is reversed from Java.
More emphasis on the name then on the type.
It’s important to notice that the language is statically typed, so if we break the rules - we’ll get a compilation error.
Also works for methods.
By convention usually we’ll declare the type in public methods to break in case of change in public API, but in private methods we’ll omit it to allow easier change.
Now let’s see some more modern constructs that will help us to organize our code.
In Java - we call a method. But we don’t really know what we get as a rusult.
Let’s have a look at this Calculator example. What will happen when we run this code?
The method signature states that it returns a Double but it lies.
Actually, there are few options. We can read the documentation, or write a test that checks this code.
using `null` as a result is a bad practice because many times bugs lead to nulls so when we have it we don’t know if it’s intended null or because of a bug
ArithmeticException is unchecked so the caller can’t know it might be thrown.
In scala we’ll usually solve this problem in the type system level.
Option is a container type that can contain a value or be empty.
For example, in our calculator example a result when a function is undefined.
So let’s change the signature of the function and now it’ll return Option[Double]
Now how we work with this Option? We can do it in imperative style like Java.
Or we can go a bit more functional.
.map works on an Option exactly like a collection with one element or empty.
Also note that we don’t have the mutable state anymore.
You can do it even shorter.
In addition, we have more goodies that help us to work with Option.
For example - default values.
Fallback value
What about existing Java codebase that can return `null`?
Easily just wrap it with option.
Just wrap your APIs that can return null with Option.
And you’ll never see a NPE anymore
Try is very similar to Option. It’s also a container type that can hold a successfull result or a Failure with a Throwable.
It works very similar to Option so I’ll skip it in this talk.
I assume that practically everyone in this room wrote a code like this one.
Let’s convert the Optional parameters that can be null to an Option type.
Then I’ll show you how you can benefit from a construct that’s called `for comprehension`.
Instead of checking nulls and catching exceptions – options are defined. If they’re none we do something if they’re some we do something else.
AnyRef is similar to a Java’s `Object`.
If you’re working with a class that’s not a case-class, for example Java code.
You can write your own extractor to any class.
Then our code will look cleaner.
Default parameters make our life much easier when we have to deal with many parameters
In this example we’re looking at a DatabaseConnection sample class.
So when we start, we make sure that the constructor get the needed parameters.
But the we found out that in most cases we don’t change the port, so we decide to add another constructor.
Let’s say it’s mysql so the default port is 3306.
But then, we find out that usually we use ‘localhost’ as the host, so we add another one
And again, we don’t want the credentials to be mandatory so we add another one
But now, we have a new use case when we want to specify the host, but not the port.
So in this case it’s doable because the host is a String but the port is an int, but if they both would be strings it’s getting complicated.
So In java we have a solution for this.
The builder pattern, but still that’s a lot of code to write.
And the as the user of the class you need to know about the Builder to build the connection.
In scala we can use default parameters to solve this problem.
This DatabaseConnection class will look like this.
We can use ordering
Or naming.
Named parameters have another advantage.
This is Java’s File API.
Who knows what’s the true, false means?
So there’s a way to write it in a more readable way.
Extract variables
In Scala it’s even easier.
Default parameters make our life much easier when we have to deal with many parameters
Quotes and multiline
Domain Specific Languages
This example is taken from the source code of the Scala Compiler
We can use `Implicit Class` to extend existing classes.
In this case they extended the java File class and added to it 2 methods.
To use it, all we need to do is make sure that we have this class in the scope and we can call them as they’re methods on this class.
The IDE will signal to us that the method `isClass` is an extention
The IDE is even powerful enough to find which `implicit class` we’re using here
Using this, we can write something like this.
This expression returns a class of type Range which is actually an `Iterable`
Remember this example, we’ll get back to it shortly.
We all know how we invoke a method on a class.
For some operators we can do it a bit differently, although it’s actually the same thing. If you think about it. We’re invoking the `+` function on a class of type String and giving it another string as an parameter.
In Java, actually the compiler is taking care of this + operator on the string, converts it to a StringBuilder and calls the .append method.
So in Scala, we can do it with any method name. It’s perfectly fine.
Odersky’s quote
Now, let’s combine these two features.
And a `for loop`, will look like this
specs2 is a well known testing library in the Scala ecosystem.
I want to show you the DSL they built to write tests.
The added some methods on a `String` to let you do that.
Also, look at the test itself, it also looks like English
This is how it looks in the IDE when we run the tests.
Finally we can have nice human readable tests descriptions easily
So in addition to that I like Scala and I think that it’s awesome.
It got pretty high score as a Loved language in stack-overfllow’s developers survery for 2016
Also, at least in the US, it’s the most well paid language.
OK, so we all convinced that it’s good for us, now let’s talk about how to we start.
First of all you should know that you’re not alone. Many big companies already use this technology in production and the community is getting bigger and bigger all the time.
So not only that it’s cool, we can definitely say that the technology is production prooven.
If you’re a JVM shop, it’ll be very easy for you to move to Scala.
You already have the runtime on your production servers, you can keep using your build tools, your IDE, benchmarking tools
Basically you're already familiar with the tools you need.
All the eco-system is available for us - all the JVM libraries.
You can start writing imperative style (Jala), and gradually move to be more functional.
It’s a hybrid imperative/functional language and you can choose the style.
You can use concepts from both worlds of OOP and functional programming.
You can start writing Jala in a matter of days/weeks.
You can combine Scala classes together with Java classes in the same project.
An important note for beginners, you don’t have to know everything, you can make a progress gradually.
The move from Java can be incremental.
If I’ll say that all is perfect, you probably won’t beliebe me.
Not everything is perfect, and you should be aware of that.
One big critisism of Scala is that it’s very easy to write code that is hard to read later.
Too much freedom - but you’ll get used to write idiomatic Scala. I like this freedom, but you should be responsible. A rule that I always use is to use the most simple tools to solve your problem. Recommended blog post.
Longer compilation time. Because the compiler is much more powerful and smart it takes longer to compile your code.
This is improving all the time.
In Wix we have microservices architecture so we have many small apps so the compilation time is not a problem for us.
In larger apps it can get noticeable and annoying.
Less tooling. There are many tools from the JVM world that you can use with Scala, but some tools still not complete. For example - the IDE (debug, refactor). Getting better all the time.
Also cluttered stack traces.
Because Scala cought popularity lately, it’s hard to find experienced Scala developers. In Wix we’re aiming to hire the best software engineers that can write any language and not a specific language software developer. The good software engineers will be happy to learn new exciting language and concepts. So this is even a kind of filter.
Needless to say that it also have a cost of education and mentoring after the hire.
So you’re in the Java world and you want to move to Scala, here are few tips that will help you to get started.
Let’s go over the steps.
If you don’t feel comfortable enough to write your production application in Scala you can start with the tests. Scala have few great testing frameworks like specs2 which we use at Wix and scala-test also good one.
You can start writing new classes in Scala while old classes still in Java.IDE can convert to Jala, then refactor. This will make your classes much shorter and more readable.
Yes, you see this correctly
Just one click
3. Scala has its own collections library. To avoid the friction use Javaconversions
4. If you work with libraries that rely on getters/setters you can use @BeanPropery annotation.
5. Tip to save the history. Change the filename, commit, then change the content and commit again.
...
To wrap up - we covered very briefly some of the basic concepts of Scala, why this is good for you and you got some tips to start using Scala.
Hope that you all enjoyed and you already started planning the move :)
Look, there’s a learning curve, but when you know it well you’re super productive - in orders of magnitude.