Slide 1

Slide 1 text

2024年版 Kotlin サーバーサイドプログラミング 実践開発 2024年6月22日 Kotlin Fest 2024 竹端 尚人

Slide 2

Slide 2 text

自己紹介

Slide 3

Slide 3 text

竹端 尚人 主にバックエンドエンジニア Twitter: @n_takehata ● 2006.04〜 公務員 ● 2007.12〜 SES ● 2011.04〜 モバイルゲーム開発(サーバーサイド Kotlinを始める) ● 2020.12〜 フリーランス(バックエンド開発、 テックリード、技術顧問など) 概要 現在は主に、クラウド型電子カルテを開発している株式 会社ヘンリーでエンジニアとして従事 Kotlin愛好会というコミュニティの運営もやっています

Slide 4

Slide 4 text

● CEDEC 2018、2019登壇 ● Software Design 2019年2月号〜4月号で短期連載 「サーバーサイド開発の品質を向上させる Java→Kotlin移行のススメ」執筆 ● 2021年4月 書籍「Kotlin サーバーサイドプログラ ミング実践開発」出版 ● 2023年4月 Techpitにて「Kotlin入門ガイドー言語 思想から特徴・歴史・使いどころまで、まるっと予 備知識がわかる教科書」執筆 ● Kotlin Fest 2024登壇 ←New 登壇、執筆

Slide 5

Slide 5 text

アジェンダ 1. 旧Kotlinサーバーサイドプログラミング実践開発 2. 最近のサーバーサイドKotlinで使えるフレームワーク 3. 新Kotlinサーバーサイドプログラミング実践開発 4. まとめ

Slide 6

Slide 6 text

サーバーサイドKotlinで使えるフレームワークの紹介と、 現在ならどういう構成にするかの一案を紹介します

Slide 7

Slide 7 text

1. 旧Kotlinサーバーサイド プログラミング実践開発

Slide 8

Slide 8 text

書籍の概要

Slide 9

Slide 9 text

● Kotlinの基礎構文についての学習 ● サーバーサイドで使用するフレームワークの学習 (Spring Boot、MyBatis) ● 実践的なサーバーサイドアプリケーション(書籍管理シ ステム)の実装 ● Kotlin製のフレームワークの学習(Ktor、Exposedなど) 書籍の概要

Slide 10

Slide 10 text

Kotlin基礎 ↓ サーバーサイドKotlin基礎 ↓ サーバーサイドKotlin実践(アプリケーション作成) ↓ Extra StageとしてKotlin製フレームワークを知る

Slide 11

Slide 11 text

書籍内のアプリケーションの全体像

Slide 12

Slide 12 text

● Spring Boot(Webアプリケーションフレームワーク、 DIフレームワーク) ● MyBatis(O/Rマッパー) ● JUnit(テストフレームワーク) ● オニオンアーキテクチャ(アーキテクチャ) 書籍内のアプリケーションで使用しているフレームワー ク、アーキテクチャ

Slide 13

Slide 13 text

Javaのフレームワークを使用し まずはサーバーサイドKotlin自体の開発に慣れる

Slide 14

Slide 14 text

RepositoryImpl O/Rマッパー (MyBatis) ドメイン オブジェクト Repository Test (JUnit) Service Controller (Spring Boot) DI(Spring Boot)

Slide 15

Slide 15 text

各種フレームワークを現在の考えで 置き換えていきます

Slide 16

Slide 16 text

2. 最近のサーバーサイドKotlin で使えるフレームワーク

Slide 17

Slide 17 text

● Webアプリケーションフレームワーク ● DIフレームワーク ● O/Rマッパー ● テストフレームワーク

Slide 18

Slide 18 text

● Webアプリケーションフレームワーク ● DIフレームワーク ● O/Rマッパー ● テストフレームワーク

Slide 19

Slide 19 text

Kotlinで使える Webアプリケーションフレームワーク

Slide 20

Slide 20 text

● Ktor ● Micronaut ● gRPC-Kotlin Webアプリケーションフレームワーク

Slide 21

Slide 21 text

Ktor

Slide 22

Slide 22 text

● JetBrains社が開発しているKotlin製の軽量なWebアプ リケーションフレームワーク ● プラグインの機能により、柔軟な機能追加ができ拡張 性が高い ● 非同期I/Oをサポートしている 現時点の最終リリース: 2024年5月 Ktorとは?

Slide 23

Slide 23 text

