Slide 1

Slide 1 text

Scala

Slide 2

Slide 2 text

Who am I?

Slide 3

Slide 3 text

Yann Simon @simon_yann

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

Why Scala?

Slide 6

Slide 6 text

Fear to lose job?

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

Java can be pain #1

Slide 11

Slide 11 text

public String createInvoiceName( Date invoiceDate, String invoiceId, String userId, String firmId, boolean directInvoice, boolean firmInvoice, boolean electronic) { // ...

Slide 12

Slide 12 text

String newInvoiceId = invoiceCreator.createInvoiceName( new Date(), "45AE-45F", "872346", "abc-234", true, false, false );

Slide 13

Slide 13 text

let's make it readable

Slide 14

Slide 14 text

String newInvoiceId = invoiceCreator.createInvoiceName( new Date(), // invoiceDate "45AE-45F", // invoiceId "872346", // userId "abc-234", // firmId true, // directInvoice false, // firmInvoice false // electronic );

Slide 15

Slide 15 text

OO maybe?

Slide 16

Slide 16 text

public class NewInvoiceNameCommand { private final Date invoiceDate; private final String invoiceId; private final String userId; private final String firmId; private final boolean directInvoice; private final boolean firmInvoice; private final boolean electronic; public NewInvoiceNameCommand( Date invoiceDate, String invoiceId, String userId, String firmId, boolean directInvoice, boolean firmInvoice, boolean electronic) { this.invoiceDate = invoiceDate; this.invoiceId = invoiceId; this.userId = userId; this.firmId = firmId; this.directInvoice = directInvoice; this.firmInvoice = firmInvoice; this.electronic = electronic; } public Date getInvoiceDate() { return invoiceDate; } public String getInvoiceId() { return invoiceId; } public String getUserId() { return userId; } public String getFirmId() { return firmId; } public boolean isDirectInvoice() { return directInvoice; } public boolean isFirmInvoice() { return firmInvoice; } public boolean isElectronic() { return electronic; } }

Slide 17

Slide 17 text

public String createInvoiceName( NewInvoiceNameCommand newInvoiceNameCommand) { // ... return "id"; } String newInvoiceId = invoiceCreator.createInvoiceName( newInvoiceNameCommand);

Slide 18

Slide 18 text

NewInvoiceNameCommand newInvoiceNameCommand = new NewInvoiceNameCommand( new Date(), "45AE-45F", "872346", "abc-234", true, false, false );

Slide 19

Slide 19 text

builder pattern to the rescue

Slide 20

Slide 20 text

public class NewInvoiceNameCommand { public static class NewInvoiceNameCommandBuilder { private Date invoiceDate; private String invoiceId; private String userId; private String firmId; private boolean directInvoice; private boolean firmInvoice; private boolean electronic; public NewInvoiceNameCommand build() { return new NewInvoiceNameCommand( invoiceDate, invoiceId, userId, firmId, directInvoice, firmInvoice, electronic); } public NewInvoiceNameCommandBuilder withInvoiceDate(Date invoiceDate) { this.invoiceDate = invoiceDate; return this; } public NewInvoiceNameCommandBuilder withInvoiceId(String invoiceId) { this.invoiceId = invoiceId; return this; } [...] } } private final Date invoiceDate; private final String invoiceId; private final String userId; private final String firmId; private final boolean directInvoice; private final boolean firmInvoice; private final boolean electronic; private NewInvoiceNameCommand( Date invoiceDate, String invoiceId, String userId, String firmId, boolean directInvoice, boolean firmInvoice, boolean electronic) { this.invoiceDate = invoiceDate; this.invoiceId = invoiceId; this.userId = userId; this.firmId = firmId; this.directInvoice = directInvoice; this.firmInvoice = firmInvoice; this.electronic = electronic; } public Date getInvoiceDate() { return invoiceDate; } public String getInvoiceId() { return invoiceId; } public String getUserId() { return userId; } public String getFirmId() { return firmId; } public boolean isDirectInvoice() { return directInvoice; } public boolean isFirmInvoice() { return firmInvoice; } public boolean isElectronic() { return electronic; }

Slide 21

Slide 21 text

NewInvoiceNameCommand newInvoiceNameCommand = new NewInvoiceNameCommand.NewInvoiceNameCommandBuilder() .withInvoiceDate(new Date()) .withInvoiceId("45AE-45F") .withUserId("872346") .withFirmId("abc-234") .withDirectInvoice(true) .withFirmInvoice(false) .withElectronic(false) .build(); String newInvoiceId = invoiceCreator.createInvoiceName(newInvoiceNameCommand);

Slide 22

Slide 22 text

with default values

Slide 23

Slide 23 text

public class NewInvoiceNameCommand { public static class NewInvoiceNameCommandBuilder { private Date invoiceDate; private String invoiceId; private String userId; private String firmId; private boolean directInvoice; private boolean firmInvoice; private boolean electronic; public NewInvoiceNameCommandBuilder() { // default values this.directInvoice = true; this.firmInvoice = false; } public NewInvoiceNameCommand build() { return new NewInvoiceNameCommand( invoiceDate, invoiceId, userId, firmId, directInvoice, firmInvoice, electronic); }

Slide 24

Slide 24 text

NewInvoiceNameCommand newInvoiceNameCommand = new NewInvoiceNameCommand.NewInvoiceNameCommandBuilder() .withInvoiceDate(new Date()) .withInvoiceId("45AE-45F") .withUserId("872346") .withFirmId("abc-234") .withElectronic(false) .build(); String newInvoiceId = invoiceCreator.createInvoiceName(newInvoiceNameCommand);

Slide 25

Slide 25 text

better!

Slide 26

Slide 26 text

just need some glue

Slide 27

Slide 27 text

public class NewInvoiceNameCommand { public static class NewInvoiceNameCommandBuilder { private Date invoiceDate; private String invoiceId; private String userId; private String firmId; private boolean directInvoice; private boolean firmInvoice; private boolean electronic; public NewInvoiceNameCommandBuilder() { // default values this.directInvoice = true; this.firmInvoice = false; } public NewInvoiceNameCommand build() { return new NewInvoiceNameCommand( invoiceDate, invoiceId, userId, firmId, directInvoice, firmInvoice, electronic); } public NewInvoiceNameCommandBuilder withInvoiceDate(Date invoiceDate) { this.invoiceDate = invoiceDate; return this; } public NewInvoiceNameCommandBuilder withInvoiceId(String invoiceId) { this.invoiceId = invoiceId; return this; } public NewInvoiceNameCommandBuilder withUserId(String userId) { this.userId = userId; return this; } public NewInvoiceNameCommandBuilder withFirmId(String firmId) { this.firmId = firmId; return this; } public NewInvoiceNameCommandBuilder withDirectInvoice(boolean directInvoice) { this.directInvoice = directInvoice; return this; } public NewInvoiceNameCommandBuilder withFirmInvoice(boolean firmInvoice) { this.firmInvoice = firmInvoice; return this; } public NewInvoiceNameCommandBuilder withElectronic(boolean electronic) { this.electronic = electronic; return this; } } private final Date invoiceDate; private final String invoiceId; private final String userId; private final String firmId; private final boolean directInvoice; private final boolean firmInvoice; private final boolean electronic; private NewInvoiceNameCommand( Date invoiceDate, String invoiceId, String userId, String firmId, boolean directInvoice, boolean firmInvoice, boolean electronic) { this.invoiceDate = invoiceDate; this.invoiceId = invoiceId; this.userId = userId; this.firmId = firmId; this.directInvoice = directInvoice; this.firmInvoice = firmInvoice; this.electronic = electronic; } public Date getInvoiceDate() { return invoiceDate; } public String getInvoiceId() { return invoiceId; } public String getUserId() { return userId; } public String getFirmId() { return firmId; } public boolean isDirectInvoice() { return directInvoice; } public boolean isFirmInvoice() { return firmInvoice; } public boolean isElectronic() { return electronic; } }

Slide 28

Slide 28 text

let's try with Scala

Slide 29

Slide 29 text

def createInvoiceName( invoiceDate: Date, invoiceId: String, userId: String, firmId: String, directInvoice: Boolean, firmInvoice: Boolean, electronic: Boolean): String = { // ... }

Slide 30

Slide 30 text

val newInvoiceId = invoiceCreator.createInvoiceName( new Date, "45AE-45F", "872346", "abc-234", true, false, false )

Slide 31

Slide 31 text

Scala can be ugly too (surprise #1)

Slide 32

Slide 32 text

val newInvoiceId = invoiceCreator.createInvoiceName( new Date, // invoiceDate "45AE-45F", // invoiceId "872346", // userId "abc-234", // firmId true, // directInvoice false, // firmInvoice false // electronic )

Slide 33

Slide 33 text

comments exist in Scala (surprise #2)

Slide 34

Slide 34 text

val newInvoiceId = invoiceCreator.createInvoiceName( invoiceDate = new Date, invoiceId = "45AE-45F", userId = "872346", firmId = "abc-234", directInvoice = true, firmInvoice = false, electronic = false )

Slide 35

Slide 35 text

Yes, named parameters!

Slide 36

Slide 36 text

and default values?

Slide 37

Slide 37 text

def createInvoiceName( invoiceDate: Date, invoiceId: String, userId: String, firmId: String, directInvoice: Boolean = true, firmInvoice: Boolean = false, electronic: Boolean): String = {

Slide 38

Slide 38 text

val newInvoiceId = invoiceCreator.createInvoiceName( invoiceDate = new Date, invoiceId = "45AE-45F", userId = "872346", firmId = "abc-234", electronic = false )

Slide 39

Slide 39 text

but I want a command object

Slide 40

Slide 40 text

case class NewInvoiceNameCommand ( invoiceDate: Date, invoiceId: String, userId: String, firmId: String, directInvoice: Boolean = true, firmInvoice: Boolean = false, electronic: Boolean )

Slide 41

Slide 41 text

val newInvoiceNameCommand = NewInvoiceNameCommand ( invoiceDate = new Date, invoiceId = "45AE-45F", userId = "872346", firmId = "abc-234", electronic = false ) val newInvoiceId = invoiceCreator.createInvoiceName( newInvoiceNameCommand)

Slide 42

Slide 42 text

Java can be pain #2

Slide 43

Slide 43 text

public int multiplyBy2(int number) { return number * 2; } [...] public void multiplyUserInputBy2() { Integer userInput = null; multiplyBy2(userInput); }

Slide 44

Slide 44 text

def multiplyBy2(number: Int): Int = { number * 2 } def multiplyUserInputBy2 { //val userInput: Int = null // does not compile //val userInput = Int.unbox(new Integer(null)) throws exception val userInput = 2 multiplyBy2(userInput) }

Slide 45

Slide 45 text

Java can be pain #3

Slide 46

Slide 46 text

public class User { private final String name; private final String gender; private final Date dateOfBirth; public User(String name, String gender, Date dateOfBirth) { this.name = name; this.gender = gender; this.dateOfBirth = dateOfBirth; } public String getName() { return name; } public String getGender() { return gender; } public Date getDateOfBirth() { return dateOfBirth; } }

Slide 47

Slide 47 text

public class User { private final String name; private final String gender; private final Date dateOfBirth; public User(String name, String gender, Date dateOfBirth) { this.name = name; this.gender = gender; this.dateOfBirth = dateOfBirth; } public String getName() { return name; } public String getGender() { return gender; } public Date getDateOfBirth() { return dateOfBirth; } public Integer getAge() { if (dateOfBirth == null) { return null; } Date now = new Date(); long difference = now.getTime() - dateOfBirth.getTime(); Calendar yearCalculator = Calendar.getInstance(); yearCalculator.setTimeInMillis(difference); return yearCalculator.get(Calendar.YEAR); } }

Slide 48

Slide 48 text

public class UserBusiness { private final UserRepository userRepository = new UserRepository(); public boolean isUserAllowed(String name) { User user = userRepository.findUserByName(name); if (user != null) { if (user.getGender() != null && user.getGender().equals("F")) { if (user.getAge() != null && user.getAge() >= 18) { return true; } } } return false; } }

Slide 49

Slide 49 text

case class User ( name: String, gender: Option[String] = None, dateOfBirth: Option[Date] = None ) { def age: Option[Int] = dateOfBirth.map { dob => calculateAge(dob) } private def calculateAge(dateOfBirth: Date): Int = { val now = new Date() val difference = now.getTime - dateOfBirth.getTime val yearCalculator = Calendar.getInstance() yearCalculator.setTimeInMillis(difference) yearCalculator.get(Calendar.YEAR) } }

Slide 50

Slide 50 text

class UserBusiness { val userRepository = new UserRepository() def isUserAllowed(name: String): Boolean = { val allowedUser = for { user <- userRepository.findUserByName(name) gender <- user.gender if gender == "F" age <- user.age if age >= 18 } yield user allowedUser.isDefined } }

Slide 51

Slide 51 text

Bye bye NullPointerException

Slide 52

Slide 52 text

Asynchronous IO

Slide 53

Slide 53 text

Asynchronous IO - What?

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

No content

Slide 56

Slide 56 text

No content

Slide 57

Slide 57 text

Asynchronous IO - Why?

Slide 58

Slide 58 text

No content

Slide 59

Slide 59 text

No content

Slide 60

Slide 60 text

No content

Slide 61

Slide 61 text

No content

Slide 62

Slide 62 text

Asynchronous IO in Java

Slide 63

Slide 63 text

public Promise searchStock(String query) { Promise responsePromise = WS.url("http://localhost:9001/search") .setQueryParameter("query", query) .get(); return responsePromise.map(new F.Function() { @Override public JsonNode apply(WS.Response response) throws Throwable { if (response.getStatus() == 200) { JsonNode jsonNode = response.asJson(); return jsonNode.findPath("results"); } else { throw new Exception("Error calling search service.\nResponse status " + response.getStatus() + "\n"); } } }); }

Slide 64

Slide 64 text

Asynchronous IO in Scala

Slide 65

Slide 65 text

def searchStock(query: String): Future[Seq[JsObject]] = { WS.url("http://localhost:9001/search") .withQueryString("query" -> query) .get() .map { response => response.status match { case 200 => (response.json \ "results").as[Seq[JsObject]] case _ => throw new Exception(s"Error calling search service.\nResponse status ${response.status}\n") } } }

Slide 66

Slide 66 text

Three sequential calls

Slide 67

Slide 67 text

public static Promise index(String userId) { Promise user = backends.getUserById(userId); Promise> orders = user.flatMap(new F.Function>>() { @Override public Promise> apply(User user) throws Throwable { return backends.getOrdersForUser(user.getEmail()); } }); Promise> products = orders.flatMap(new F.Function, Promise>>() { @Override public Promise> apply(List orders) throws Throwable { return backends.getProductsForOrders(orders); } }); Promise> stocks = products.flatMap(new F.Function, Promise>>() { @Override public Promise> apply(List products) throws Throwable { return backends.getStocksForProducts(products); } }); Promise> promises = Promise.sequence(user, orders, products, stocks); return promises.map(new F.Function, Result>() { @Override public Result apply(List results) throws Throwable { User user = (User)results.get(0); List orders = (List)results.get(1); List products = (List)results.get(2); List stocks = (List)results.get(3); return ok(orders.size() + " order(s) for user " + user.getEmail()); } }); }

Slide 68

Slide 68 text

def index(userId: String) = Action.async { for { user <- getUserById(userId) orders <- getOrdersForUser(user.email) products <- getProductsForOrders(orders) stocks <- getStocksForProducts(products) } yield Ok(s"${orders.size} order(s) for user ${user.email}") }

Slide 69

Slide 69 text

OK, I want to try Scala

Slide 70

Slide 70 text

Be careful

Slide 71

Slide 71 text

Scala can be pain #1

Slide 72

Slide 72 text

✗ slow compilation

Slide 73

Slide 73 text

✗ slow compilation incremental compilation ~run modules Scala 2.11

Slide 74

Slide 74 text

Scala can be pain #2

Slide 75

Slide 75 text

functional programming terrorists

Slide 76

Slide 76 text

use the most appropriate style for the problem (and for the maintenance)

Slide 77

Slide 77 text

Scala can be pain #3

Slide 78

Slide 78 text

# Scala dev < Java

Slide 79

Slide 79 text

use this problem as opportunity Ex: “Yes, all of us were quite experienced Java programmers. [...] Because we were all learning together, this worked really well.”

Slide 80

Slide 80 text

Online courses: Functional Programming Principles in Scala Principles of Reactive Programming

Slide 81

Slide 81 text

Scala User Group Play framework User Group

Slide 82

Slide 82 text

Trainings http://www.leanovate.de/training/software/

Slide 83

Slide 83 text

I get it I want to try Scala

Slide 84

Slide 84 text

Integration in my project?

Slide 85

Slide 85 text

✔ Maven ✔ ANT ✔ SBT ✔ Gradle

Slide 86

Slide 86 text

Begin with scala-test?

Slide 87

Slide 87 text

test("content disposition parser extracts the filename") { val header = "Attachment; filename=example.html" val filename = ContentDispositionHeader.parse(header).filename assert(filename === Some("example.html")) }

Slide 88

Slide 88 text

it should "replace ä with ae" in { SwiftLatinCharset.from("fooÄfoo") shouldEqual "fooAefoo" SwiftLatinCharset.from("fooäfoo") shouldEqual "fooaefoo" }

Slide 89

Slide 89 text

Integration in my firm?

Slide 90

Slide 90 text

Continuous Integration

Slide 91

Slide 91 text

sbt test mvn test ...

Slide 92

Slide 92 text

✔ ✔ ✔

Slide 93

Slide 93 text

Scala ✔ Integrate with Java ✔ Integrate with existing build ✔ Usual tools

Slide 94

Slide 94 text

Build products ✔ efficient development ✔ motivated teams ✔ enable SOA (async IO) ✔ less lines of code ✔ easier maintenance

Slide 95

Slide 95 text

✔ focus on your product!

Slide 96

Slide 96 text

thanks for your attention