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
型だけでバグを減らそう! Kotlinの型パワーを使った実践タイプセーフエンジニ...
Search
YuitoSato
December 10, 2022
Technology
2
1.5k
型だけでバグを減らそう! Kotlinの型パワーを使った実践タイプセーフエンジニアリング
Kotlin Fest 2022の登壇内容のスライドです。
YuitoSato
December 10, 2022
Tweet
Share
More Decks by YuitoSato
See All by YuitoSato
Railway Oriented Programming を オニオンアーキテクチャに適用する by kotlin-result / Railway Oriented Programming in Onion Architecture by kotlin-result
yuitosato
3
560
リファクタリングへの耐性が高いモデルベースの統合テストの紹介 / Model-Base Integration Test for Refactoring
yuitosato
7
2.3k
Expressing Business Logic with Types: Functional DDD for OOP
yuitosato
1
79
ビジネスロジックを「型」で表現するOOPのための関数型DDD / Functional And Type-Safe DDD for OOP
yuitosato
41
26k
Java21とKotlinの代数的データ型 & パターンマッチの紹介と本当に嬉しい使い方 / Algebraic Data Type in Java and Kotlin: Happy Use of Pattern Match
yuitosato
14
4.4k
ログラスの継続的ライブラリアップデートのWhyとHow / Why and How to Update Libraries Continuously in Loglass
yuitosato
0
380
リプレイス「後」が大事!Reactフルリプレイスから2年で良かったこと・その後大事なこと / The Important Point After The Framework Replacement
yuitosato
3
980
B2B SaaSあるある! 一括処理のエラーハンドリングをKotlinで関数型的に処理する / Kotlin Functional Multi Error Handling
yuitosato
2
480
Kotlinサーバサイドで頑張る「単体テストの考え方_使い方」 / "Unit Testing Principles, Practices, and Patterns" by Kotlin
yuitosato
3
920
Other Decks in Technology
See All in Technology
生成AI × 旅行 LLMを活用した旅行プラン生成・チャットボット
kominet_ava
0
150
Fabric 移行時の躓きポイントと対応策
ohata_ds
1
150
完全自律型AIエージェントとAgentic Workflow〜ワークフロー構築という現実解
pharma_x_tech
0
320
AWSマルチアカウント統制環境のすゝめ / 20250115 Mitsutoshi Matsuo
shift_evolve
0
100
[IBM TechXchange Dojo]Watson Discoveryとwatsonx.aiでRAGを実現!事例のご紹介+座学②
siyuanzh09
0
110
デジタルアイデンティティ人材育成推進ワーキンググループ 翻訳サブワーキンググループ 活動報告 / 20250114-OIDF-J-EduWG-TranslationSWG
oidfj
0
390
CDKのコードレビューを楽にするパッケージcdk-mentorを作ってみた/cdk-mentor
tomoki10
0
190
Git scrapingで始める継続的なデータ追跡 / Git Scraping
ohbarye
5
450
KMP with Crashlytics
sansantech
PRO
0
230
技術に触れたり、顔を出そう
maruto
1
140
三菱電機で社内コミュニティを立ち上げた話
kurebayashi
1
350
embedパッケージを深掘りする / Deep Dive into embed Package in Go
task4233
1
200
Featured
See All Featured
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
3
350
Faster Mobile Websites
deanohume
305
30k
Optimising Largest Contentful Paint
csswizardry
33
3k
YesSQL, Process and Tooling at Scale
rocio
170
14k
Build The Right Thing And Hit Your Dates
maggiecrowley
33
2.5k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
49k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
38
1.9k
[RailsConf 2023] Rails as a piece of cake
palkan
53
5.1k
Practical Orchestrator
shlominoach
186
10k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
365
25k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
33
2.7k
Art, The Web, and Tiny UX
lynnandtonic
298
20k
Transcript
1 ©2022 Loglass Inc. 型だけでバグを減らそう! Kotlinの型パワーを使った実践タイプセーフ エンジニアリング 2022.12.10 佐藤有斗(Yuiiitoto) 株式会社ログラス
2 ©2022 Loglass Inc. 自己紹介 佐藤有斗(Yuiiitoto) ログラス エンジニア # React
# 組織・アジャイル # Kotlin
3 ©2022 Loglass Inc. ログラスについて(5秒) 企業価値を向上する 経営管理クラウド
4 ©2022 Loglass Inc. 目次 • なぜ型を使いこなすことでバグが減るのか? • 型によってバグが減らせるパターン 1.
標準の型をラップする 2. 認可処理などの特定の処理をパスしたことを型で示す 3. 型でデータの不整合をなくす • まとめ • 最後に: タイプセーフなポストモーテム
5 ©2022 Loglass Inc. 目次 • なぜ型を使いこなすことでバグが減るのか? • 型によってバグが減らせるパターン 1.
標準の型をラップする 2. 認可処理などの特定の処理をパスしたことを型で示す 3. 型でデータの不整合をなくす • まとめ • 最後に: タイプセーフなポストモーテム
6 ©2022 Loglass Inc. なぜ型を使いこなすことでバグが減るのか コンパイル時に実装ミスに気付けるから
7 ©2022 Loglass Inc. コンパイル時に実装ミスに気づくとは?
8 ©2022 Loglass Inc. ミドルネームにnullを渡す
9 ©2022 Loglass Inc. ぬるぽ、ガッ! Λ_Λ \\ ( ・∀・) | | ガッ と )
| | Y /ノ 人 / ) < >_Λ∩ _/し' //. V`Д´)/ (_フ彡 / ←>>1 NullPointerExceptionが起きる
10 ©2022 Loglass Inc. と思いきやKotlinはコンパイルで落ちる
11 ©2022 Loglass Inc. Kotlinではデフォルトで 引数や変数にnullを渡すことができない KotlinのNull Safety
12 ©2022 Loglass Inc. Kotlinではデフォルトで 引数や変数にnullを渡すことができない KotlinのNull Safety
13 ©2022 Loglass Inc. 実装ミスをコンパイル時に気づけると何がいいのか? • 実行時に気付くバグと比較して ... ◦ 全ての分岐を実行しなくてもよく
必ず実装ミスに気づくことができる ◦ テストカバレッジ100%は現実的ではない
14 ©2022 Loglass Inc. では、なぜKotlin? • Kotlinは型に関する機能が豊富 ◦ Generics ◦
型推論 ◦ Smart Cast ◦ 代数的データ型 ◦ 高階関数やラムダ ◦ Delegation などなど
15 ©2022 Loglass Inc. 要するに、、 Kotlinを駆使して、実装ミスをコンパイルで 気付けるようにしよう!!!
16 ©2022 Loglass Inc. 型によってバグが減らせるパターン • なぜ型を使いこなすことでバグが減るのか? • 型によってバグが減らせるパターン 1.
標準の型をラップする 2. 認可処理などの特定の処理をパスしたことを型で示す 3. 型でデータの不整合をなくす • まとめ • 最後に: タイプセーフなポストモーテム
17 ©2022 Loglass Inc. 標準の型をラップする • なぜ型を使いこなすことでバグが減るのか? • 型によってバグが減らせるパターン 1.
標準の型をラップする 2. 認可処理などの特定の処理をパスしたことを型で示す 3. 型でデータの不整合をなくす • まとめ • 最後に: タイプセーフなポストモーテム
18 ©2022 Loglass Inc. 標準の型をラップする • よくあるミス: 引数のIDを取り間違えてしまった
19 ©2022 Loglass Inc. 標準の型をラップする • よくあるミス: 引数のIDを取り間違えてしまった
20 ©2022 Loglass Inc. Stringをラップする
21 ©2022 Loglass Inc. TaskIdとUserIdを区別することでコンパイル時に実装ミスに気付ける
22 ©2022 Loglass Inc. TaskIdとUserIdを区別することでコンパイル時に実装ミスに気付ける
23 ©2022 Loglass Inc. ちなみに: ラップすることによるオーバーヘッドを避ける • Stringをクラスでラップするとヒープ領域のオーバーヘッドが増える • inline
classesという機能を使うことで String型として扱えてスタック領域だけの割り当てで済む
24 ©2022 Loglass Inc. ここで一つ疑問が 全てのIDに別々の型をつけるの面倒 ではないか?
25 ©2022 Loglass Inc. タイプセーフにしたいが、型の増加を抑制したい => Genericsを使おう! Genericsでさらに汎用的にする
26 ©2022 Loglass Inc. Genericsでさらに汎用的にする
27 ©2022 Loglass Inc. Genericsでさらに汎用的にする
28 ©2022 Loglass Inc. Genericsでさらに汎用的にする • 型を増やさずに、タスク IDとユーザーIDを区別できた!
29 ©2022 Loglass Inc. Genericsでさらに汎用的にする • 型を増やさずに、タスク IDとユーザーIDを区別できた!
30 ©2022 Loglass Inc. Genericsでさらに汎用的にする • 型を増やさずに、タスク IDとユーザーIDを区別できた!
31 ©2022 Loglass Inc. Genericsでさらに汎用的にする • 型を増やさずに、タスク IDとユーザーIDを区別できた!
32 ©2022 Loglass Inc. Genericsでさらに汎用的にする • 型を増やさずに、タスク IDとユーザーIDを区別できた!
33 ©2022 Loglass Inc. 標準の型をラップする : まとめ 標準の型をラップして取り間違いを防ぐ 型の増加をGenericsで抑制する
34 ©2022 Loglass Inc. 認可処理などの特定の処理をパスしたことを型で示す • なぜ型を使いこなすことでバグが減るのか? • 型によってバグが減らせるパターン 1.
標準の型をラップする 2. 認可処理などの特定の処理をパスしたことを型で示す 3. 型でデータの不整合をなくす • まとめ • 最後に: タイプセーフなポストモーテム
35 ©2022 Loglass Inc. 認可処理などの特定の処理をパスしたことを型で示す • よくあるミス: 認可されていないIDで参照をしてしまった
36 ©2022 Loglass Inc. 認可処理などの特定の処理をパスしたことを型で示す • よくあるミス: 認可されていないIDで参照をしてしまった
37 ©2022 Loglass Inc. 認可処理などの特定の処理をパスしたことを型で示す • よくあるミス: 認可されていないIDで参照をしてしまった
38 ©2022 Loglass Inc. 「認可された」ID型を導入する • 認可されたID型として AuthorizedTaskId を定義する
39 ©2022 Loglass Inc. 「認可された」ID型を導入する • TaskAuthChecker だけが返す特別な型とする
40 ©2022 Loglass Inc. 「認可された」ID型を導入する • TaskAuthChecker だけが返す特別な型とする
41 ©2022 Loglass Inc. 「認可された」ID型を導入する • findTaskByIdはAuthorizedTaskIdしか受け付けないように修正
42 ©2022 Loglass Inc. 「認可された」ID型を導入する • findTaskByIdはAuthorizedTaskIdしか受け付けないように修正
43 ©2022 Loglass Inc. 「認可された」ID型を導入する • 認可処理を通過していない IDはコンパイル時に落ちるようになる
44 ©2022 Loglass Inc. 「認可された」ID型を導入する • 認可処理を通過していない IDはコンパイル時に落ちるようになる
45 ©2022 Loglass Inc. 「認可された」ID型を導入する • 認可処理を通過していない IDはコンパイル時に落ちるようになる
46 ©2022 Loglass Inc. 「認可された」ID型を導入する • 認可処理を通過していない IDはコンパイル時に落ちるようになる
47 ©2022 Loglass Inc. しかし油断してはいけない • AuthorizedTaskIdのコンストラクタが公開されている! ここに public が潜んでいる
48 ©2022 Loglass Inc. しかし油断してはいけない • AuthorizedTaskIdのコンストラクタが公開されている!
49 ©2022 Loglass Inc. しかし油断してはいけない • 不正に認可されていない AuthorizedTaskIdが作成されてしまう
50 ©2022 Loglass Inc. しかし油断してはいけない • 不正に認可されていない AuthorizedTaskIdが作成されてしまう
51 ©2022 Loglass Inc. 不正にインスタンスを作成されないためには? data classを使ってコンストラクタの可視性を コントロールする
52 ©2022 Loglass Inc. コンストラクタの可視性を data classで制御する
53 ©2022 Loglass Inc. コンストラクタの可視性を data classで制御する • インスタンスを作成できない interface
AuthorizedTaskIdを定義する sealed を使えば同ファイルからしか継承できない
54 ©2022 Loglass Inc. コンストラクタの可視性を data classで制御する • コンストラクタ機能だけの data
classをprivateで定義する private classは同ファイルからしか参照できない
55 ©2022 Loglass Inc. コンストラクタの可視性を data classで制御する • TaskAuthCheckerからのみprivate data
classにアクセスする
56 ©2022 Loglass Inc. コンストラクタの可視性を data classで制御する • 別ファイルから AuthorizedTaskId
インスタンスが生成できなくなった!
57 ©2022 Loglass Inc. コンストラクタの可視性を data classで制御する • 別ファイルから AuthorizedTaskId
インスタンスが生成できなくなった!
58 ©2022 Loglass Inc. コンストラクタの可視性を data classで制御する • 別ファイルから AuthorizedTaskId
インスタンスが生成できなくなった!
59 ©2022 Loglass Inc. コンストラクタをprivateにするのではダメ? • この場合のprivateは同じクラス ファイル のみアクセス可能という意味なので NG
60 ©2022 Loglass Inc. 認可処理などの特定の処理をパスしたことを型で示す : まとめ 処理が通過したことを型で示す コンストラクタを非公開にして不正にインスタンスを作らせない
61 ©2022 Loglass Inc. 型でデータの不整合をなくす • なぜ型を使いこなすことでバグが減るのか? • 型によってバグが減らせるパターン 1.
標準の型をラップする 2. 認可処理などの特定の処理をパスしたことを型で示す 3. 型でデータの不整合をなくす • まとめ • 最後に: タイプセーフなポストモーテム
62 ©2022 Loglass Inc. 型でデータの不整合をなくす • よくあるミス: あり得ないデータを作成してしまった
63 ©2022 Loglass Inc. 型でデータの不整合をなくす • タスクには以下のステータスがある • 完了ステータスのときのみ完了時刻を持つ
64 ©2022 Loglass Inc. 型でデータの不整合をなくす • しかし間違えて着手時に完了時刻を入れてしまった • →着手中なのに完了時刻を持つという不整合データが誕生
65 ©2022 Loglass Inc. 型でデータの不整合をなくす • しかし間違えて着手時に完了時刻を入れてしまった • →着手中なのに完了時刻を持つという不整合データが誕生
66 ©2022 Loglass Inc. データ不整合をなくすには? sealed classを使って データの不整合が起こりえない型を定義する
67 ©2022 Loglass Inc. sealed class を導入する • 完了の時のみ完了時刻をもつというデータ構造を sealed
classで定義
68 ©2022 Loglass Inc. sealed class を導入する • sealed class
+ object, data classのパターンはEnumのように扱える
69 ©2022 Loglass Inc. sealed class を導入する • Enumだとこうなる •
objectはEnumとほぼ同じ扱いで、data classはEnum + 構造体というような振る舞い
70 ©2022 Loglass Inc. sealed class を導入する • Task型からnullableなcompletedAtプロパティが消える
71 ©2022 Loglass Inc. sealed class を導入する • 着手中時に完了時刻を渡せなくなった
72 ©2022 Loglass Inc. sealed class を導入する • 着手中時に完了時刻を渡せなくなった
73 ©2022 Loglass Inc. sealed class を導入する • 完了時には完了時刻の入力を強制できる
74 ©2022 Loglass Inc. sealed class を導入する • 完了時には完了時刻の入力を強制できる
75 ©2022 Loglass Inc. OSS: kotlin-resultの事例 • 成功値かエラー値かどちらかの値をとる Result型を提供するOSS kotlin-result
: https://github.com/michaelbull/kotlin-result
76 ©2022 Loglass Inc. OSS: kotlin-resultの事例 • 成功値かエラー値かどちらかの値をとる Result型を提供するOSS kotlin-result
: https://github.com/michaelbull/kotlin-result
77 ©2022 Loglass Inc. OSS: kotlin-resultの事例 • NGパターン: nullableな value
と errorを持っているわけではないことに注意
78 ©2022 Loglass Inc. 型でデータ不整合をなくす : まとめ sealed classを使って データの不整合が起こりえない型を定義する
79 ©2022 Loglass Inc. まとめ • なぜ型を使いこなすことでバグが減るのか? • 型によってバグが減らせるパターン 1.
標準の型をラップする 2. 認可処理などの特定の処理をパスしたことを型で示す 3. 型でデータの不整合をなくす • まとめ • 最後に: タイプセーフなポストモーテム
80 ©2022 Loglass Inc. まとめ • なぜ型を使いこなすことでバグが減るのか? ◦ →コンパイル時に実装ミスを検出できるから ◦
→Kotlinの型パワーを使ってコンパイル時により多くのミスを検出する
81 ©2022 Loglass Inc. まとめ • 型によってバグが減らせるパターン 1. 標準の型をラップする →
genericsで型の増加を抑制しよう 2. 認可処理などの特定の処理をパスしたことを型で示す → コンストラクタの可視性を data classを使ってコントロールしよう 3. 型でデータの不整合をなくす → sealed classでデータの不整合をなくそう
82 ©2022 Loglass Inc. 最後に: タイプセーフなポストモーテム • なぜ型を使いこなすことでバグが減るのか? • 型によってバグが減らせるパターン
1. 標準の型をラップする 2. 認可処理などの特定の処理をパスしたことを型で示す 3. 型でデータの不整合をなくす • まとめ • 最後に: タイプセーフなポストモーテム
83 ©2022 Loglass Inc. 最後に: タイプセーフなポストモーテム 情報漏洩が起きました!再発防止策は?
84 ©2022 Loglass Inc. 最後に: タイプセーフなポストモーテム - レビュワーを2人に増やす - 偉い人のチェックを増やす
- GitHubのPRテンプレにチェック項目を足 す - テスト工数を2倍にする etc…
85 ©2022 Loglass Inc. 最後に: タイプセーフなポストモーテム それ、型で解決できませんか?
86 ©2022 Loglass Inc. 最後に: タイプセーフなポストモーテム • 障害のたびにテスト工数を増やしたり、「儀式」を追加するとスピードが落ちる • 最優先で考えるべき再発防止策はコンパイル時に障害のタネを気付けるようにすること
• Kotlinはそのための機能をたくさん有している
87