57
in Practice Scala @patforna [email protected] 3 years later…

Scala in practice - 3 years later

Embed Size (px)

Citation preview

Page 1: Scala in practice - 3 years later

in PracticeScala

@patforna [email protected]

3 years later…

Page 2: Scala in practice - 3 years later

Context

Page 3: Scala in practice - 3 years later

Context

Pat

Springer

Software

Engineer

Technical

Principal

10+ years

Academic

Publisher

Pretty Large

Springer

Link

Strategic

95 % Online

Revenue66 % Total

Revenue

9 Mio items

2TB XML

Re-built

3 years ago

Content

Delivery

Platform

52 Mio

PageViews / Month

99.9%

Availability

Scala NoSql

Co-Sourced

Team

TW

Ex-TW

SpringerGlobal

CD

Page 4: Scala in practice - 3 years later

SpringerLink

Page 5: Scala in practice - 3 years later

Timeline

Startdevelopment

CyclingTrip

Re-joined

Product -> platformPaying back tech debt

Today

04/11 04/12 08/13 04/14

Inception

05/12 09/12

BookfairRelease

RDLive

User migration,enhancements

LinkLive

SmartBooksLive

Enhancements

Page 6: Scala in practice - 3 years later

Looking back: why scala?• Increase productivity

• Be more attractive employer

• Team decision

Page 7: Scala in practice - 3 years later

Looking back: good vs badGood

• Functional programming

• Terse syntax

• JVM ecosystem

• Gentle learning curve

• DSL friendly syntax

• Motivated team

Bad

• Tool support

• Compilation times

• Language complexity #moreRope

Page 8: Scala in practice - 3 years later

Fast-forward

Page 9: Scala in practice - 3 years later

Fast-forward (Aug 2013)

• 2.5 years into project

• 1.5 years of weekly live releases

• 100k LOC

• >10k commits

• >90 committers

Page 10: Scala in practice - 3 years later

Fast-forward (Aug 2013)

• 2.5 years into project

• 1.5 years of weekly live releases

• 100k LOC

• >10k commits

• >90 committers

not all related to Scala - to be fair

• Poor feedback loops

• Lots of accidental complexity

Page 11: Scala in practice - 3 years later

Trend (2 years)

LOC

~ 100k

Page 12: Scala in practice - 3 years later

Trend (2 years)

build time

LOC

Page 13: Scala in practice - 3 years later

Trend (2 years)

build time

LOC• 1:34 min src/main

• 6:44 min src/test

• 8:18 min total

Page 14: Scala in practice - 3 years later

What did we do?

Page 15: Scala in practice - 3 years later

What did we do• Reduced build time

• Improved feedback loops

• Reduced accidental complexity

Page 16: Scala in practice - 3 years later

Build time• Reduced size of codebase (broke off vertical slices, pulled out APIs, pulled out libraries,

removed unused features, removed low-value tests, etc.)

• Reduced usage of certain language features (esp. traits and implicits)

Page 17: Scala in practice - 3 years later

Trend (Dec 2013)

LOC

Page 18: Scala in practice - 3 years later

Trend (Dec 2013)

build time

# traits

LOC

unable to compile on 13” macbook

Page 19: Scala in practice - 3 years later

Trend (Dec 2013)

build time

# traits

LOC

unable to compile on 13” macbook

Page 20: Scala in practice - 3 years later

The problem with traits• Will re-compile on every class the trait is mixed in

• Slows down dev-build cycle

• Will result in byte code bloat

• Will compile *a lot* slower

!

For faster compile times:

• Use pure traits

• Use old-school composition for code re-use

• Use pure functions via imports (e.g. import Foo._)

• If unavoidable, use inheritance for code re-use

Page 21: Scala in practice - 3 years later

Build time

Page 22: Scala in practice - 3 years later

Build time

• 1:34 min src/main

• 6:44 min src/test

• 8:18 min total

Page 23: Scala in practice - 3 years later

Build time

• 1:34 min src/main

• 6:44 min src/test

• 8:18 min total

• 0:24 min src/main

• 3:11 min src/test

• 3:35 min total

Page 24: Scala in practice - 3 years later

Build time (on CI server)

• Incremental compilation on CI

• Only one dedicated CI agent

• Physical build servers

• CPUs with higher clock speed

Page 25: Scala in practice - 3 years later

Build time (on CI server)

• Incremental compilation on CI

• Only one dedicated CI agent

• Physical build servers

• CPUs with higher clock speed

Page 26: Scala in practice - 3 years later

Complexity

Page 27: Scala in practice - 3 years later

Complexity• There’s still a lot of code in our codebase that is hard to read

• It seems to be very easy to shoot yourself in the foot with Scala

• Scala *is* complex (and that’s why scalac will never be as fast as javac)

Page 28: Scala in practice - 3 years later

Complexity• There’s still a lot of code in our codebase that is hard to read

• It seems to be very easy to shoot yourself in the foot with Scala

• Scala *is* complex (and that’s why scalac will never be as fast as javac)

