scala refactoring for fun and profit (japanese subtitles)
TRANSCRIPT
Scala Refactorin
gTomer Gabel, Scala Matsuri 2016
for Fun and Profit
楽しく役立つ Scala リファクタリング
Agenda• For the next 40
minutes, we’ll:– Look at examples
– Discuss patterns
– … and anti-patterns– Showcase
refactoring techniques例を通してパターンとアンチパターンを議論し、
リファクタリングのテクニックを説明する
Our Victim• … is ScalaChess
– Provides a full domain model for chess
– Good test coverage
– High quality code– MIT license– Integrated in
lichess.org* ScalaChess is an open-source project by Thibault Duplessis
チェスのドメインモデルを備える ScalaChess を例にする高品質で lichess.org と統合された MIT ライセンスのOSS
THE LAY OF THE LAND前線の状況
Stringly Typed“Used to describe an implementation that needlessly relies on strings when programmer & refactor friendly options are available.” -- Coding Horror
アンチパターン: Stringly Typed型付けできる所で不必要に文字列に頼った実装のこと
Stringly Typed• Examples:– 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
place3. What’s with all the
boilerplate?
Stringly Typed の例 1: パースしてないデータを持ち回す
Stringly Typed• Examples:– 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 handling3. Zero boilerplate!
パース後のデータを使うことで効率的で、エラー処理が容易に、お決まりの処理も不要になる
Stringly Typed• Examples:– 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 :-)
Stringly Typed の例 2: Option の代わりに空文字を使う
REAL-WORLD EXAMPLE TIME!
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
Scala にはたくさんのコレクション、 case クラス、関数、タプルがある。これらは、実は簡単に濫用できてしまう
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?アンチパターン:
一行に処理を詰め込み過ぎる
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!
中間状態に名前を付けよう!
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?
アンチパターン:タプルの使いすぎ
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.
Scala では case クラスを簡単に定義できるどんどん使おう
REAL-WORLD EXAMPLE TIME!