non-functional programming in scala

57
Non-Functional Programming in Scala Naoki Takezoe @takezoen BizReach, Inc

Upload: takezoe

Post on 21-Jan-2018

5.074 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Non-Functional Programming in Scala

Non-Functional Programming in Scala

Naoki Takezoe@takezoen

BizReach, Inc

Page 2: Non-Functional Programming in Scala

自己紹介

竹添 直樹: @takezoen

ビズリーチという会社でScalaを書いてます

OSS開発や技術書の執筆などもしています

Page 3: Non-Functional Programming in Scala

主題

Scalaがもっと普及して欲しい

そうしないと自分が失業してしまう(重要!!)

そのためにはどうすればいいのか?

Page 4: Non-Functional Programming in Scala

いままでやってきたこと

Scalaの本を書いたり、翻訳したりした

SI企業で業務システム開発の事例を作った

Scalaでオープンソースプロダクトを開発

Scala関連イベントのサポート

Webサービス企業でそれなりの規模でScalaを採用した

Page 5: Non-Functional Programming in Scala

突き当たった壁

Page 6: Non-Functional Programming in Scala

関数型プログラミング

Page 7: Non-Functional Programming in Scala

関数型プログラミング in Scala

基本的には副作用を使った手続き型プログラミング言語

関数型言語由来の様々な機能を備えている

for内包表記、暗黙的なモナド

Scalaz、Cats、Slickなどの関数型ライブラリ

どこまで関数型に寄せるか?という選択を迫られる

プログラミングスタイルだけでなく、ライブラリやフレームワークの

選定から考慮しなくてはならない

Page 8: Non-Functional Programming in Scala

振り返ってみる

業務での開発で起きたこと

OSS開発で起きたこと

Page 9: Non-Functional Programming in Scala

業務での開発で起きたこと

時間

Scala力

Page 10: Non-Functional Programming in Scala

業務での開発で起きたこと

最初はみんな初心者

時間

Scala力

Page 11: Non-Functional Programming in Scala

業務での開発で起きたこと

Scala力アップ!!

最初はみんな初心者

時間

Scala力

Page 12: Non-Functional Programming in Scala

業務での開発で起きたこと

Scala力アップ!!

最初はみんな初心者

後から入ってくる人つらい!!

時間

Scala力

ハードルの高さ

Page 13: Non-Functional Programming in Scala

こうあって欲しい(気持ちは理解できる)

時間

Java力

Page 14: Non-Functional Programming in Scala

業務での開発で起きたこと

最初はみんなScala初心者だった

初期のメンバーが少しずつレベルアップしてくる

関数型プログラミングが取り入れられてくる

時代によってコードの傾向が違う

後から入ってくる人ほどつらくなってしまう

Page 15: Non-Functional Programming in Scala

振り返り

Scalaはプログラマの成長にあわせてスタイルを変えられる

長期間、固定のチームで開発するのであればチームの成長にあ

わせて変化していくことができる

メンバーの増加・入れ替わりが激しい場合は変化が大きいとどん

どんハードルが上がっていってしまう

Page 16: Non-Functional Programming in Scala

OSS開発で起きたこと

Elasticsearch-Hadoop、Apache PredictionIOなど

手続き型バリバリのプログラミングスタイル

varやmutableコレクション、whileループ、returnや例外なども多

用されている

Page 17: Non-Functional Programming in Scala

OSS開発で起きたこと

コミッターのスキルが低いのか?そんなことはない

バックグラウンド、モチベーションの違い

SparkのためにScalaを使っている

Page 18: Non-Functional Programming in Scala

振り返り

言語としてではなくプロダクトとしてのニーズが存在する

○○を使えば□□ができる、というフックは増やしていくべき

Page 19: Non-Functional Programming in Scala

関数型プログラミングへのモチベーションが低い状況でどうScalaを使うか?

Page 20: Non-Functional Programming in Scala

方針

そもそもScalaは副作用のある手続き型プログラミング言語であ

り、モナドを意識せずに使えるように設計されている

