joy of scala

86
The Joy of Maxim Novak @maximnovak [email protected] https://github.com/ maximn Or : Why I love Scala

Upload: maxim-novak

Post on 15-Apr-2017

11.767 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Joy of scala

The Joy of

Maxim Novak

@maximnovak

[email protected] https://github.com/maximn

Or : Why I love Scala

Page 2: Joy of scala

The Joy of

Maxim Novak

@maximnovak

[email protected] https://github.com/maximn

Or : Why I love Scala

Page 3: Joy of scala

HiI’m Maxim Novak.

• Working on Wix’s back-end• 8 years in the software

industry• 2 years avid Scala advocate

Page 4: Joy of scala

Scala is the better Java.

Page 5: Joy of scala

Scala is the better Java.

Page 6: Joy of scala

Simple conceptsBig impact

Page 7: Joy of scala

Why I Scala

Conciseness

Page 8: Joy of scala

public class Checkout { private double tax;

public Checkout(double tax) { this.tax = tax; }

double total(final List<Product> products) { double total = 0.0;

for (Product product : products) { total += product.getPrice(); }

return total * tax; }}

Java (7) Checkout class

Page 9: Joy of scala

public class Checkout { private double tax;

public Checkout(double tax) { this.tax = tax; }

double total(final List<Product> products) { return products .stream() .mapToDouble(Product::getPrice) .sum() * tax; }}

Java (8) Checkout class

Page 10: Joy of scala

public class Checkout { private double tax;

public Checkout(double tax) { this.tax = tax; }

double total(final List<Product> products) { return products .stream() .mapToDouble(Product::getPrice) .sum() * tax; }}

Public by default

Page 11: Joy of scala

Public by defaultclass Checkout { private double tax;

public Checkout(double tax) { this.tax = tax; }

double total(final List<Product> products) { return products .stream() .mapToDouble(Product::getPrice) .sum() * tax; }}

Page 12: Joy of scala

class Checkout { private double tax;

public Checkout(double tax) { this.tax = tax; }

double total(final List<Product> products) { return products .stream() .mapToDouble(Product::getPrice) .sum() * tax; }}

No need for semi-colons

Page 13: Joy of scala

No need for semi-colonsclass Checkout { private double tax

public Checkout(double tax) { this.tax = tax }

double total(final List<Product> products) { return products .stream() .mapToDouble(Product::getPrice) .sum() * tax }}

Page 14: Joy of scala

class Checkout { private double tax

public Checkout(double tax) { this.tax = tax }

double total(final List<Product> products) { return products .stream() .mapToDouble(Product::getPrice) .sum() * tax }}

Concise constructor and fields

Page 15: Joy of scala

Concise constructor and fields

class Checkout(tax: Double) { double total(final List<Product> products) { return products .stream() .mapToDouble(Product::getPrice) .sum() * tax }}

Page 16: Joy of scala

class Checkout(tax: Double) { double total(final List<Product> products) { return products .stream() .mapToDouble(Product::getPrice) .sum() * tax }}

Return last statement by default

Page 17: Joy of scala

Return last statement by default

class Checkout(tax: Double) { double total(final List<Product> products) { products .stream() .mapToDouble(Product::getPrice) .sum() * tax }}

Page 18: Joy of scala

class Checkout(tax: Double) { double total(final List<Product> products) { products .stream() .mapToDouble(Product::getPrice) .sum() * tax }}

Method arguments are final by defaultAnd the Name comes before the Type

Page 19: Joy of scala

Method arguments are final by defaultAnd the Name comes before the Type

class Checkout(tax: Double) { def total(products: Seq[Product]): Double = { products .stream() .mapToDouble(Product::getPrice) .sum() * tax }}

Page 20: Joy of scala

class Checkout(tax: Double) { def total(products: Seq[Product]): Double = { products .stream() .mapToDouble(Product::getPrice) .sum() * tax }}

Type Inference

Page 21: Joy of scala

Type Inference

class Checkout(tax: Double) { def total(products: Seq[Product]) = { products .stream() .mapToDouble(Product::getPrice) .sum() * tax }}

Page 22: Joy of scala

class Checkout(tax: Double) { def total(products: Seq[Product]) = { products .stream() .mapToDouble(Product::getPrice) .sum() * tax }}

Remove more boilerplate

Page 23: Joy of scala

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

Page 24: Joy of scala

class Checkout(tax: Double) { def total(products: Seq[Product]) =

products.map(_.getPrice).sum * tax}

Scalapublic class Checkout { private double tax;

public Checkout(double tax) { this.tax = tax; }

double total(final List<Product> products) { return products .stream() .mapToDouble(Product::getPrice) .sum() * tax; }}

Java

Page 25: Joy of scala

