Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
「2024年版 Kotlin サーバーサイドプログラミング実践開発」の補講 〜O/Rマッパー編〜
Search
Takehata Naoto
July 18, 2024
Programming
2
460
「2024年版 Kotlin サーバーサイドプログラミング実践開発」の補講 〜O/Rマッパー編〜
2024年7月18日(土) 「Server-side Kotlin Night 2024/07」の発表資料です。
Takehata Naoto
July 18, 2024
Tweet
Share
More Decks by Takehata Naoto
See All by Takehata Naoto
2024年版 Kotlin サーバーサイドプログラミング実践開発
n_takehata
4
3.5k
Server-Side目線で見る、Kotlin Festの楽しみ方
n_takehata
0
330
KotlinとCloud Vision APIで領収書の電子帳簿保存法対応をする
n_takehata
1
210
KotlinConf 2023 現地参加レポート
n_takehata
1
300
サーバーサイドKotlinクイズ
n_takehata
0
160
サーバーサイドでのKotlin Coroutines
n_takehata
0
1.1k
KotlessとDynamoDBで自分のツイートを収集するサーバーレスアプリケーションを作る
n_takehata
0
370
書籍『Kotlin サーバーサイドプログラミング実践開発』のこだわりとおすすめポイント
n_takehata
0
500
Server-Side Kotlinで必要なJavaの知識
n_takehata
1
470
Other Decks in Programming
See All in Programming
「今のプロジェクトいろいろ大変なんですよ、app/services とかもあって……」/After Kaigi on Rails 2024 LT Night
junk0612
5
2.2k
TypeScript Graph でコードレビューの心理的障壁を乗り越える
ysk8hori
2
1.1k
Contemporary Test Cases
maaretp
0
140
エンジニアとして関わる要件と仕様(公開用)
murabayashi
0
290
as(型アサーション)を書く前にできること
marokanatani
10
2.7k
とにかくAWS GameDay!AWSは世界の共通言語! / Anyway, AWS GameDay! AWS is the world's lingua franca!
seike460
PRO
1
880
Nurturing OpenJDK distribution: Eclipse Temurin Success History and plan
ivargrimstad
0
940
AI時代におけるSRE、 あるいはエンジニアの生存戦略
pyama86
6
1.2k
LLM生成文章の精度評価自動化とプロンプトチューニングの効率化について
layerx
PRO
2
190
Snowflake x dbtで作るセキュアでアジャイルなデータ基盤
tsoshiro
2
520
シェーダーで魅せるMapLibreの動的ラスタータイル
satoshi7190
1
480
よくできたテンプレート言語として TypeScript + JSX を利用する試み / Using TypeScript + JSX outside of Web Frontend #TSKaigiKansai
izumin5210
6
1.7k
Featured
See All Featured
Six Lessons from altMBA
skipperchong
27
3.5k
Adopting Sorbet at Scale
ufuk
73
9.1k
Automating Front-end Workflow
addyosmani
1366
200k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
44
2.2k
What's new in Ruby 2.0
geeforr
343
31k
GitHub's CSS Performance
jonrohan
1030
460k
KATA
mclloyd
29
14k
Scaling GitHub
holman
458
140k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
6
410
Optimising Largest Contentful Paint
csswizardry
33
2.9k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
356
29k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
364
24k
Transcript
「2024年版 Kotlin サーバーサイドプログラミング 実践開発」の補講 〜O/Rマッパー編〜 2024年7月18日 Server-side Kotlin Night 2024/07
竹端 尚人
自己紹介
竹端 尚人 主にバックエンドエンジニア Twitter: @n_takehata • 2006.04〜 公務員 • 2007.12〜
SES • 2011.04〜 モバイルゲーム開発(サーバーサイド Kotlinを始める) • 2020.12〜 フリーランス(バックエンド開発、 テックリード、技術顧問など) 概要 現在は主に、クラウド型電子カルテを開発している株式 会社ヘンリーでエンジニアとして従事 Kotlin愛好会というコミュニティの運営もやっています
Kotlin愛好会も明日やります!
• CEDEC 2018、2019登壇 • Software Design 2019年2月号〜4月号で短期連載 「サーバーサイド開発の品質を向上させる Java→Kotlin移行のススメ」執筆 •
2021年4月 書籍「Kotlin サーバーサイドプログラ ミング実践開発」出版 • 2023年4月 Techpitにて「Kotlin入門ガイドー言語 思想から特徴・歴史・使いどころまで、まるっと予 備知識がわかる教科書」執筆 • Kotlin Fest 2024登壇 登壇、執筆
2024年版 Kotlin サーバーサイドプログラミング実践開発
Kotlin Fest 2024で話した内容から、 盛り上がったO/Rマッパーについて深堀って話します
Kotlin Fest 2024の発表資料はこちら https://speakerdeck.com/n_takehata/kotlin-s erver-side-programming-practice-2024
アジェンダ 1. Kotlin Fest 2024の振り返り 2. 各種O/Rマッパーのおさらい 3. 色々なSQLを実装してみる 4.
まとめ
アジェンダ 1. Kotlin Fest 2024の振り返り 2. 各種O/Rマッパーのおさらい 3. 色々なSQLを実装してみる 4.
まとめ
1. Kotlin Fest 2024の振り返り
「2024年版 Kotlin サーバーサイドプログラミング 実践開発」 の内容
• 「Kotlin サーバーサイドプログラミング実践開発」の 内容紹介 • 現在のサーバーサイドKotlinで使えるフレームワークの 紹介(Web、DI、O/Rマッパー、テスト) • 今Kotlinでアプリケーションを作る場合のフレームワー ク選定の紹介
「2024年版 Kotlin サーバーサイドプログラミング 実践開発」 の内容
• Ktor(Webアプリケーションフレームワーク) • Koin(DIフレームワーク) • JOOQ(O/Rマッパー) • Kotest(テストフレームワーク)
RepositoryImpl O/Rマッパー (JOOQ) ドメイン オブジェクト Repository Test (Kotest) Service Controller
(Ktor) DI(Koin)
Ask the Speaker、懇親会で O/Rマッパーの話で盛り上がった
• セッションでも「O/Rマッパーが一番迷った」と話して いた • 「O/Rマッパーだけは何使おうか迷うんですよね」とい う悩みが多かった • SQLに近い形で書ける方がいいという意見に「やっぱ りそうですよね」というリアクション O/Rマッパーの話で盛り上がった
結局エンジニアはSQLを書きたい(人が多い)
なぜエンジニアはSQLを書きたいのか?
• 結局「こういうSQLを書きたいからコードは・・・」 という順序で考えている • テーブル設計を意識してデータを扱うのに、SQLだけ 抽象化しても混乱する • テーブルもSQLも意識せず「こういうデータが欲し い」を考えるだけにできないと抽象化の意味がない なぜエンジニアはSQLを書きたいのか?
結局エンジニアはSQLを書きたい(人が多い) 書きたいわけではないけど、いい具合に抽象化された ソリューションがない?
今回は各種O/Rマッパーで色々なSQLの 実装方法を紹介します
参考: Kotlin Fest 2024登壇の振り返り(ブログ) https://blog.takehata-engineer.com/entry/loo k-back-at-kotlin-fest-2024
アジェンダ 1. Kotlin Fest 2024の振り返り 2. 各種O/Rマッパーのおさらい 3. 色々なSQLを実装してみる 4.
まとめ
2. 各種O/Rマッパーのおさらい
• Exposed • JOOQ • Ktorm Kotlin Fest 2024で紹介したO/Rマッパー
Exposed
• JetBrains社が開発しているKotlin製のO/Rマッパー • SQLライクに実装できるDSL、軽量なDAOという2つの アクセス方法が用意されている • 長い間0.x系が続いていたが、2024年中に1.0になるこ とが予定されている Exposedとは?
JOOQ
• SQLに近いDSLでのクエリ作成が可能 • テーブルスキーマからのコード生成が可能で、もとも とJavaのO/RマッパーだがKotlinのコード生成にも対応 している • R2DBCによるノンブロッキングI/Oにも対応 JOOQとは?
Ktorm
• 純粋なJDBCに基づいたKotlin用の軽量なO/Rマッパー • Kotlin製のサードパーティフレームワーク • 生のSQLに近い形で書ける柔軟なDSLが用意されている Ktormとは?
Kotlin Fest 2024では紹介しなかった その他のO/Rマッパー
• MyBatis • Doma2 • Komapper その他のO/Rマッパー
アジェンダ 1. Kotlin Fest 2024の振り返り 2. 各種O/Rマッパーのおさらい 3. 色々なSQLを実装してみる 4.
まとめ
3. 色々なSQLを実装してみる
• Exposed • JOOQ • Ktorm ※ExposedはSQL DSLを使用します この3つのO/Rマッパーで色々なクエリを書いて 比較していきます
使用するテーブル(RDBはMySQLを使用) CREATE TABLE users ( id varchar(10) NOT NULL, name
varchar(50) NOT NULL, age int NOT NULL, PRIMARY KEY (id) ); CREATE TABLE user_purchase_histories ( id varchar(10) NOT NULL, user_id varchar(10) NOT NULL, purchase_date date NOT NULL, price int NOT NULL, PRIMARY KEY (id) );
基本的なCRUDのクエリ (Kotlin Festからの再掲)
transaction { // Insert Users.insert { it[id] = "kotlin" it[name]
= "Kotlin Fest" it[age] = 3 } // Update Users.update({ Users.id eq "kotlin" }) { it[age] = 4 } // Select val users = Users.select(Users.name, Users.age).where { Users.age greaterEq 3 } // Delete Users.deleteWhere{ id eq "kotlin" } } Exposed
// Insert dslContext.insertInto(USERS) .columns(USERS.ID, USERS.NAME, USERS.AGE) .values("kotlin", "Kotlin Fest", 3)
.execute() // Update dslContext.update(USERS) .set(USERS.AGE, 4) .where(USERS.ID.eq("kotlin")) .execute() // Select val users = dslContext.selectFrom(USERS).where(USERS.AGE.ge(3)).fetch() // Delete dslContext.deleteFrom(USERS) .where(USERS.ID.eq("kotlin")) .execute() JOOQ
// Insert database.insert(Users) { set(it.id, "kotlin") set(it.name, "Kotlin Fest" )
set(it.age, 3) } // Update database.update(Users) { set(it.age, 4) where { it.id eq "kotlin" } } // Select val users = database.from(Users).select().where { Users.age greaterEq 3 } // Delete database.delete(Users) { it.id eq "kotlin" } Ktorm
• Exposedはfromやupdate文のsetなど、キーワードを 削って抽象化している • JOOQはほぼ生のSQLと同じ構文で書ける • Ktormも生のSQLに近いが、fromの位置やinsertで使 うsetキーワードなど、少し差分がある
GROUP BY、ORDER BY、LIMIT、OFFSET
select age, count(*) from USERS group by age order by
count(*) desc limit 3 offset 1;
Users.select(Users.age, Users.id.count()) .groupBy(Users.age) .orderBy(Users.id.count(), SortOrder.DESC) .limit(3, offset = 1) Exposed
dslContext.select(USERS.AGE, count()) .from(USERS) .groupBy(USERS.AGE) .orderBy(count().desc()) .limit(1, 3) .fetch() JOOQ
dslContext.select(USERS.AGE, count()) .from(USERS) .groupBy(USERS.AGE) .orderBy(count().desc()) .limit(3) .offset(1) .fetch() offsetを別で渡すことも可能
database.from(Users) .select(Users.age, count()) .groupBy(Users.age) .orderBy(count().desc()) .limit(1, 3) Ktorm
database.from(Users) .select(Users.age, count()) .groupBy(Users.age) .orderBy(count().desc()) .limit(3) .offset(1) off offsetを別で渡すことも可能
• 3つとも書き方に大きな差分はない • ExposedがFromがない分短いくらい
JOIN
select * from USERS left join USER_PURCHASE_HISTORIES on USERS.id =
USER_PURCHASE_HISTORIES.user_id;
Users.leftJoin( UserPurchaseHistories , { Users.id }, { UserPurchaseHistories.userId } ).selectAll()
Exposed
dslContext.select() .from(USERS) .leftJoin(USER_PURCHASE_HISTORIES) .on(USERS.ID.eq(USER_PURCHASE_HISTORIES.USER_ID)) .fetch() JOOQ
database .from(Users) .leftJoin( UserPurchaseHistories , on = Users.id eq UserPurchaseHistories.userId)
.select() Ktorm
• Exposedはonのキーワードを使わず、少し抽象化して いる • JOOQとKtormは近いが、JOOQの方がonをチェーンし て書いてる分、より生のSQLに近い印象
サブクエリ
select * from USERS where exists( select * from USER_PURCHASE_HISTORIES
where USERS.id = USER_PURCHASE_HISTORIES.user_id );
Users.select(Users.columns) .where { exists( UserPurchaseHistories .select(UserPurchaseHistories.id).where{ Users.id eq UserPurchaseHistories.userId }
) } Exposed
dslContext.selectFrom(USERS) .whereExists( dslContext.selectOne() .from(USER_PURCHASE_HISTORIES) .where(USER_PURCHASE_HISTORIES.USER_ID.eq(USERS.ID)) ) .fetch() JOOQ
database .from(Users) .select() .where { exists( database.from(UserPurchaseHistories) .select(UserPurchaseHistories.id) .where {
UserPurchaseHistories.userId eq Users.id } ) } Ktorm
• JOOQだけwhereExists、selectOneなどの関数があり 少し抽象化されている • ExposedとKtormはwhere→exists→selectの階層に なっており、生のSQLに近い
JOINして絞り込む
select USERS.id, USERS.name, sum(USER_PURCHASE_HISTORIES.price) from USERS left join USER_PURCHASE_HISTORIES on
USERS.id = USER_PURCHASE_HISTORIES.user_id where USERS.age >= 20 group by USERS.id having sum(USER_PURCHASE_HISTORIES.price) >= 3000;
Users.leftJoin(UserPurchaseHistories , { Users.id }, { UserPurchaseHistories .userId }) .select(Users.id,
Users.name, UserPurchaseHistories .price.sum()) .where { Users.age greaterEq 20 } .groupBy(Users.id) .having { UserPurchaseHistories .price.sum() greaterEq 3000 } Exposed
dslContext.select(USERS.ID, USERS.NAME, DSL.sum(USER_PURCHASE_HISTORIES.PRICE)) .from(USERS) .leftJoin(USER_PURCHASE_HISTORIES) .on(USERS.ID.eq(USER_PURCHASE_HISTORIES.USER_ID)) .where(USERS.AGE.ge(20)) .groupBy(USERS.ID) .having(DSL.sum(USER_PURCHASE_HISTORIES.PRICE). ge(BigDecimal(3000)))
.fetch() JOOQ
database .from(Users) .leftJoin(UserPurchaseHistories, on = Users.id eq UserPurchaseHistories .userId) .select(Users.id,
Users.name, sum(UserPurchaseHistories.price)) .where { Users.age greaterEq 20 } .groupBy(Users.id, Users.name) .having { sum(UserPurchaseHistories.price) greaterEq 3000 } Ktorm
• 少し複雑で長いSQLになった分、構文で抽象化してい るExposedの短さがより際立っている • JOOQは生のSQLに近い構文な上、”DSL.”のように書か なければいけないキーワードが多いので長い
アジェンダ 1. Kotlin Fest 2024の振り返り 2. 各種O/Rマッパーのおさらい 3. 色々なSQLを実装してみる 4.
まとめ
4. まとめ
• 書きたいわけではないが、書く以外でいいソリュー ションがない • SQLだけ抽象化された状態では微妙 • 結果SQLっぽく書けるO/Rマッパーが好まれやすい エンジニアはSQLを書きたい?
• ExposedはFROMを省略したりJOINの書き方が簡略化 されたりと、少し短く書けるようになっている • JOOQは一番SQLに近い構文で書ける印象 • KtormもSQLに近いが、句の順序やJOINの書き方など 一部差分がある 各種O/Rマッパーの特性
Have a nice Server-side Kotlin!