Scalaの便利な機能を使いつつ、関数型プログラミングに寄せす

ぎないようにする

Page 21: Non-Functional Programming in Scala

使うべきか?使わないべきか?

● var、while● mutableコレクション

● return● 例外

● null● Option.get● for内包表記

● 型クラス

Page 22: Non-Functional Programming in Scala

考えてみよう!!

Page 23: Non-Functional Programming in Scala

var、while

Page 24: Non-Functional Programming in Scala

var、while

ループ処理などでフラグやアキュムレータなどに使いがち

takeWhileやfoldLeftなどで代用可能だが取っつきづらい

var line = reader.readLine()

while(line != null) {

...

line = reader.readLine()

}

Page 25: Non-Functional Programming in Scala

var、while

ループ処理などでフラグやアキュムレータなどに使いがち

takeWhileやfoldLeftなどで代用可能だが取っつきづらい

var line = reader.readLine()

while(line != null) {

...

line = reader.readLine()

}

Page 26: Non-Functional Programming in Scala

var、while

メソッド内での利用であれば許容する

valはJavaでfinalをつけるかどうかくらいの感覚で使い分けるの

がよさそう

Page 27: Non-Functional Programming in Scala

mutableコレクション

Page 28: Non-Functional Programming in Scala

mutableコレクション

ループしながら詰め替えるような処理で使いがち

val list = ...

val map = mutable.Map("some" -> 0, "none" -> 0)

list.foreach { x =>

if (x.nonEmpty) {

map.put("some", map("some") + 1)

} else {

map.put("none", map("none") + 1)

}

}

Page 29: Non-Functional Programming in Scala

mutableコレクション

ループしながら詰め替えるような処理で使いがち

val list = ...

val map = mutable.Map("some" -> 0, "none" -> 0)

list.foreach { x =>

if (x.nonEmpty) {

map.put("some", map("some") + 1)

} else {

map.put("none", map("none") + 1)

}

}

Page 30: Non-Functional Programming in Scala

mutableコレクション

メソッド内での利用であれば許容する

戻り値として返す際にimmutableなコレクションに変換する

使わなくても済むものはimmutableなコレクションを使うように啓

蒙していく

val map = list.groupBy(_.nonEmpty)

.map { case (nonEmpty, values) =>

if(nonEmpty) "some" -> values.size

else "none" -> values.size

}

Page 31: Non-Functional Programming in Scala

return

Page 32: Non-Functional Programming in Scala

return

Ealry returnやループ処理中からのreturnなどが使われがち

def hello(names: Seq[String]): String = {

if(name.isEmpty) return ""

...

}

戻り値の型を明記しないといけなくなる

コンパイル後に例外(ControlThrowable)で実現されるケースが

ある

Page 33: Non-Functional Programming in Scala

return

Ealry returnやループ処理中からのreturnなどが使われがち

def hello(names: Seq[String]): String = {

if(name.isEmpty) return ""

...

}

戻り値の型を明記しないといけなくなる

コンパイル後に例外(ControlThrowable)で実現されるケースが

ある

Page 34: Non-Functional Programming in Scala

return

実際に問題になるケースは少ないので許容してもよいのでは

そもそも例外をThrowableでキャッチしない

try {

...

} catch {

case NonFatal(t) => ...

}

Page 35: Non-Functional Programming in Scala

例外

Page 36: Non-Functional Programming in Scala

例外

エラーを戻り値で返すか?Eitherなどで返すか?

def findUser(): Either[Exception, User] = {

try {

val user: User = ...

Right(user)

} catch {

case e: Exception => Left(e)

}

}

Page 37: Non-Functional Programming in Scala

例外

エラーを戻り値で返すか?Eitherなどで返すか?

def findUser(): Either[Exception, User] = {

try {

val user: User = ...

Right(user)

} catch {

case e: Exception => Left(e)

}

}

Page 38: Non-Functional Programming in Scala

例外

Eitherで返そうとすると

例外の発生は防げないので変換が必要になる

