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

保険SaaSのORM導入について(2022/6/17、Server-Side Kotlin Meetup vol.3)

kazu
June 17, 2022
1k

保険SaaSのORM導入について(2022/6/17、Server-Side Kotlin Meetup vol.3)

kazu

June 17, 2022
Tweet

Transcript

  1. 自己紹介 • 吉本和弘 • 株式会社justInCaseTechnologies(2021/9〜) • 保険SaaS基盤「 joinsure 」のRecordチームのバックエンドエンジニア •

    Kotlin、Spring Boot(Spring WebFlux) • 入社までは • Ruby on Rails • Java、Spring Boot(Spring MVC) • Vue.js、(React.js) 2
  2. 保険会社 * 3 *事業会社や保険代理店 のご利用も可能 顧客 プラン選択 本人認証 告知・重要事項説明 会員資格確認

    商品ページ(LP) & 申込フォーム 契約参照 異動・解約 決済 契約更新 お客様 ポータル 査定・承認 問合せ 提出書類の参照 (電子データ) 支払記録 保険金 請求フォーム クラウドベースの保険基盤をコンポーネントに分けて提供する”joinsure” © 2021 justInCase, All Rights Reserved. 何を開発しているか
  3. 本日の発表の流れ • 背景 • ORMの比較 • フェーズ1 • Spring Data

    R2DBC • フェーズ2 • Spring Data R2DBC、jOOQ • フェーズ3 • jOOQ 4
  4. 背景 保険SaaS「joinsure」Recordの新規開発 • フレームワーク • Spring WebFlux • リアクティブプログラミングによってノンブロッキングで非同期な アプリケーションを開発できるSpring

    Framework • アプリケーションアーキテクチャー • ドメイン駆動設計 • CQRS(コマンドクエリ責務分離) • 更新系、参照系で処理が分離 • ORM • ???(未定) • MyBatis or Exposed or jOOQ or Spring Data R2DBC 6
  5. ORMの比較① • MyBatis • Pros • SQLベースで記述できる • Cons •

    XMLベースでSQLを記述する必要がありメンテナンスコストがかかる 8
  6. ORMの比較② • Exposed • Pros • coroutine サポートがある (non-blocking) •

    Raw SQLを使用することができる • Spring Boot Starterがある • Cons • JSONB / JSON サポートがない • バージョンが0.x.x(安定版ではない) • R2DBCに未対応 9
  7. ORMの比較③ • jOOQ • Pros • SQLライクにKotlinで記述できるのでメンテナンスしやすい • JSONB /

    JSON をサポート • R2DBC に対応している • Cons • R2DBCに対応している(3.15以降)が、Spring Boot Starterは3.14 • https://blog.jooq.org/reactive-sql-with-jooq-3-15-and-r2 dbc/ 10
  8. ORMの比較④ • Spring Data R2DBC • Pros • Spring Dataファミリー(Spring

    Data JDBC、Spring Data JPA) • Spring WebFluxを使う場合は一般的 • CoroutineCrudRepositoryでCRUD処理はORMの標準メソッドで可 能 • Cons • テーブル間のリレーション(Spring Data JPAの「@OneToOne、 @OneToMany」)に対応していない 11
  9. ORMを比較した結論 • Spring Data R2DBC or jOOQ • R2DBCでの実績を重視してSpring Data

    R2DBC • クエリ処理(join)ではORMの標準メソッドが使えなそう • R2dbcEntityTemplateなどでSQLライクに記述できそう • 問題がありそうなら、jOOQの利用を検討する • クエリ系の処理での対応 • R2dbcEntityTemplate • SQLライクにKotlinで実装することができる • joinができない • https://spring.pleiades.io/spring-data/r2dbc/docs/current/reference/html/#r2dbc.enti tyoperations • @Query、DatabaseClientを使ってSQLを記述する 12
  10. ORMの方針(フェーズ1) • 更新系、参照系 • XXXCommandReposity : CoroutineCrudRepository<XXXRecord,XXX> →CRUD処理をORMの機能で実現 • 一部の参照系(ORMの標準機能で実現できない処理)

    • XXXQueryReposity →@Query、DatabaseClientを使ってSQLを記述する  val record = TaskRecord(id = id, name=name) taskCommandRepository.save(record) interface TaskCommandRepository : CoroutineCrudRepository<TaskRecord, UUID> 14
  11. ORMの方針(フェーズ2) • 更新系 • Spring Data R2DBC • XXXCommandReposity :

    CoroutineCrudRepository<XXXRecord,XXX>   →CRUD処理をORMの機能で実現 • 参照系 • jOOQ • spring-boot-starter-jooqがjOOQ:3.14でR2DBCに未対応のため、 R2DBC対応のjOOQ(3.15以降)を単体で導入 17
  12. フェーズ2での課題① • CoroutineCrudRepository.saveメソッドの仕様 • Entity(TaskRecord)のprimary keyがnull→INSERT、値がある→UPDATE →アプリケーションでUUIDを生成できない →複合主キーが使えない @Table("TASKS") data

    class TaskRecord(val name) { @Id val id: UUID?, val name: String, } val id: UUID? = xxx val name:String = xxx val record = TaskRecord(id = id, name=name) taskCommandRepository.save(record) interface TaskCommandRepository : CoroutineCrudRepository<TaskRecord, UUID> 18
  13. フェーズ2での課題② • Entityが2階層(ドメイン、永続化) @Table("TASKS") data class TaskRecord(val name) { @Id

    val id: UUID?, val name: String, } data class Task(val id: UUID?,val name) { xxx } ドメイン層 永続化(テーブル) class TaskQueryRepository interface TaskCommandRepository : CoroutineCrudRepository<TaskRecord, UUID> @Repository class TaskRepositoryImpl( private val taskCommandRepository: TaskCommandRepository, ) : TaskRepository • Repositoryが2階層(ドメイン、永続化) ドメイン層 永続化 19
  14. jOOQのJDBC版、R2DBC版の併用 • @Qualifier、@Beanを使って、DIするDSLContextをR2DBC、 JDBCで出し分け • jOOQで自動生成するファイルは共有可能 @Repository class TaskRepositoryImpl( @Qualifier(“R2DBC”)

    private val create: DSLContext ) @Configuration class JooqConfig { @Bean(name = ["R2DBC"]) fun r2dbcContext(cfi: ConnectionFactory): DSLContext { xxx } } 24
  15. ORMの方針(フェーズ3):実装例 • Entity data class Task(val id: UUID,val name) {

    xxx } @Repository class TaskRepositoryImpl( private val create: DSLContext, ) : TaskRepository { override fun save(task: Task): Task { XXX(jOOQでSQLを記述) } } • Repository ドメイン層 ドメイン層 jOOQの自動生成ファイル 永続化 25
  16. バックエンドエンジニア募集中 - 技術スタック - Kotlin - Spring WebFlux - jOOQ

    - 勤務環境 - フルリモート・フルフレックスOK! - 技術顧問 竹端 尚人さん (@n_takehata) への相談会勉強会 など学習の場がある - シリーズA後期のスタートアップ×金融事業でローリスク・ハイリターン の挑戦ができる - 気になる方はこちらからエントリー (【ジャストインケース 採用】で検索!) 29
  17. 3 0