Scala 3, what does it means for me? / Scala 3って、私にはどんな影響があるの? by Joan Goyeau
1. JOAN GOYEAU
SENIOR DATA ENGINEER
Scala 3,
What does it
means to me?
Scala 3 について話す前に、私の仕事・チームを紹介します。
2. “Netflix is just streaming movies. I don’t see what
else you are doing there.”
— Most of my friends
Netflix って動画ストリーミングでしょ。他になにをやってるのかよくわからない、と多
くの友人から言われます。
15. Scala 3,
What does it
means to me?
Netflix では、大量のデータの処理に Scala を使っています。Scala 3 も楽しみにしてますが、私た
ちユーザーのコーディングや問題解決にどのような影響を与えるか理解することは難しいことでし
ょう。そこで、Scala 2 の悩み事がどのように解決されるか紹介します。
16. SCALA 3, WHAT DOES IT MEANS TO ME?
JOAN GOYEAU
1.
2.
3.
4.
5.
Episode 1:
Limited
Enumerations
制約のある列挙型
17. object PlayTraceType extends Enumeration {
type PlayTraceType = Value
val Start, Pause, Stop = Value
}
PlayTraceType.values
PlayTraceType.withName("Pause")
全ての値の取得と、withName関数がある点は良いですね。
18. sealed trait PlayTraceType
object PlayTraceType {
case object Start extends PlayTraceType
case object Pause extends PlayTraceType
case object Stop extends PlayTraceType
}
19. sealed abstract class PlayTraceType(description: String)
object PlayTraceType {
case object Start extends PlayTraceType("Start event")
case object Pause extends PlayTraceType("Pause event")
case object Stop extends PlayTraceType("Stop event")
}
PlayTraceType.values
PlayTraceType.withName("Pause")
20. import enumeratum._
sealed abstract class PlayTraceType(description: String)
extends EnumEntry
object PlayTraceType extends Enum[PlayTraceType] {
case object Start extends PlayTraceType("Start event")
case object Pause extends PlayTraceType("Pause event")
case object Stop extends PlayTraceType("Stop event")
val values = findValues
}
PlayTraceType.values
PlayTraceType.withValue("Pause")
22. enum PlayTraceType(description: String) {
case Play extends PlayTraceType("Start event")
case Pause extends PlayTraceType("Pause event")
case Stop extends PlayTraceType("Stop event")
}
PlayTraceType.enumValues
PlayTraceType.enumValueNamed("Play")
23. Episode 2:
Either and Coproducts
SCALA 3, WHAT DOES IT MEANS TO ME?
JOAN GOYEAU
Eitherと余積(Coproduct)
24. def audio(movieId: String):
Either[NotFoundException, Array[Byte]] =
??? // Get audio here
def subtitle(movieOffset: Int):
Either[Exception, String] =
if (movieOffset < 0)
new IllegalArgumentException(s"$movieOffset is < than 0")
else ??? // Get subtitles here. May throw NotFoundException
25. def audio(movieId: String):
Array[Byte] | NotFoundException =
??? // Get audio here
def subtitle(movieOffset: Int):
String | IllegalArgumentException | NotFoundException =
if (movieOffset < 0)
new IllegalArgumentException(s"$movieOffset is < than 0")
else ??? // Get subtitles here. May throw NotFoundException
26. def audio(movieId: String):
Array[Byte] | NotFoundException =
??? // Get audio here
def subtitle(movieOffset: Int Refined Positive):
String | NotFoundException =
??? // Get subtitles here. May throw NotFoundException
36. def recordView(movieId: String, userId: String) =
???
val userId = "some_user_id"
val movieId = "some_movie_id"
recordView(userId, movieId)
37. type MovieId = String
type UserId = String
def recordView(movieId: MovieId, userId: UserId) =
???
val userId: UserId = "some_user_id"
val movieId: MovieId = "some_movie_id"
recordView(userId, movieId)
38. case class MovieId(value: String)
case class UserId(value: String)
def recordView(movieId: MovieId, userId: UserId) =
???
val userId: UserId = UserId("some_user_id")
val movieId: MovieId = MovieId("some_movie_id")
recordView(userId, movieId)
39. case class MovieId(value: String) extends AnyVal
case class UserId(value: String) extends AnyVal
def recordView(movieId: MovieId, userId: UserId) =
???
val userId: UserId = UserId("some_user_id")
val movieId: MovieId = MovieId("some_movie_id")
recordView(userId, movieId)
40. opaque type MovieId = String
opaque type UserId = String
def recordView(movieId: MovieId, userId: UserId) =
???
val userId: UserId = "some_user_id"
val movieId: MovieId = "some_movie_id"
recordView(userId, movieId)
42. “I learned implicits today.
The one that made me smile is implicit classes.
You can be so lost if you are not aware of what it is.”
— Yannick
implicits を学んでわかったこと。 暗黙のクラスは私を笑顔にしてくれる。しかしその正
体に気づかなければ、途方に暮れることでしょう。
56. def send[T](data: T)
(implicit encoder: Encoder[T],
httpClient: HttpClient): Seq[String] = {
val raw = encoder(data)
// Send the data
}
57. def send[T](data: T)
(implicit encoder: Encoder[T]): Seq[String] = {
val raw = encoder(data)
// Send the data
}
send(Movie("Black Mirror", 1000))(0)
type mismatch;
found : Int(0)
required: Encoder
58. def send[T](data: T)
(implicit encoder: Encoder[T]): Seq[String] = {
val raw = encoder(data)
// Send the data
}
send(Movie("Black Mirror", 1000)).apply(0)
59. trait Encoder[T] {
def apply(o: T): String
}
implied for Encoder[Int] = _.toString
implied for Encoder[Movie] = ???
def send[T](data: T)
given (encoder: Encoder[T]: Seq[String] = {
val raw = the[Encoder[T]](data)
the[HttpClient].send(raw)
// Send the data
}
60. trait Encoder[T] {
def apply(o: T): String
}
implied for Encoder[Int] = _.toString
implied for Encoder[Movie] = ???
def send[T](data: T)
given (encoder: Encoder[T],
client: HttpClient): Seq[String] = {
val raw = the[Encoder[T]](data)
the[HttpClient].send(raw)
}
61. SCALA 3, WHAT DOES IT MEANS TO ME?
JOAN GOYEAU
Ep9: Untyped equality
型チェックされない同値性
62. case class Movie(title: String, duration: Int)
val blackMirror = Movie("Black Mirror", 1000)
Hi // today I’m going to speak about Scala 3 / and what it MEANS to us // but BEFORE we start / I’d like tell you a bit MORE about what we do in my team / and what we use Scala for.My name is Joan / and I’m a Data Engineer in the Streaming Data Science & Engineering team at Netflix
This friend is basically saying Netflix is just that.
We are responsible for 15% of the internet traffic.
And it goes all the way to 40% at peak time.
As you may know, Netflix is fully hosted on AWS. We don’t own any server.
And you are using the network of a provider like NTT docomo.
If we apply our scale it would probably look like this.
Both the ISP and Netflix would have to pay a lot in transit cost.
The ISP wouldn’t be happy as we exploded their network for which they support the full cost.
So we fit servers directly into the ISPs infrastructure.
The ISP and Netflix get back their transit cost
And the latency is much lower for the users
This is the holy grail of Netflix
Like the CAP theorem:
If you want to start fast either you cut on quality or you will have more rebuffers.
If you want high quality either you start slow or you will have more rebuffers.
If you don’t want rebuffers either you cut on quality or you buffer before starting.
We believe we can push the boundaries more and more.
To do so, every decision at Netflix is Data Driven.
Anything we do is AB tested.
For example, we take like a million users that we try a UI change on and compare with another million on the baseline
We have many tests in parallel at scale.
We’ve been able to improve our encoders to compress a 2h movie to...
5,924 downloadables
We AB even the images and the trailers
There is also another type of testing we do at Netflix.When someone tells us that it should failover if we have an issue, we say ok lets try it in prod.
So data is core to Netflix from measuring if anything is working well, through testing changes, to business decisions.
And at Netflix we are using quiet some Scala to process the ton of data we collect.
We’ve all heard about Scala 3 either through Martin Odersky’s great talks or feature listing on Dotty’s website and we are very excited by this upcoming release.
But it’s often hard for us, users of Scala, to understand how it will impact our ways of coding and what issues we are trying to solve.So I thought I’ll reverse everything and speak about the annoying stuff in Scala 2 and talk about how Scala 3 aims to tackle these.
It’s good because we get those functions to get all values or withName
You might wonder, this is all cool but how are we going to go on Scala 3?
It’s already painful between minor versions.
A 2.11 project depends on a 2.11 library.
If we upgrade to 2.12 then all our dependencies need to be compiled to 2.12.
Why? The bitcode generated by the Scala compiler is different, for example in 2.12 we are now compiling higher order functions as java lambdas whereas before it was a hack with classes.
Why java doesn’t have this issue? Because they control the JVM so they can handle the breaking change on the JVM side.
All we need is upgrade the dependencies.
But now all the 2.11 libraries won’t compile anymore.
So we cross compile between Scala versions
As we add new supported Scala versions we drop the old ones.
When Scala 3 will be released libraries would have to cross compile to Scala 3 without using all the new features.
Even better you could now compile to any target.
So this feature will be in 2.14 so that we can have a smooth transition to Scala 3.