Invariant/covariant/contravariant types (T, +T and -T)Refined types (new Foo {...})Structural types (x: {def y: Int})Path dependant types (a.B)Specialized types (@specialized)Self types (this =>)Projection types (A#B)Existential types (M[_])

Type bounds (<:, >:) Type constraints (=:=, <:< and <%<)

Type members (type T)Type aliases (type T = Int)

Type classes ( (implicit ...) )View bounds (<%)

Higher kinded types (* => *)F-Bounded type polymorphism (M[T <: M[T]])

http://nurkiewicz.github.io/talks/2014/scalar/#/16

Page 29: Scala in practice - 3 years later

Not opinionated

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

• Many ways to do the same thing

• Coding conventions help, but only so much

Page 30: Scala in practice - 3 years later

Not opinionated

def foo() = "foo"def bar = "bar"!foofoo()barbar() // won't compile

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

• Many ways to do the same thing

• Coding conventions help, but only so much

Page 31: Scala in practice - 3 years later

Not opinionated

def foo() = "foo"def bar = "bar"!foofoo()barbar() // won't compile

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

• Many ways to do the same thing

• Coding conventions help, but only so much

def baz(x: String) = x“x”.charAt(0)“x” charAt(0) // won't compile“x”.charAt 0 // won't compile“x” charAt 0baz("x")baz “x" // won't compile

Page 32: Scala in practice - 3 years later

Not opinionated

def foo() = "foo"def bar = "bar"!foofoo()barbar() // won't compile

list.foreach { x => println(x) }list.foreach ( x => println(x) )list.foreach { println(_) }list.foreach ( println(_) )list foreach { x => println(x) }list foreach ( x => println(x) )list foreach { println(_) }list foreach ( println(_) )

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

• Many ways to do the same thing

• Coding conventions help, but only so much

def baz(x: String) = x“x”.charAt(0)“x” charAt(0) // won't compile“x”.charAt 0 // won't compile“x” charAt 0baz("x")baz “x" // won't compile

Page 33: Scala in practice - 3 years later

Not opinionated

def foo() = "foo"def bar = "bar"!foofoo()barbar() // won't compile

list.foreach { x => println(x) }list.foreach ( x => println(x) )list.foreach { println(_) }list.foreach ( println(_) )list foreach { x => println(x) }list foreach ( x => println(x) )list foreach { println(_) }list foreach ( println(_) )

if (foo) "x" else "y" foo match { case true => "x" case _ => "y"}

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

• Many ways to do the same thing

• Coding conventions help, but only so much

def baz(x: String) = x“x”.charAt(0)“x” charAt(0) // won't compile“x”.charAt 0 // won't compile“x” charAt 0baz("x")baz “x" // won't compile

Page 34: Scala in practice - 3 years later

Surprises

http://dan.bodar.com/2013/12/04/wat-scala/

Page 35: Scala in practice - 3 years later

SurprisesList(1, 2, 3).toSet

http://dan.bodar.com/2013/12/04/wat-scala/

Page 36: Scala in practice - 3 years later

SurprisesList(1, 2, 3).toSet scala.collection.immutable.Set[Int] = Set(1, 2, 3)

http://dan.bodar.com/2013/12/04/wat-scala/

Page 37: Scala in practice - 3 years later

SurprisesList(1, 2, 3).toSet scala.collection.immutable.Set[Int] = Set(1, 2, 3)

List(1, 2, 3).toSet()

http://dan.bodar.com/2013/12/04/wat-scala/

Page 38: Scala in practice - 3 years later

SurprisesList(1, 2, 3).toSet scala.collection.immutable.Set[Int] = Set(1, 2, 3)

List(1, 2, 3).toSet()Boolean = false

http://dan.bodar.com/2013/12/04/wat-scala/

Page 39: Scala in practice - 3 years later

Implicits• Can make it very hard to read code

• Tool support is very bad

• Impacts compilation time

• Surprising behaviour (esp. when used with overloaded methods or optional params)

Page 40: Scala in practice - 3 years later

Tooling

def handle(response: HttpResponse, request: HttpRequest)

• Tool support is still very basic

• Makes it hard to continuously refactor (which means people are less likely to do it)

Page 41: Scala in practice - 3 years later

Tooling

def handle(response: HttpResponse, request: HttpRequest)

• Tool support is still very basic

• Makes it hard to continuously refactor (which means people are less likely to do it)

no luck with “change signature” refactoring support

Page 42: Scala in practice - 3 years later

Trait entanglements• Makes it difficult to reason about behaviour

Page 43: Scala in practice - 3 years later

Trait entanglements• Makes it difficult to reason about behaviour

trait A { def foo = "a"}

Page 44: Scala in practice - 3 years later

Trait entanglements• Makes it difficult to reason about behaviour

trait A { def foo = "a"}

trait B extends A { override def foo = "b"}

Page 45: Scala in practice - 3 years later

Trait entanglements• Makes it difficult to reason about behaviour

trait A { def foo = "a"}

trait B extends A { override def foo = "b"}

class C extends A with Bnew C().foo

Page 46: Scala in practice - 3 years later

Trait entanglements• Makes it difficult to reason about behaviour

trait A { def foo = "a"}

trait B extends A { override def foo = "b"}

class C extends A with Bnew C().foo

"b"

Page 47: Scala in practice - 3 years later

Trait entanglements• Makes it difficult to reason about behaviour

trait A { def foo = "a"}

trait B extends A { override def foo = "b"}

class C extends A with Bnew C().foo

"b"

class D extends B with Anew D().foo

Page 48: Scala in practice - 3 years later

Trait entanglements• Makes it difficult to reason about behaviour

trait A { def foo = "a"}

trait B extends A { override def foo = "b"}

class C extends A with Bnew C().foo

"b"

class D extends B with Anew D().foo

"b"

Page 49: Scala in practice - 3 years later

Trait entanglements (2)

ArticlePageSteps

WebDriverSupport

AuthorStepsCoverImageSteps

SummarySection

Waiter SectionPageSteps

CommonPageSteps

WebElementSupport

Assertions

Uris TripleEquals

OnHost TripleEqualsSupport

MachineNames

Page 50: Scala in practice - 3 years later

Trait entanglements (3)

ArticlePageSteps_0

WebDriverSupport_1 AuthorSteps_1 CoverImageSteps_1 SummarySection_1Waiter_1 SectionPageSteps_1 CommonPageSteps_1

CommonPageSteps_2 WebElementSupport_2Assertions_2 WebDriverSupport_2Uris_2

WebElementSupport_3 WebDriverSupport_3Uris_3 TripleEquals_3 OnHost_3

OnHost_4 TripleEqualsSupport_4 MachineNames_4

MachineNames_5

Page 51: Scala in practice - 3 years later

Trait entanglements (3)

ArticlePageSteps_0

WebDriverSupport_1 AuthorSteps_1 CoverImageSteps_1 SummarySection_1Waiter_1 SectionPageSteps_1 CommonPageSteps_1

CommonPageSteps_2 WebElementSupport_2Assertions_2 WebDriverSupport_2Uris_2

WebElementSupport_3 WebDriverSupport_3Uris_3 TripleEquals_3 OnHost_3

OnHost_4 TripleEqualsSupport_4 MachineNames_4

MachineNames_5

Page 52: Scala in practice - 3 years later

Trait entanglements (4)

ArticlePageTests_0

ArticlePageSteps_1 AboutSectionSteps_1 SearchResultsPageSteps_1 Uris_1 ArticleTestFixture_1 JavascriptSupport_1 IssuePageSteps_1 CommonAbstractSteps_1 GoogleAnalyticsSteps_1 FakeEntitlementSteps_1 ExportCitationPageSteps_1 FullTextPageSteps_1 OtherActionsSectionSteps_1

WebDriverSupport_2 AuthorSteps_2 CoverImageSteps_2 SummarySection_2Waiter_2 SectionPageSteps_2 CommonPageSteps_2

CommonPageSteps_3 WebElementSupport_3Assertions_3 WebDriverSupport_3Uris_3

WebElementSupport_4 WebDriverSupport_4Uris_4 TripleEquals_4 OnHost_4

OnHost_5 TripleEqualsSupport_5 MachineNames_5

MachineNames_6

Page 53: Scala in practice - 3 years later

Trait entanglements (4)

ArticlePageTests_0

ArticlePageSteps_1 AboutSectionSteps_1 SearchResultsPageSteps_1 Uris_1 ArticleTestFixture_1 JavascriptSupport_1 IssuePageSteps_1 CommonAbstractSteps_1 GoogleAnalyticsSteps_1 FakeEntitlementSteps_1 ExportCitationPageSteps_1 FullTextPageSteps_1 OtherActionsSectionSteps_1

WebDriverSupport_2 AuthorSteps_2 CoverImageSteps_2 SummarySection_2Waiter_2 SectionPageSteps_2 CommonPageSteps_2

CommonPageSteps_3 WebElementSupport_3Assertions_3 WebDriverSupport_3Uris_3

WebElementSupport_4 WebDriverSupport_4Uris_4 TripleEquals_4 OnHost_4

OnHost_5 TripleEqualsSupport_5 MachineNames_5

MachineNames_6

Imagine many more circle here

Page 54: Scala in practice - 3 years later

So, what’s next?

Page 55: Scala in practice - 3 years later

Today• We’ve delivered successfully using Scala

• Don’t think we’re more productive (pure gut feeling, though)

• We try to stick to the good parts (conventions, functional programming, pattern matching, etc.)

• Complexity, slow compilation and lack of tool support are real problems

Page 56: Scala in practice - 3 years later

The future• No urgency to move away from Scala or re-write existing systems

• Java 8 is an alternative

• Smaller teams and apps will probably lead to more polyglotism (and less Scala)

Page 57: Scala in practice - 3 years later

Thanks

@patforna [email protected]

http://joinit.springer.com