Why it’s Good for Ya

Page 26: Joy of scala

Immutable by default

Page 27: Joy of scala

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/09/objects-should-be-immutable.html

Page 28: Joy of scala

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

Page 29: Joy of scala

Domain Objects

Page 30: Joy of scala

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; }

Page 31: Joy of scala

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

Page 32: Joy of scala

Case Classes

case class Product(name: String, price: Double)

What else?

val book = Product("Book", 42)val discountedBook = book.copy(price = 32)

Page 33: Joy of scala

Static Types InferencePromotes better naming over type declaration

val i = 8val 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) ^

Page 34: Joy of scala

Static Types InferencePromotes better naming over type declaration

private def add(a: Int, b: Int) = a + b

public def add(a: Int, b: Int): Int = a + b

Page 35: Joy of scala

Clarity & Comprehension

Page 36: Joy of scala

Why I Scala

1. Use types to understand functions

Page 37: Joy of scala

interface Calculator { Double divideOneBy(Integer divisor)}

calculator.divideOneBy(0);

null ArithmeticException Double.NaN

What’s the result ?

Page 38: Joy of scala

Meet Scala OptionsA better way for handling NULLs

Option [ T ]

None Some [ T ]

Page 39: Joy of scala

Meet Scala OptionsA better way for handling NULLs

trait Calculator { def divideOneBy(i: Int): Option[Double]}

calculator.divideOneBy(0) == Nonecalculator.divideOneBy(2) == Some(0.5)

Page 40: Joy of scala

Meet Scala Optionsval result: Option[Double] = calculator.divideOneBy(...)

var halfResult: Double = null

if (result.isDefined) { halfResult = result.get / 2 }else { ??? }

Imperative Style

Page 41: Joy of scala

Meet Scala OptionsImperative Style

val result: Option[Double] = calculator.divideOneBy(...)

var halfResult: Option[Double] = None

if (result.isDefined) { halfResult = Some(result.get / 2)}

Page 42: Joy of scala

Meet Scala OptionsFunctional style

val result: Option[Double] = calculator.divideOneBy(...)

val halfResult = result.map(r => r / 2)

Page 43: Joy of scala

Meet Scala OptionsFunctional style

val result: Option[Double] = calculator.divideOneBy(...)

val halfResult = result.map(_ / 2)

Page 44: Joy of scala

Meet Scala OptionsDefault Values

val productPhotoUrl: Option[String] = ...

val photoUrl: String = productPhotoUrl.getOrElse("http://site.com/defaultProductImage.jpg")

Page 45: Joy of scala

What You Can Do with Options

val default: Option[String] = ...val fallback: Option[String] = ...

val url = default.orElse(fallback)

Fallback

Page 46: Joy of scala

Java LibrariesWorking with Java? Just wrap it with an Option

Option(null) == None

Option(obj) == Some(obj)

Page 47: Joy of scala

Java LibrariesWorking with Java? Just wrap it with an Option

def javaApi(): SomeType = ...

val result = Option(javaApi())

NullPointerException – Never Again

Page 48: Joy of scala

Meet Scala’s TryThe flow is clear when it comes to Exceptions

Try [ T ]

Failure Success [ T ]

Page 49: Joy of scala

Why I Scala

1. Use types to understand functions2. Elegant flow

Page 50: Joy of scala

For Comprehensioncase 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}

Page 51: Joy of scala

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

Page 52: Joy of scala

Why I Scala

1. Use types to understand functions2. Elegant flow3. Powerful Pattern matching

Page 53: Joy of scala

Pattern MatchingA 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"}

Page 54: Joy of scala

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 MatchingExtracting Case-Classes

case class Product(name: String, price: Double)

Page 55: Joy of scala

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 ExtractorsMake your code cleaner by extracting the how to’s

Page 56: Joy of scala

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 ExtractorsMake your code cleaner by extracting the how to’s

Page 57: Joy of scala

Why I Scala

1. Use types to understand functions2. Elegant flow3. Powerful Pattern matching4. Awesome Parameters

Page 58: Joy of scala

Default Parameters

class DatabaseConnection { public DatabaseConnection(String host, int port, Credentials credentials) {}}

Constructor overloading

Page 59: Joy of scala

Default Parameters

class DatabaseConnection { public DatabaseConnection(String host, int port, Credentials credentials) {} public DatabaseConnection(String host, Credentials credentials) { this(host, 3306, credentials); }}

Constructor overloading

Page 60: Joy of scala

Default Parametersclass DatabaseConnection { public DatabaseConnection(String host, int port, Credentials credentials) {} public DatabaseConnection(String host, Credentials credentials) { this(host, 3306, credentials); }

public DatabaseConnection(Credentials credentials) { this("localhost", credentials); }}

