Upload
tzach-zohar
View
378
Download
0
Embed Size (px)
Citation preview
“Insulin” for Scala’s Syntactic DiabetesTzach Zohar // Kenshoo // Scalapeño 2016
OR: How to adopt Scala and survive source
Who am INOT Chuck Norris!
Scala “Advanced Beginner” / “Competent”
System Architect @ Kenshoo
Who’s Kenshoo10-year Tel-Aviv based startup
Industry Leader in Digital Marketing
Java + JavaScript shop
http://kenshoo.com/
Scala @ Kenshoo5 services written in Scala
More to come...
Internal Scala course on the go
What’s so scary?
trait GeneralizedCategory { type U <: Hom type =>:[A >: U#L <: U#H, B >: U#L <: U#H] = U#C[A, B]
def id[A >: U#L <: U#H]: A =>: A
def compose[A >: U#L <: U#H, B >: U#L <: U#H, C >: U#L <: U#H]( f: B =>: C, g: A =>: B): A =>: C
def *[UY<:Hom](that : GeneralizedCategory {type U=UY}) = Category.ProductCategory[U,UY](this,that)}
source
source
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That
Now for some sane examples source
val tuples = List((1, 374), (3, 42), (5, 693))
val ids = tuples.map(_._1)val ids = tuples.map(tuple => tuple._1)val ids = tuples.map { tuple => tuple._1 }
val tuples = List((1, 374), (3, 42), (5, 693))
val ids = tuples.map(_._1)val ids = tuples.map(tuple => tuple._1)val ids = tuples.map { tuple => tuple._1 }
val ids = tuples.map(t => t match { case (id, value)=> id })val ids = tuples.map(_ match { case (id, value) => id })val ids = tuples.map({ case (id, value) => id })val ids = tuples.map { case (id, value) => id }val ids = tuples.map { case (id, _) => id }
case class Profile() { … }case class ProfileId(id: Int)
def loadProfile(profileId: ProfileId): Profile = ???
case class Profile() { … }case class ProfileId(id: Int)
def loadProfile(profileId: ProfileId): Profile = ???loadProfile(ProfileId(3))loadProfile(new ProfileId(3))loadProfile(profileId = ProfileId(3))loadProfile(profileId = new ProfileId(3))
case class Profile() { … }case class ProfileId(id: Int)implicit def toId(i :Int): ProfileId = ProfileId(i)
def loadProfile(profileId: ProfileId): Profile = ???loadProfile(ProfileId(3))loadProfile(new ProfileId(3))loadProfile(profileId = ProfileId(3))loadProfile(profileId = new ProfileId(3))loadProfile(3)loadProfile(profileId = 3)
def loadInt(): Int = { … }
def f(value: () => Int) = { … }f(() => 2 + loadInt())
def loadInt(): Int = { … }
def f(value: () => Int) = { … }f(() => 2 + loadInt())
def f(value: => Int) = { … } f(2 + loadInt())
Issues so far
Too many ways to write the same thingTradeoff between short and readable
Advanced features getting in the way
Insulin to the rescue
Style Guides1. The basic: Official Scala-Lang Style Guide2. The conservative: Databricks' Scala Style Guide3. The exhaustive: Twitter's Effective Scala4. Your own!
Style Guidesimplicit def toId(i :Int): ProfileId = ProfileId(i)loadProfile(ProfileId(3))loadProfile(3)
“Do not use implicits to do automatic conversions between similar datatypes”
Style Guides
“Avoid infix notation for methods that aren't symbolic methods”
list map funcstring contains "foo"list.map(func)string.contains("foo")val x = y + 2
Style Guidesval ids = tuples.map(t => t match { case (id, value)=> id })val ids = tuples.map(_ match { case (id, value) => id })val ids = tuples.map { case (id, value) => id }val ids = tuples.map { case (id, _) => id }
“Use pattern matching directly in function definitions whenever applicable”
Style Guidesdef f(value: => Int) = ???f(2 + 3)def f(value: () => Int) = ???f(() => 2 + 3)
“Avoid using call by name. Use () => T explicitly”
@throws[IOException]def mightThrowException(): Int
def neverThrowsException(): Option[Int]def neverThrowsException(): Try[Int]def neverThrowsException(): Either[Int, String]def neverThrowsException(): MyResult
Style Guides
“Scala provides an exception facility, but do not use it for commonplace errors”
val ids = tuples.map(_._1)val ids = tuples.map(tuple => tuple._1)
val ids = tuples.map { case (id, value) => id }val ids = tuples.map { case (id, _) => id }
Style Guides
“Avoid using tuple field names like _1, prefer pattern matching or a dedicated case class”
2. Code Reviews source
Code ReviewsRefer author to Style GuidesMix “Scala Levels” - juniors should review seniors’ code
Code Reviews
Code Reviews
Code Reviews
[Only] methods which act as accessors [...] should be declared without parentheses, except if they have side effects
3. Style Checkers source
Style CheckersAutomate some of the (simpler) rules1. Scalastyle (SBT/Gradle/Maven/Eclipse/IntelliJ)2. Scalafmt (SBT/Vim/CLI/IntelliJ) [NEW]
⌚ 18:45:25 ➜ sbt scalastyle [info] Loading project definition from /.../project[info] Set current project to myProject (in build file:/.../)[warn] MyJob.scala:31:6: parameter.number.message[error]MyService.scala:42:6: public.methods.have.type.message[info] Processed 42 file(s)[info] Found 1 errors[info] Found 2 warnings[info] Found 0 infos[info] Finished in 39 ms
Style Checkers
4. Scala Levels source
Scala Levels
Application Programmer Library Designer
A1: Beginner L1: Junior
A2: Intermediate L2: Senior
A3: Expert L3: Expert
Defined by Martin Odersky in a 2011 post
Scala LevelsApplication Includes
A1: Beginner Basic syntax; Simple Closures; Collections; For-expressions; …
A2: Intermediate Pattern matching; Trait composition; (Tail) Recursion; …
A3: Expert Folds; Streams + other lazy data structures; Actors; …
Scala LevelsLibrary Includes
L1: Junior Type parameters; Traits; Lazy vals; Currying; By-name parameters
L2: Senior Variance; Existential types; Cake Pattern; Structural types; Extractors; …
L3: Expert Early initializers; Abstract types; Implicit definitions; Higher-kinded types; …
source
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That
Conclusions
1. Intermediate Scala works
(might be better than Expert Java!) 2. Style and Feature-
set can be controlled
3. No Chuck-Norrisness Required source
Thank You