ルーティング fun Application.configureRouting() { routing { get("/users") { call.respond( User(1, "kotlin", "[email protected]") ) } } }

Slide 24

Slide 24 text

プラグインのインストール fun main() { embeddedServer(Netty, port = 8080, host = "0.0.0.0") { install(CORS) install(Authentication) }.start(wait = true) }

Slide 25

Slide 25 text

Micronaut

Slide 26

Slide 26 text

● マイクロサービスとサーバーレスアプリケーションの ために設計されたJavaフレームワーク ● 高速でメモリ消費の少ない起動を実現している ● Ktorの構文での記述もサポートされている 現時点の最終リリース: 2024年6月 Micronautとは?

Slide 27

Slide 27 text

ルーティング @Controller("/hello") class HelloController { @Get @Produces(MediaType.TEXT_PLAIN) fun index() = "Hello World" }

Slide 28

Slide 28 text

gRPC-Kotlin

Slide 29

Slide 29 text

● gRPCをKotlinで実装するためのフレームワーク ● Protocol BuffersからKotlinのコードを生成し、使うこ とが可能 ※ Webアプリケーションフレームワークという分類とは少 し違うが、Webのインターフェースの一種として紹介 現時点の最終リリース: 2023年12月 gRPC-Kotlinとは?

Slide 30

Slide 30 text

RPCの実装 class HelloWorldService : GreeterGrpcKt.GreeterCoroutineImplBase() { override suspend fun sayHello(request: HelloRequest) { helloReply { message = "Hello ${request.name}" } } }

Slide 31

Slide 31 text

おすすめ

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

● 軽量で柔軟性の高い設計になっており、アプリケー ションの起動速度も速い ● JetBrains社製かつKotlin製で、Coroutinesを使用した 非同期I/Oにも対応しており、Kotlinの特性を活かした 実装もしやすい ● REST APIなど、通常のWebアプリケーション・サー バーであればベターな選択肢 Ktor

Slide 34

Slide 34 text

● マイクロサービスの1つとして使用する場合は、 gRPC-Kotlinを使用したい(gRPCをマイクロサービスを 実装することは定番) ● gRPCを使わない場合は、Micronautも選択肢に上がる その他のフレームワークについて

Slide 35

Slide 35 text

● Webアプリケーションフレームワーク ● DIフレームワーク ● O/Rマッパー ● テストフレームワーク

Slide 36

Slide 36 text

Kotlinで使える DIフレームワーク

Slide 37

Slide 37 text

● Koin ● Dagger2 ● Kodein DIアプリケーションフレームワーク

Slide 38

Slide 38 text

Koin

Slide 39

Slide 39 text

● サーバーサイド、Android、KMPと様々なプラット フォームで使用可能なKotlin製のDIフレームワーク ● シンプルなDSLにより設定が容易 ● KSPを使用してアノテーションの解決が行われる 現時点の最終リリース: 2024年4月 Koinとは?

Slide 40

Slide 40 text