Constructor overloading

Page 61: Joy of scala

Default Parametersclass DatabaseConnection { public DatabaseConnection(String host, int port, Credentials credentials) {} public DatabaseConnection(String host, Credentials credentials) { this(host, 3306, credentials); }

public DatabaseConnection(Credentials credentials) { this("localhost", credentials); }

public DatabaseConnection() { this(Credentials.empty); }}

Constructor overloading

Page 62: Joy of scala

Default Parametersclass DatabaseConnectionBuilder { private String host = "localhost"; private int port = 3306; private Credentials credentials = Credentials.empty

public DatabaseConnectionBuilder withHost(int port) { this.host = host; return this; }

public DatabaseConnectionBuilder withPort(int port) { this.port = port; return this; }

public DatabaseConnectionBuilder withCredentials(Credentials credentials) { this.credentials = credentials; return this; }

public DatabaseConnection build() { return new DatabaseConnection(host, port, credentials); }}

Builder Pattern

Page 63: Joy of scala

Default Parametersclass DatabaseConnection(host: String = "localhost", port: Int = 3306, credentials: Credentials = Credentials.empty)

Page 64: Joy of scala

Default Parametersclass DatabaseConnection(host: String = "localhost", port: Int = 3306, credentials: Credentials = Credentials.empty)

new DatabaseConnection("otherhost.com")

Page 65: Joy of scala

Default Parametersclass DatabaseConnection(host: String = "localhost", port: Int = 3306, credentials: Credentials = Credentials.empty)

new DatabaseConnection(port = 3030)

Page 66: Joy of scala

Named Parameters

new File(path).setExecutable(true, false)

Page 67: Joy of scala

Named Parameters

boolean executable = true;boolean ownerOnly = false;new File(path).setExecutable(executable, ownerOnly);

Page 68: Joy of scala

Named Parameters

new File(path).setExecutable(executable = true, ownerOnly = false)

Page 69: Joy of scala

Why I Scala

1. Use types to understand functions2. Elegant flow3. Powerful Pattern matching4. Awesome Parameters5. Easier Strings

Page 70: Joy of scala

String InterpolationMore readable, Use $ for variables

val name = "Max"val lang = "Scala"

val desc = s"Hello $name. $lang is awesome!"

Hello Max. Scala is awesome!

Page 71: Joy of scala

Quotes & MultilineMore readable, Easier to implement

val withQuotes = """Now I can use "quotes" without escaping"""

val multiline = """{ "firstName": "John", "lastName": "Smith", "age": 25 }"""

Page 72: Joy of scala

FUN & PROFIT

http://stackoverflow.com/research/developer-survey-2016

Page 73: Joy of scala

FUN & PROFIT

http://stackoverflow.com/research/developer-survey-2016

Page 74: Joy of scala

First Steps

Page 75: Joy of scala

You’re not alone

Adopted by:

… and a rapidly growing community

Page 76: Joy of scala

Migrating from JavaYou can do it! Things working for you:

EASY to start

Page 77: Joy of scala

Migrating from JavaYou can do it! Things working for you:

All Java libraries that you know and love work in Scala too

Page 78: Joy of scala

Migrating from JavaYou can do it! Things working for you:

You can start imperative and move to functional, decide where you want to be

Page 79: Joy of scala

Migrating from JavaThere are caveats. Things working against you:

(Too much?) freedom in programming style

http://www.lihaoyi.com/post/StrategicScalaStylePrincipleofLeastPower.html

Page 80: Joy of scala

Migrating from JavaThere are caveats. Things working against you:

Slower compile time

Page 81: Joy of scala

Migrating from JavaThere are caveats. Things working against you:

Less tooling

Page 82: Joy of scala

Migrating from JavaThere are caveats. Things working against you:

Recruiting

Page 83: Joy of scala

Java

Step 1Tests in Scala

Scala

Step 2Convert class to JALA, make it compile, refactor

Step 3scala.collections.JavaConversions._

Step 4@BeanProperty Annotation

Step 5Preserve Git

history

Page 84: Joy of scala

Java

Step 1Tests in Scala

Scala

Step 2Convert class to JALA, make it compile, refactor

Step 3scala.collections.JavaConversions._

Step 4@BeanProperty Annotation

Step 5Preserve Git

history

Page 85: Joy of scala

Wanna Learn More?https://twitter.github.io/scala_school/

http://danielwestheide.com/scala/neophytes.html

http://twitter.github.io/effectivescala/

https://www.scala-exercises.org/std_lib/assertsAdvanced Topics• Multiple inheritance• Implicits• Macros• Functional libraries

Page 86: Joy of scala

Thank You!Any Questions?Maxim Novak

@[email protected] https://github.com/maximn