5. Our Victim
• … is ScalaChess
– Provides a full domain
model for chess
– Great test coverage
– High quality code
– MIT license
– Integrated in lichess.org
* ScalaChess is an open-source project by Thibault Duplessis
8. Naming Things
• Scala adds certain classes of offenses:
– Infix notation (a.k.a dot-free syntax)
– Symbolic operators
case class Geo(lat: Double, long: Double) {
def distance(other: Geo): Double = // ...
}
val (center, loc): Geo = // ...
if (centre.distance(loc) <= radius)
Some(loc) else None
9. Naming Things
• Scala adds certain classes of offenses:
– Infix notation (a.k.a dot-free syntax)
– Symbolic operators
case class Geo(lat: Double, long: Double) {
def distanceFrom(other: Geo): Double = // ...
}
val (center, loc): Geo = // ...
if (loc distanceFrom center <= radius)
Some(loc) else None
10. Naming Things
• Scala adds certain classes of offenses:
– Infix notation (a.k.a dot-free syntax)
– Symbolic operators
case class Geo(lat: Double, long: Double) {
def <->(other: Geo): Double = // ...
}
val (center, loc): Geo = // ...
if (loc <-> center <= radius)
Some(loc) else None
Why would you do that?!
11. Naming Things
• There are worse offenders. Take Dispatch:
import dispatch.Http
import Http._
val server = url("http://example.com")
val headers = Map("Accept" -> "application/json")
Http(server >>> System.out) // GET
Http(server <:< headers >>> System.out) // GET
Http(server << yourPostData >|) // POST
12. Naming Things
• There are worse offenders. Take scalaz:
def s[A](a: A) = a.success[List[String]]
val add3 = (x: Int) =>
(y: Int) =>
(z: Int) => x + y + z
val res = (7) <*> (s(8) <*> (s(9) ∘ add3))
assert(res == s(24))
15. Stringly Typed
“Used to describe an implementation
that needlessly relies on strings when
programmer & refactor friendly options
are available.”
-- Coding
Horror
16. Stringly Typed
• Examples:
– Passing dates as strings
– Carrying unparsed data around
– Using empty strings instead of Options
case class Person(name: String, created: String)
def resolveConflict(p1: Person, p2: Person): Person = {
val c1 = dateParser.parse(p1.created)
val c2 = dateParser.parse(p2.created)
if (c1 compareTo c2 > 0) p1 else p2
}
1. Parser needs to be well-known
2. Error handling all over the place
3. What’s with all the boilerplate?
17. Stringly Typed
• Examples:
– Passing dates as strings
– Carrying unparsed data around
– Using empty strings instead of Options
case class Person(name: String, location: String)
def nearest(to: Person, all: List[Person]): Person = {
val geo: Point = Point.parse(to.location)
all.minBy(p => geo.distanceTo(Point.parse(p.location)))
}
1. Inefficient (space/time)
2. Error handling all over the place
3. What’s with all the boilerplate?
18. Stringly Typed
• Examples:
– Passing dates as strings
– Carrying unparsed data around
– Using empty strings instead of Options
case class Person(name: String, location: Point)
def nearest(to: Person, all: List[Person]): Person =
all.minBy(p => to.location distanceTo p.location)1. Efficient (only parsed once)
2. Sane error handling
3. Zero boilerplate!
19. Stringly Typed
• Examples:
– Passing dates as strings
– Carrying unparsed data around
– Using empty strings instead of Options
case class Person(firstName: String, lastName: String)
def render(p: Person): String =
s"""
|<div id='first-name'>${p.firstName}</div>
|<div id='last-name'>${p.lastName}</div>
""".stripMargin
1. Nothing enforces emptiness check!
2. Scala has a great type for these :-)
21. Collective Abuse
• Scala has a massive
collection library
• Loads of built-ins too
– Case classes
– Functions and partials
– Tuples, tuples, tuples
• Fairly easy to abuse
22. Collective Abuse
• Common anti-patterns:
– Too many inline steps
– Tuple overload
val actors: List[(Int, String, Double)] = // ...
def bestActor(query: String) =
actors.filter(_._2 contains query)
.sortBy(-_._3)
.map(_._1)
.headOption
1. What does this even do?!
2. How does data flow here?
23. Collective Abuse
• Common anti-patterns:
– Too many inline steps
– Tuple overload
val actors: List[(Int, String, Double)] = // ...
def bestActor(query: String) = {
val matching = actors.filter(_._2 contains query)
val bestByScore = matching.sortBy(-_._3).headOption
bestByScore.map(_._1)
} Name intermediate steps!
24. Collective Abuse
• Common anti-patterns:
– Too many inline steps
– Tuple overload
val actors: List[(Int, String, Double)] = // ...
def bestActor(query: String) =
actors.filter(_._2 contains query)
.sortBy(-_._3)
.map(_._1)
.headOption
What’s with all these
underscores?
25. Collective Abuse
• Common anti-patterns:
– Too many inline steps
– Tuple overload
case class Actor(id: Int, name: String, score: Double)
def bestActor(query: String, actors: List[Actor]) =
actors.filter(_.name contains query)
.sortBy(-_.score)
.map(_.id)
.headOption
Scala classes are cheap.
Use them.