for内包表記やEitherTなどが登場してしまう

通常は積極的に例外に倒してしまってもよいのでは?

ただし非同期処理の場合は別

Page 39: Non-Functional Programming in Scala

null

Page 40: Non-Functional Programming in Scala

null

Page 41: Non-Functional Programming in Scala

null

使うべき理由がまるでない

がくぞー先生に消されてしまう

Optionを使う

Javaライブラリを使う部分は仕方ない

Page 42: Non-Functional Programming in Scala

Option.get

Page 43: Non-Functional Programming in Scala

Option.get

値が必ず入っているはずだと直接getしがち

Noneチェックしてからgetしがち

val opt: Option[String] = ...

if(opt.isDefined){

val str = opt.get

...

}

Page 44: Non-Functional Programming in Scala

Option.get

値が必ず入っているはずだと直接getしがち

Noneチェックしてからgetしがち

val opt: Option[String] = ...

if(opt.isDefined){

val str = opt.get

...

}

Page 45: Non-Functional Programming in Scala

Option.get

opt.getOrElse("") などとする人が出現

getして明示的にエラーになる方がマシではある

mapやforeachなどを使うよう啓蒙していく

Page 46: Non-Functional Programming in Scala

for内包表記

Page 47: Non-Functional Programming in Scala

for内包表記

モナモナするときに使う

for {

project <- findProject(projectId)

user <- findUser(userId)

} yield {

registerComment(project, user, comment)

}

Page 48: Non-Functional Programming in Scala

for内包表記

モナモナするときに使う

for {

project <- findProject(projectId)

user <- findUser(userId)

} yield {

registerComment(project, user, comment)

}

Page 49: Non-Functional Programming in Scala

for内包表記

無理して使わない

コレクション操作やFutureのチェーンをシンプルに記述するため

に使う

その場合もmapやflatMapのシンタックスシュガーという認識があ

ればよい

「モナド」って言わない

Page 50: Non-Functional Programming in Scala

型クラス

Page 51: Non-Functional Programming in Scala

型クラス

implicitの使い方の一種

implicit val userInfoReads = Json.reads[UserInfoInfo]

r.body.validate[UserInfo].fold(

error => ...,

form => ...

)

sealed trait JsValue extends JsReadable {

def validate[A](implicit rds: Reads[A]): JsResult[A]

}

Page 52: Non-Functional Programming in Scala

型クラス

implicitの使い方の一種

implicit val userInfoReads = Json.reads[UserInfoInfo]

r.body.validate[UserInfo].fold(

error => ...,

form => ...

)

sealed trait JsValue extends JsReadable {

def validate[A](implicit rds: Reads[A]): JsResult[A]

}

Page 53: Non-Functional Programming in Scala

型クラス

フレームワークやライブラリで使っているケースが多い

使うだけであれば意識する必要はない(CanBuildFromを意識し

なくてもScalaのコレクションは使える)

play-jsonのReads/Writesのように自分で実装しないといけない

ケースもあるが、そこまで躓くことはない印象(面倒なのはさてお

き...)

「型クラス」って言わない

Page 54: Non-Functional Programming in Scala

結果

● var、while● mutableコレクション

● return● 例外

● null● Option.get● for内包表記

● 型クラス

Page 55: Non-Functional Programming in Scala

最終的にはケースバイケース

これはあくまでも判断の一例

プロダクトの方向性、今後のチーム運営も考えて決める

チームのスキルが一様であればそれにあわせればよい

Page 56: Non-Functional Programming in Scala

Scalaを使う人がもっと増えて欲しい

最初はみんな初心者だった

Scalaで楽しくプログラミングをして欲しい

関数型プログラミングに興味のある人だけでなく、

それ以外の人たちにもScalaを使って欲しい

Scalaを使っているのにというジレンマを感じることもある

いろんな使い方ができるのもScalaの良いところ

Scalaユーザが増えることで自分たちの選択肢も広がる

Page 57: Non-Functional Programming in Scala

ご静聴ありがとうございました