Scala Refactoring for Fun and Profit (Japanese subtitles)
-
Upload
tomer-gabel -
Category
Engineering
-
view
5.066 -
download
1
Transcript of Scala Refactoring for Fun and Profit (Japanese subtitles)
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!