Upgrade to Pro — share decks privately, control downloads, hide ads and more …

社内の共通フレームワークをScala 3移行するまで/NextbeatTechBar-20230421-1

社内の共通フレームワークをScala 3移行するまで/NextbeatTechBar-20230421-1

2023年4月21日に開催された「Nextbeat Tech Bar:Scala今昔物語」にて発表した資料です。

nextbeat-engineer

April 24, 2023
Tweet

More Decks by nextbeat-engineer

Other Decks in Technology

Transcript

  1. Copyright © nextbeat All Rights Reserved 社内の共通フレームワークをScala 3移行するまで Copyright ©

    nextbeat All Rights Reserved Nextbeat Tech Bar:Scala今昔物語(2023年4月21日) 株式会社ネクストビート 溝上友貴
  2. Copyright © nextbeat All Rights Reserved Copyright © nextbeat All

    Rights Reserved 2 今日話すこと • ネクストビートの Scala 3 採用状況 • 社内での Scala 3 導入体験談 (Scala 3 PJ)
  3. 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) • 愛友:ハムスター 🐹
  4. 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 が開始
  5. 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 複数事業を爆速で立ち上げるために、 共通ロジックをフレームワーク化 ネクストビートは事業領域が広い。どこから始めよう?
  6. Copyright © nextbeat All Rights Reserved Copyright © nextbeat All

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

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

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

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