Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Scala警察のすすめ

9,114 views

Published on

#scalafukuoka

Published in: Software
  • Hello! Get Your Professional Job-Winning Resume Here - Check our website! https://vk.cc/818RFv
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Scala警察のすすめ

  1. 1. Scala警察のすすめ Naoki Takezoe @takezoen BizReach, Inc
  2. 2. 有名OSSでもScala的に微妙なコードが多い ● ビッグデータ、機械学習界隈のプロダクトにこの 傾向がある ● 元々関数型界隈ではなく、ビッグデータ界隈や機 械学習界隈の人がSparkやMLlibを使うために Scalaを使っているので仕方ない ● むしろScala警察活躍のチャンス!!!!
  3. 3. Scala的に微妙なコードあるある
  4. 4. その1. Procedure Syntax
  5. 5. Procedure Syntax メソッドの戻り値がUnitの場合はメソッド定義の「=」 を省略できるという記法 def hello() { "Hello World!!" }
  6. 6. なぜダメか? ● 戻り値の型がUnitになってしまう ● Javaから来た人が間違って書いてしまいがち ● 将来のバージョンのScalaでは廃止予定 def hello(): Unit = { "Hello World!!" } def hello(): String = { "Hello World!!" } こういうメソッドを定義しているつもりが・・・ 実はこうなっている
  7. 7. どうすればよいか? Procedure Syntaxは使わない def hello(): String = { "Hello World!!" } def hello() = { "Hello World!!" } または
  8. 8. その2. Unit is not Unit value
  9. 9. Unit値を返すつもりでUnitと書いてしまう def hello(): Unit = { // ...いろいろ処理... Unit } これ
  10. 10. なぜダメか? ● Unit値は()、UnitはUnitオブジェクト ● メソッドの戻り値など、実害はないケースが多い ので気づきにくい scala> val x = () x: Unit = () scala> val x = Unit x: Unit.type = object scala.Unit
  11. 11. どうすればよいか? Unitではなく()と書きましょう def hello(): Unit = { // ...いろいろ処理... () } こう書く
  12. 12. その3. Auto Tupling
  13. 13. 引数を自動的にタプルに変換する機能 def hello(x: (String, String)): String = { x._1 + " " + x._2 } // 本来であればこう呼び出す hello(("Naoki", "Takezoe")) // こう書ける hello("Naoki", "Takezoe")
  14. 14. なぜダメか? ● なぜコンパイルエラーになるのかわかりにくい ケースがある ● リファクタリング時に意図せずコンパイルが通って しまうケースがある
  15. 15. どうすればよいか? ● Auto-Tuplingを使わずに記述する ● 名前付き引数で引数を渡す ● Any型の引数を持つメソッドを定義する場合や、 リファクタリング時は特に注意する Scalaパズルにも 書いてある!
  16. 16. その3. Escape by "return"
  17. 17. def hello(name: String): String = { return s"Hello ${name}!" } そもそもこういう場合はreturnは不要
  18. 18. 引数チェックのEarly return def hello(names: Seq[String]): String = { // Seqが空の場合 if(names.isEmpty) return "" // Seqに空文字列が含まれている場合 names.foreach { name => if(name.isEmpty) return "" } // 実際の処理 names.mkString(", ") }
  19. 19. なぜダメか? ● メソッドの戻り値の型推論が効かなくなるので戻り 値の型を明示的に記述する必要がある ● 場合によっては例外にコンパイルされている (ControlThrowable)
  20. 20. どうすればよいか? ● 不要な場合は書かない ● if elseやコレクション操作に置き換える ● 使う場合は例外処理に気をつける
  21. 21. def hello(names: Seq[String]): String = { // Seqが空の場合 if(names.isEmpty) "" // Seqに空文字列が含まれている場合 else if(names.exists(_.isEmpty) "" // 実際の処理 else names.mkString(", ") }
  22. 22. 例外処理をする場合 ● Throwableでキャッチしない ● Throwableもキャッチする必要がある場合は NonFatalを使う try { // ...処理... } catch { case NonFatal(t) => t.printStackTrace() } ControlThrowableなどは マッチしない
  23. 23. 他にもよくあるパターン ● varやmutableコレクション ○ ループカウンタやコレクションの詰め替え処理など ● whileループ ○ varやmutableなコレクションと組み合わせで使用されてい ることが多い ○ returnやbreakなどとの合わせ技担っている場合も
  24. 24. ループカウンタが必要な場合 var i = 1 seq.foreach { x => println(s"${i}: ${x}") i = i + 1 }
  25. 25. zipWithIndexを使う seq.zipWithIndex.foreach { case (x, i) => println(s"${i + 1}: ${x}") }
  26. 26. 途中で処理を止めたい場合 var line: String = null val lines = new ListBuffer[String]() line = reader.readLine() while(line != null){ lines += line line = reader.readLine() }
  27. 27. Iterator.continuallyが使える val lines = Iterator.continually(reader.readLine()) .takeWhile(_ != null)
  28. 28. バッドコードを検出するために ● コンパイラのオプションを設定しよう ● Lintツールを使おう ○ scalastyle ○ wartremover scalacOptions in ThisBuild ++= Seq( "-feature", "-unchecked", "-deprecation", "-Xfuture", "-Yno-adapted-args", "-Ywarn-dead-code", "-Ywarn-numeric-widen" )
  29. 29. SparkがScalaの隙間産業を生み出している ● PredictionIO ● Spark MLlib ● Mahout-Spark ● Elasticsearch-Hadoop
  30. 30. SparkがScalaの隙間産業を生み出している ● PredictionIO ● Spark MLlib ● Mahout-Spark ● Elasticsearch-Hadoop あなたもScala警察として OSSコミッタになろう!

×