Slide 1

Slide 1 text

Copyright © nextbeat All Rights Reserved 社内の共通フレームワークをScala 3移行するまで Copyright © nextbeat All Rights Reserved Nextbeat Tech Bar:Scala今昔物語(2023年4月21日) 株式会社ネクストビート 溝上友貴

Slide 2

Slide 2 text

Copyright © nextbeat All Rights Reserved Copyright © nextbeat All Rights Reserved 2 今日話すこと ● ネクストビートの Scala 3 採用状況 ● 社内での Scala 3 導入体験談 (Scala 3 PJ)

Slide 3

Slide 3 text

Copyright © nextbeat All Rights Reserved Copyright © nextbeat All Rights Reserved 3 自己紹介 溝上 友貴 (Mizogami Tomoki, @taretmch) ● 株式会社ネクストビート Technology Division Development Team ○ 2020年4月〜新卒入社 ○ 2022年4月〜テックリード ● FP、圏論、スクラム開発に興味があります ○ Scala で始める圏論入門 ○ 圏論勉強会 ● 開発言語 ○ Scala, TypeScript, Ionic (Angular) ● 愛友:ハムスター 🐹

Slide 4

Slide 4 text

Copyright © nextbeat All Rights Reserved Copyright © nextbeat All Rights Reserved 4 Scala 3 PJ の発足 ● Scala 3 は2021年5月13日にリリースされた ● 個人的に興味があり、社内で Scala 3 勉強会を実施(全 8回) ○ [第0回〜第1回] Scala 3 ことはじめ ○ [第2回〜第4回] 文法 ○ [第5回〜第6回] Context Abstractions ○ [第7回〜第8回] 型システム ● 上記の活動が発端となり 社内のコードを Scala 3 に移行する PJ を始めた (nextbeat developers lab.) 興味があって始めた勉強会から、 Scala 3 PJ が開始

Slide 5

Slide 5 text

Copyright © nextbeat All Rights Reserved Copyright © nextbeat All Rights Reserved 5 Scala 3 PJ の発足 採用技術 ● バックエンド ○ Scala, Play Framework ○ Scala 3, Typelevel ○ NestJS ● フロントエンド ○ Svelte ○ Angular ○ Ionic → 当時は Scala only 複数事業を爆速で立ち上げるために、 共通ロジックをフレームワーク化 ネクストビートは事業領域が広い。どこから始めよう?

Slide 6

Slide 6 text

Copyright © nextbeat All Rights Reserved Copyright © nextbeat All Rights Reserved 6 Scala 3 PJ の発足 ● Play Framework, Slick, AWS SDK をラップしていたため、 誰でも簡単にプロダクションコードを書くことができた ● 一方で、全事業の技術スタックが共通フレームワークに依存 してしまっていた ● ラップしていたため標準な書き方ができず、 学習コストが高かった ○ 学習のために研修生が作成したコンテンツ ■ エンティティに関する記事 ■ リポジトリに関する記事 → 既存プロダクトを Scala 3 に更新するのは非現実的 😱 (Play も対応していなかったし) → 新規プロダクトを Scala 3 で作れるよう、エンティティの定義やデータベースコネクションなどのコアな部分だけを担うライブラリ を開発することに ✊ 「共通フレームワーク」という技術的負債

Slide 7

Slide 7 text

Copyright © nextbeat All Rights Reserved Copyright © nextbeat All Rights Reserved 7 IO http4s circe doobie 共通ライブラリの開発 Future Akka HTTP play-json Slick ScalikeJDBC 採用ライブラリの選定 ZIO zio-http zio-json zio-protoquill

Slide 8

Slide 8 text

Copyright © nextbeat All Rights Reserved Copyright © nextbeat All Rights Reserved 8 IO http4s circe doobie 共通ライブラリの開発 Future Akka HTTP play-json Slick ScalikeJDBC 採用ライブラリの選定 ZIO zio-http zio-json zio-protoquill

Slide 9

Slide 9 text

Copyright © nextbeat All Rights Reserved Copyright © nextbeat All Rights Reserved 9 class TaskRepositoryImpl(using xa: Transactor[IO]) extends TaskRepository[IO], DoobieRepository[IO], CustomMapping: def findAll(): IO[List[Task.EmbeddedId]] = ??? 共通ライブラリの開発 F[_] の選定はプロダクト側で行う //- Repository for task trait TaskRepository[F[_]]: /** Get list of all entities * * @return list of all entity */ def findAll(): F[Seq[Task.EmbeddedId]] class TaskRepositoryImpl(using QuillDatabase) extends TaskRepository[Id], QuillRepository, db.CustomEncoding: def findAll(): Seq[Task.EmbeddedId] = ??? ドメイン層 実装 (doobie) 実装 (quill)

Slide 10

Slide 10 text

Copyright © nextbeat All Rights Reserved Copyright © nextbeat All Rights Reserved 10 共通ライブラリの開発 Entity Id は shapeless の tagged type を使って定義していたが、 Scala 3 では Opaque Type を使って定義することができた 書いてて楽しかった Scala 3 // Opaque types opaque type Id <: EntityId.IdLong = EntityId.IdLong object Id extends EntityId.IdLongGen[Id] // Tagged Type val Id = the[Identity[Id]] type Id = Long @@ User Scala 3 (標準ライブラリのみ ) Scala 2 (shapeless を利用)

Slide 11

Slide 11 text

Copyright © nextbeat All Rights Reserved Copyright © nextbeat All Rights Reserved 11 共通ライブラリの開発 EntityId.IdLong, EntityId.IdString, EntityId.IdLongGen などを定義することによって、 Json Formatter や Mapped Column Type などの given インスタンスを共通定義している 書いてて楽しかった Scala 3 // Circe の例 // Json Encoder given [L <: EntityId.IdLong]: Encoder[L] = e => Encoder.encodeLong(e.toLong) given [S <: EntityId.IdString]: Encoder[S] = e => Encoder.encodeString(e.toString) // Json Decoder given [L <: EntityId.IdLong]: Decoder[L] = Decoder[Long].emap(l => Try(EntityId.IdLong(l).asInstanceOf[L]).toEither.left.map(_.getMessage)) given [S <: EntityId.IdString]: Decoder[S] = Decoder[String].emap(s => Try(EntityId.IdString(s).asInstanceOf[S]).toEither.left.map(_.getMessage))

Slide 12

Slide 12 text

Copyright © nextbeat All Rights Reserved Copyright © nextbeat All Rights Reserved 12 共通ライブラリの開発 ● インデント記法は見やすく、書きやすい ● 標準ライブラリの機能が強く、 Enum 型や Union Type の使い勝手が良い ● Implicit が書きやすくなり (given, using, extension, Conversion)、ContextFunction によるコンテキストの引き回しがやり やすくなった ○ 例)データベースのコネクション周り 書いてて楽しかった Scala 3

Slide 13

Slide 13 text

Copyright © nextbeat All Rights Reserved Copyright © nextbeat All Rights Reserved 13 プロダクションへの Scala 3 導入 ● ChatBot のバックエンドを開発 ● Typelevel スタックで API サーバーも稼働している そして新規事業へ

Slide 14

Slide 14 text

Copyright © nextbeat All Rights Reserved Copyright © nextbeat All Rights Reserved 14 ● Scala 3 で動くようになっただけで、最適解ではない ● 今後も Scala が必要なプロダクトの開発には Scala 3 を採用していく ● Play Framework の Scala 3 の安定版リリースも近いので、既存プロダクトのバージョン更新も本格的に進めていきたい 今後の展望 まだまだ発展途上