in PracticeScala
@patforna
patric.fornasier@springer.com
3 years later…
Context
Context
Pat
Springer
Software
Engineer
Technical
Principal
10+ years
Academic
Publisher
Pretty Large
Springer
Link
Strateg...
SpringerLink
Timeline
Start
development
Cycling
Trip
Re-joined
Product -> platform
Paying back tech debt
Today
04/11 04/12 08/13 04/14
...
Looking back: why scala?
• Increase productivity
• Be more attractive employer
• Team decision
Looking back: good vs bad
Good
• Functional programming
• Terse syntax
• JVM ecosystem
• Gentle learning curve
• DSL frien...
Fast-forward
Fast-forward (Aug 2013)
• 2.5 years into project
• 1.5 years of weekly live releases
• 100k LOC
• >10k commits
• >90 commi...
Fast-forward (Aug 2013)
• 2.5 years into project
• 1.5 years of weekly live releases
• 100k LOC
• >10k commits
• >90 commi...
Trend (2 years)
LOC
~ 100k
Trend (2 years)
build time
LOC
Trend (2 years)
build time
LOC
• 1:34 min src/main
• 6:44 min src/test
• 8:18 min total
What did we do?
What did we do
• Reduced build time
• Improved feedback loops
• Reduced accidental complexity
Build time
• Reduced size of codebase (broke off vertical slices, pulled out APIs, pulled out libraries,
removed unused fea...
Trend (Dec 2013)
LOC
Trend (Dec 2013)
build time
# traits
LOC
unable to compile on	

13” macbook
Trend (Dec 2013)
build time
# traits
LOC
unable to compile on	

13” macbook
The problem with traits
• Will re-compile on every class the trait is mixed in
• Slows down dev-build cycle
• Will result ...
Build time
Build time
• 1:34 min src/main
• 6:44 min src/test
• 8:18 min total
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 tot...
Build time (on CI server)
• Incremental compilation on CI
• Only one dedicated CI agent
• Physical build servers
• CPUs wi...
Build time (on CI server)
• Incremental compilation on CI
• Only one dedicated CI agent
• Physical build servers
• CPUs wi...
Complexity
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...
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...
Not opinionated
For example: http://twitter.github.io/effectivescala/
• Many ways to do the same thing
• Coding conventions...
Not opinionated
def foo() = "foo"	
def bar = "bar"	
!
foo	
foo()	
bar	
bar() // won't compile
For example: http://twitter....
Not opinionated
def foo() = "foo"	
def bar = "bar"	
!
foo	
foo()	
bar	
bar() // won't compile
For example: http://twitter....
Not opinionated
def foo() = "foo"	
def bar = "bar"	
!
foo	
foo()	
bar	
bar() // won't compile
list.foreach { x => println(...
Not opinionated
def foo() = "foo"	
def bar = "bar"	
!
foo	
foo()	
bar	
bar() // won't compile
list.foreach { x => println(...
Surprises
http://dan.bodar.com/2013/12/04/wat-scala/
Surprises
List(1, 2, 3).toSet
http://dan.bodar.com/2013/12/04/wat-scala/
Surprises
List(1, 2, 3).toSet
scala.collection.immutable.Set[Int] = Set(1, 2, 3)
http://dan.bodar.com/2013/12/04/wat-scala/
Surprises
List(1, 2, 3).toSet
scala.collection.immutable.Set[Int] = Set(1, 2, 3)
List(1, 2, 3).toSet()
http://dan.bodar.co...
Surprises
List(1, 2, 3).toSet
scala.collection.immutable.Set[Int] = Set(1, 2, 3)
List(1, 2, 3).toSet()
Boolean = false
htt...
Implicits
• Can make it very hard to read code
• Tool support is very bad
• Impacts compilation time
• Surprising behaviou...
Tooling
def handle(response: HttpResponse, request: HttpRequest)
• Tool support is still very basic
• Makes it hard to con...
Tooling
def handle(response: HttpResponse, request: HttpRequest)
• Tool support is still very basic
• Makes it hard to con...
Trait entanglements
• Makes it difficult to reason about behaviour
Trait entanglements
• Makes it difficult to reason about behaviour
trait A {
def foo = "a"
}
Trait entanglements
• Makes it difficult to reason about behaviour
trait A {
def foo = "a"
}
trait B extends A {
override de...
Trait entanglements
• Makes it difficult to reason about behaviour
trait A {
def foo = "a"
}
trait B extends A {
override de...
Trait entanglements
• Makes it difficult to reason about behaviour
trait A {
def foo = "a"
}
trait B extends A {
override de...
Trait entanglements
• Makes it difficult to reason about behaviour
trait A {
def foo = "a"
}
trait B extends A {
override de...
Trait entanglements
• Makes it difficult to reason about behaviour
trait A {
def foo = "a"
}
trait B extends A {
override de...
Trait entanglements (2)
ArticlePageSteps
WebDriverSupport
AuthorStepsCoverImageSteps
SummarySection
Waiter SectionPageStep...
Trait entanglements (3)
ArticlePageSteps_0
WebDriverSupport_1 AuthorSteps_1 CoverImageSteps_1 SummarySection_1Waiter_1 Sec...
Trait entanglements (3)
ArticlePageSteps_0
WebDriverSupport_1 AuthorSteps_1 CoverImageSteps_1 SummarySection_1Waiter_1 Sec...
Trait entanglements (4)
ArticlePageTests_0
ArticlePageSteps_1 AboutSectionSteps_1 SearchResultsPageSteps_1 Uris_1 ArticleT...
Trait entanglements (4)
ArticlePageTests_0
ArticlePageSteps_1 AboutSectionSteps_1 SearchResultsPageSteps_1 Uris_1 ArticleT...
So, what’s next?
Today
• We’ve delivered successfully using Scala
• Don’t think we’re more productive (pure gut feeling, though)
• We try t...
The future
• No urgency to move away from Scala or re-write existing systems
• Java 8 is an alternative
• Smaller teams an...
Thanks
@patforna
patric.fornasier@springer.com
http://joinit.springer.com
Upcoming SlideShare
Loading in …5
×

Scala in-practice-3-years by Patric Fornasier, Springr, presented at Pune Scala Symposium 2014, ThoughtWorks

2,250
-1

Published on

3 years ago, Springer decided to use Scala on a large, strategic project. This talk is about the journey the development teams made. Why did they choose Scala in the first place? Did they get what they hoped for? What challenges and surprises did they encounter along the way? And, most importantly, are they still happy with their choice?

Published in: Technology, Education
0 Comments
6 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,250
On Slideshare
0
From Embeds
0
Number of Embeds
5
Actions
Shares
0
Downloads
10
Comments
0
Likes
6
Embeds 0
No embeds

No notes for slide

Scala in-practice-3-years by Patric Fornasier, Springr, presented at Pune Scala Symposium 2014, ThoughtWorks

  1. 1. in PracticeScala @patforna patric.fornasier@springer.com 3 years later…
  2. 2. Context
  3. 3. Context Pat Springer Software Engineer Technical Principal 10+ years Academic Publisher Pretty Large Springer Link Strategic 95 % Online Revenue 66 % 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 Springer Global CD
  4. 4. SpringerLink
  5. 5. Timeline Start development Cycling Trip Re-joined Product -> platform Paying back tech debt Today 04/11 04/12 08/13 04/14 Inception 05/12 09/12 Bookfair Release RD Live User migration, enhancements Link Live Smart Books Live Enhancements
  6. 6. Looking back: why scala? • Increase productivity • Be more attractive employer • Team decision
  7. 7. Looking back: good vs bad Good • Functional programming • Terse syntax • JVM ecosystem • Gentle learning curve • DSL friendly syntax • Motivated team Bad • Tool support • Compilation times • Language complexity #moreRope
  8. 8. Fast-forward
  9. 9. Fast-forward (Aug 2013) • 2.5 years into project • 1.5 years of weekly live releases • 100k LOC • >10k commits • >90 committers
  10. 10. 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
  11. 11. Trend (2 years) LOC ~ 100k
  12. 12. Trend (2 years) build time LOC
  13. 13. Trend (2 years) build time LOC • 1:34 min src/main • 6:44 min src/test • 8:18 min total
  14. 14. What did we do?
  15. 15. What did we do • Reduced build time • Improved feedback loops • Reduced accidental complexity
  16. 16. 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)
  17. 17. Trend (Dec 2013) LOC
  18. 18. Trend (Dec 2013) build time # traits LOC unable to compile on 13” macbook
  19. 19. Trend (Dec 2013) build time # traits LOC unable to compile on 13” macbook
  20. 20. 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
  21. 21. Build time
  22. 22. Build time • 1:34 min src/main • 6:44 min src/test • 8:18 min total
  23. 23. 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
  24. 24. Build time (on CI server) • Incremental compilation on CI • Only one dedicated CI agent • Physical build servers • CPUs with higher clock speed
  25. 25. Build time (on CI server) • Incremental compilation on CI • Only one dedicated CI agent • Physical build servers • CPUs with higher clock speed
  26. 26. Complexity
  27. 27. 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)
  28. 28. 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
  29. 29. Not opinionated For example: http://twitter.github.io/effectivescala/ • Many ways to do the same thing • Coding conventions help, but only so much
  30. 30. Not opinionated def foo() = "foo" def bar = "bar" ! foo foo() bar bar() // won't compile For example: http://twitter.github.io/effectivescala/ • Many ways to do the same thing • Coding conventions help, but only so much
  31. 31. Not opinionated def foo() = "foo" def bar = "bar" ! foo foo() bar bar() // 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 0 baz("x") baz “x" // won't compile
  32. 32. Not opinionated def foo() = "foo" def bar = "bar" ! foo foo() bar bar() // 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 0 baz("x") baz “x" // won't compile
  33. 33. Not opinionated def foo() = "foo" def bar = "bar" ! foo foo() bar bar() // 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 0 baz("x") baz “x" // won't compile
  34. 34. Surprises http://dan.bodar.com/2013/12/04/wat-scala/
  35. 35. Surprises List(1, 2, 3).toSet http://dan.bodar.com/2013/12/04/wat-scala/
  36. 36. Surprises List(1, 2, 3).toSet scala.collection.immutable.Set[Int] = Set(1, 2, 3) http://dan.bodar.com/2013/12/04/wat-scala/
  37. 37. Surprises List(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/
  38. 38. Surprises List(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/
  39. 39. 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)
  40. 40. 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)
  41. 41. 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
  42. 42. Trait entanglements • Makes it difficult to reason about behaviour
  43. 43. Trait entanglements • Makes it difficult to reason about behaviour trait A { def foo = "a" }
  44. 44. Trait entanglements • Makes it difficult to reason about behaviour trait A { def foo = "a" } trait B extends A { override def foo = "b" }
  45. 45. 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 B new C().foo
  46. 46. 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 B new C().foo "b"
  47. 47. 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 B new C().foo "b" class D extends B with A new D().foo
  48. 48. 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 B new C().foo "b" class D extends B with A new D().foo "b"
  49. 49. Trait entanglements (2) ArticlePageSteps WebDriverSupport AuthorStepsCoverImageSteps SummarySection Waiter SectionPageSteps CommonPageSteps WebElementSupport Assertions Uris TripleEquals OnHost TripleEqualsSupport MachineNames
  50. 50. 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
  51. 51. 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
  52. 52. 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
  53. 53. 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
  54. 54. So, what’s next?
  55. 55. 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
  56. 56. 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)
  57. 57. Thanks @patforna patric.fornasier@springer.com http://joinit.springer.com
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×