モジュールの登録 @Module @ComponentScan("org.koin.kotlinfest") class Module fun main() { startKoin { modules(Module().module) } // ・・・ }

Slide 41

Slide 41 text

@Single class UserRepositoryImpl : UserRepository { override fun findUser(id: Int): User { // ・・・ } } DI対象の定義

Slide 42

Slide 42 text

コンストラクタでDI @Single class UserService(private val userRepository: UserRepository) { fun getUser(id: Int) : User = userRepository.findUser(id) }

Slide 43

Slide 43 text

class UserApplication : KoinComponent { val userService: UserService by inject() // ・・・ } フィールドでDI

Slide 44

Slide 44 text

Dagger2

Slide 45

Slide 45 text

● Googleが提供するJavaのDIフレームワーク ● もともとSquareが開発していたDagger(1.x)をGoogle がforkして開発している ● コンパイル時に全ての解析を行い依存性の解決をする ため、実行時のオーバーヘッドが少ない 現時点の最終リリース: 2024年3月 Dagger2とは?

Slide 46

Slide 46 text

@Module class RepositoryModule { @Provides fun provideUserRepository(userRepository: UserRepositoryImpl): UserRepository { return userRepository } } モジュールの定義

Slide 47

Slide 47 text

@Component(modules = [RepositoryModule::class]) interface ServiceComponent { fun getUserService(): UserService } コンポーネントの登録

Slide 48

Slide 48 text

class UserService @Inject constructor(private val userRepository: UserRepository) { fun getUser(id: Int): User = userRepository.findUser(id) } コンストラクタでDI

Slide 49

Slide 49 text

class Main { @Inject lateinit var userService: UserService // ・・・ } フィールドでDI

Slide 50

Slide 50 text

Kodein

Slide 51

Slide 51 text

● Kotlin製の軽量なDIフレームワーク ● アノテーションは使わず、シンプルで読みやすいDSLを 提供している ● インラインを多用し、高速で最適化されている 現時点の最終リリース: 2024年5月 Kodeinとは?

Slide 52

Slide 52 text

val appModule = DI.Module("appModule") { bind() with singleton { UserRepositoryImpl() } } モジュールの定義

Slide 53

Slide 53 text

class UserService(private val userRepository: UserRepository) { fun getUser(id: Int): User = userRepository.findUser(id) } コンストラクタでDI

Slide 54

Slide 54 text

fun main() { val di = DI { import(appModule) } val userService: UserService by di.instance() // ・・・ } フィールドでDI

Slide 55

Slide 55 text

おすすめ

Slide 56

Slide 56 text

No content

Slide 57

Slide 57 text

● 設定がシンプルで容易になっており、比較的導入しや すい ● SpringでのDIに慣れている人にも、読みやすい記述 ● @ComponentScanを使った一括でのDI対象の設定も可 能(KSPによりコンパイル時にscanを解決してくれる) Koin

Slide 58

Slide 58 text

● Dagger2、Kodeinともに@ComponentScanのような一括 でDI対象を登録する機能がなく、DI対象を都度全て記述す る必要がある ● Dagger2は設定がやや複雑で、学習コストが高い。コンパ イル時に依存関係を全て解決するため、実行速度は速く安 全だが、コンパイル速度が遅くなる可能性がある その他のフレームワークについて

Slide 59

Slide 59 text

● Webアプリケーションフレームワーク ● DIフレームワーク ● O/Rマッパー ● テストフレームワーク

Slide 60

Slide 60 text

Kotlinで使える O/Rマッパー

Slide 61

Slide 61 text

● Exposed ● JOOQ ● Ktorm O/Rマッパー

Slide 62

Slide 62 text

Exposed

Slide 63

Slide 63 text

● JetBrains社が開発しているKotlin製のO/Rマッパー ● SQLライクに実装できるDSL、軽量なDAOという2つの アクセス方法が用意されている ● 長い間0.x系が続いていたが、2024年中に1.0になるこ とが予定されている 現時点の最終リリース: 2024年6月 Exposedとは?

Slide 64

Slide 64 text

// 全カラム指定して定義 object Users : Table() { val id: Column = varchar("id", 10) val name: Column = varchar("name", length = 50) val age = integer("age") override val primaryKey = PrimaryKey(id) } // 数値のIDを自動作成 object Users : IntIdTable() { val name = varchar("name", 50).index() val age = integer("age") } // UUIDを自動作成 object Users : UUIDTable() { val name = varchar("name", 50).index() val age = integer("age") } テーブルの定義

Slide 65

Slide 65 text

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" } } DSLのコード

Slide 66

Slide 66 text

transaction { // Insert User.new { name = "Kotlin Fest" age = 3 } // Update user.age = 4 // Select val user = User.find { Users.name eq "Kotlin Fest" }.first() // Delete user.delete() } DAOのコード

Slide 67

Slide 67 text

JOOQ

Slide 68

Slide 68 text

● SQLに近いDSLでのクエリ作成が可能 ● テーブルスキーマからのコード生成が可能で、もとも とJavaのO/RマッパーだがKotlinのコード生成にも対応 している ● R2DBCによるノンブロッキングI/Oにも対応 現時点の最終リリース: 2024年6月 JOOQとは?

Slide 69

Slide 69 text

// 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() クエリ生成のDSLのコード

Slide 70

Slide 70 text

Ktorm

Slide 71

Slide 71 text

● 純粋なJDBCに基づいたKotlin用の軽量なO/Rマッパー ● Kotlin製のサードパーティフレームワーク ● 生のSQLに近い形で書ける柔軟なDSLが用意されている 現時点の最終リリース: 2024年5月 Ktormとは?

Slide 72

Slide 72 text

object Users : Table("USERS") { val id = varchar("id").primaryKey() val name = varchar("name") val age = int("age") } テーブルの定義

Slide 73

Slide 73 text

// 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" } クエリ生成のDSLのコード

Slide 74

Slide 74 text

val user = database.sequenceOf(Users).find { it.id eq "kotlin" } if (user != null) { user.age = 4 user.flushChanges() } DAOのような実装にすることも可能

Slide 75

Slide 75 text

おすすめ

Slide 76

Slide 76 text

No content

Slide 77

Slide 77 text

● テーブルスキーマからのコード生成に対応している ● シンプルなDSLで扱いやすく、フレームワークとしても 成熟している ● ノンブロッキングI/Oに対応することもできる JOOQ

Slide 78

Slide 78 text

● ExposedはJetBrains社製で、最近改善も重ねられてお り、今後有力な選択肢になる可能性がある ● Ktormもシンプルで扱いやすいが、JDBCベースでノン ブロッキングI/Oには対応していない ● Exposed、Ktormともにテーブルスキーマからのコード 生成は対応していない その他のフレームワークについて

Slide 79

Slide 79 text

● Webアプリケーションフレームワーク ● DIフレームワーク ● O/Rマッパー ● テストフレームワーク

Slide 80

Slide 80 text

Kotlinで使える テストフレームワーク

Slide 81

Slide 81 text

● Kotest ● Spek テストフレームワーク

Slide 82

Slide 82 text

Kotest

Slide 83

Slide 83 text

● Kotlin製のテストフレームワークで、RunnerはJUnitを 使用している ● 様々な記述方法が定義されており、目的や好みにあっ た書き方をすることが可能 ● データ駆動テスト等、様々な強力な機能を備えている 現時点の最終リリース: 2024年6月 Kotestとは?

Slide 84

Slide 84 text

class NumberTestByStringSpec : StringSpec({ "isRange:: when value in range then return true" { val number = Number(5) number.isRange(1, 10) shouldBe true } }) StringSpec

Slide 85

Slide 85 text

class NumberTestByDescribeSpec : DescribeSpec({ describe("isOdd test") { context("num is odd number" ) { val number = Number(1) it("return true") { number.isOdd() shouldBe true } } context("num is even number" ) { val number = Number(2) it("return false") { number.isOdd() shouldBe false } } } }) DescribeSpec

Slide 86

Slide 86 text

class NumberTestByStringSpec : StringSpec({ "isRange:: when value in range then return true(using forAll)" { forAll( row(1), row(10) ) { value -> val number = Number(value) number.isRange(1, 10) shouldBe true } } }) データ駆動テスト

Slide 87

Slide 87 text

Spek

Slide 88

Slide 88 text

● BDD形式での書き方が可能なテストフレームワーク ● Spek 2.xでは、マルチプラットフォームも念頭に置い て書き換えられている ● specificationとgherkinという2つのDSLが用意されて いる 現時点の最終リリース: 2022年8月 Spekとは?

Slide 89

Slide 89 text

object NumberTest : Spek({ describe("isOdd test") { context("num is odd number" ) { val number = Number(1) it("return true") { assertTrue(number.isOdd()) } } context("num is even number" ) { val number = Number(2) it("return false") { assertFalse(number.isOdd()) } } } }) テストコード

Slide 90

Slide 90 text

おすすめ

Slide 91

Slide 91 text

No content

Slide 92

Slide 92 text

● JUnitをRunnerとして安定した実行環境がある上で、 用途や好みに応じた記述方法を選択できる ● データ駆動テストやプロパティテスティング等、様々 な便利な機能を備えている ● アップデートも安定的に行われている Kotest

Slide 93

Slide 93 text

● Spekは2022年8月でアップデートが止まっているた め、現状選択しづらい ● Kotest、JUnit以外でKotlinで使えるテストフレーム ワークとして、有力なものは見当たらない状況 その他のフレームワークについて

Slide 94

Slide 94 text

3. 新Kotlinサーバーサイド プログラミング実践開発

Slide 95

Slide 95 text

サーバーサイドプログラミング実践開発で 作ったアプリケーションを、今ならどういった構成で 作るか?

Slide 96

Slide 96 text

選択したフレームワークはこちら

Slide 97

Slide 97 text

● Ktor(Webアプリケーションフレームワーク) ● Koin(DIフレームワーク) ● JOOQ(O/Rマッパー) ● Kotest(テストフレームワーク)

Slide 98

Slide 98 text

それぞれのフレームワークの選定理由

Slide 99

Slide 99 text

Ktor

Slide 100

Slide 100 text

● 軽量で柔軟性の高い設計になっており、アプリケー ションの起動速度も速い ● Kotlin製で、Coroutinesを使用した非同期I/Oにも対応 しており、Kotlinの特性を活かした実装もしやすい ● JetBrains社製で、Kotlinのアップデートへの追随も安 定している Ktorの選定理由

Slide 101

Slide 101 text

● 比較的新しいフレームワークのため、エコシステムや サードパーティのプラグインなどは発展途上 ● Springのようなフルスタックフレームワークではない ため、用途に応じて他のフレームワークとの組み合わ せも必要(Spring等に慣れてる人向けの注意点) Ktorの注意点

Slide 102

Slide 102 text

Koin

Slide 103

Slide 103 text

● 設定がシンプルなDSLで容易になっており、学習コスト も低い ● マルチプラットフォームに対応し、サーバーサイド以 外との技術スタックの共有が可能 ● @ComponentScanを使った一括でのDI対象の設定も可 能 Koinの選定理由

Slide 104

Slide 104 text

● 依存関係をランタイムで解決するため、パフォーマン スに影響が出る可能性がある ● 依存関係の追加漏れなどがあっても、コンパイル時に エラーを見つけられないため、実行時のクラッシュに つながる Koinの注意点

Slide 105

Slide 105 text

JOOQ

Slide 106

Slide 106 text

● シンプルなDSLで扱いやすく、フレームワークとしても 成熟している ● R2DBCでのノンブロッキングI/Oにも対応している ● テーブルスキーマからのKotlinのコード生成が可能 JOOQの選定理由

Slide 107

Slide 107 text

● 生のSQLに近い形のDSLになるため、難しいクエリを書 く際には記述が複雑になる可能性がある ● 併せて実装にはSQLの知識が必要 JOOQの注意点

Slide 108

Slide 108 text

Kotest

Slide 109

Slide 109 text

● 様々な記述方法が定義されており、目的や好みにあっ た書き方をすることが可能 ● データ駆動テストやプロパティテスティング等、様々 な便利な機能を備えている ● JUnitをRunnerとしていて安定した実行環境がある Kotestの選定理由

Slide 110

Slide 110 text

● 様々な記述方法が用意されているので、プロジェクト によって一定の方針決めは必要 ● 各Spec(記述方法)ごとに挙動が違う部分があるので、 複数のSpecを使用する場合は注意が必要(ネストした際 の挙動など) Kotestの注意点

Slide 111

Slide 111 text

RepositoryImpl O/Rマッパー (MyBatis) ドメイン オブジェクト Repository Test (JUnit) Service Controller (Spring Boot) DI(Spring Boot)

Slide 112

Slide 112 text

RepositoryImpl O/Rマッパー (JOOQ) ドメイン オブジェクト Repository Test (Kotest) Service Controller (Ktor) DI(Koin)

Slide 113

Slide 113 text

KtorとKoinを組み合わせて使う場合

Slide 114

Slide 114 text

implementation("io.insert-koin:koin-ktor:3.5.6") koin-ktorを使うことで、Ktorと組み合わせて実装しやすくなる

Slide 115

Slide 115 text

Moduleの定義 val databaseModule = module { single { UserRepositoryImpl(get()) } }

Slide 116

Slide 116 text

Moduleのインストール fun main() { embeddedServer(Netty, port = 8080) { install(Koin) { modules(databaseModule) } }.start(wait = true) }

Slide 117

Slide 117 text

Ktorと組み合わせることを想定したフレームワークも 増えていく可能性あり

Slide 118

Slide 118 text

4. まとめ

Slide 119

Slide 119 text

技術スタックの現状

Slide 120

Slide 120 text

● Kotlin製のフレームワークで実用的なものもあり、メン テナンスも活発にされている ● SpringやJOOQのように、Javaで定番のフレームワー クもKotlin対応がされているものもある ● 有力なフレームワークにJetBrains社製のものも含まれ ており、今後の発展にも期待が持てる

Slide 121

Slide 121 text

サーバーサイドKotlinの現状と今後

Slide 122

Slide 122 text

● サーバーサイドの選択肢として、Kotlinが一番人気とい う状況ではない ● しかし、やはり言語としての利便性やクオリティは高 く、エコシステムも拡充してきている ● サーバーサイド以外の分野も含め、言語としての発展 が期待できる技術であることは間違いない

Slide 123

Slide 123 text

サーバーサイドKotlinやっていきましょう!

Slide 124

Slide 124 text

ご清聴ありがとうございました