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.4k
型だけでバグを減らそう! 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
480
リファクタリングへの耐性が高いモデルベースの統合テストの紹介 / Model-Base Integration Test for Refactoring
yuitosato
6
2.1k
Expressing Business Logic with Types: Functional DDD for OOP
yuitosato
1
71
ビジネスロジックを「型」で表現するOOPのための関数型DDD / Functional And Type-Safe DDD for OOP
yuitosato
41
25k
Java21とKotlinの代数的データ型 & パターンマッチの紹介と本当に嬉しい使い方 / Algebraic Data Type in Java and Kotlin: Happy Use of Pattern Match
yuitosato
14
4.3k
ログラスの継続的ライブラリアップデートのWhyとHow / Why and How to Update Libraries Continuously in Loglass
yuitosato
0
340
リプレイス「後」が大事!Reactフルリプレイスから2年で良かったこと・その後大事なこと / The Important Point After The Framework Replacement
yuitosato
3
960
B2B SaaSあるある! 一括処理のエラーハンドリングをKotlinで関数型的に処理する / Kotlin Functional Multi Error Handling
yuitosato
2
450
Kotlinサーバサイドで頑張る「単体テストの考え方_使い方」 / "Unit Testing Principles, Practices, and Patterns" by Kotlin
yuitosato
3
900
Other Decks in Technology
See All in Technology
LINEヤフーのフロントエンド組織・体制の紹介【24年12月】
lycorp_recruit_jp
0
530
OpenAIの蒸留機能(Model Distillation)を使用して運用中のLLMのコストを削減する取り組み
pharma_x_tech
4
540
GitHub Copilot のテクニック集/GitHub Copilot Techniques
rayuron
23
11k
ずっと昔に Star をつけたはずの思い出せない GitHub リポジトリを見つけたい!
rokuosan
0
150
サーバレスアプリ開発者向けアップデートをキャッチアップしてきた #AWSreInvent #regrowth_fuk
drumnistnakano
0
190
TSKaigi 2024 の登壇から広がったコミュニティ活動について
tsukuha
0
160
Wvlet: A New Flow-Style Query Language For Functional Data Modeling and Interactive Data Analysis - Trino Summit 2024
xerial
1
110
5分でわかるDuckDB
chanyou0311
10
3.2k
コンテナセキュリティのためのLandlock入門
nullpo_head
2
320
マイクロサービスにおける容易なトランザクション管理に向けて
scalar
0
110
How to be an AWS Community Builder | 君もAWS Community Builderになろう!〜2024 冬 CB募集直前対策編?!〜
coosuke
PRO
2
2.8k
レンジャーシステムズ | 会社紹介(採用ピッチ)
rssytems
0
150
Featured
See All Featured
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
Visualization
eitanlees
146
15k
Agile that works and the tools we love
rasmusluckow
328
21k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.3k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
10
810
Large-scale JavaScript Application Architecture
addyosmani
510
110k
Unsuck your backbone
ammeep
669
57k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
132
33k
Building Flexible Design Systems
yeseniaperezcruz
327
38k
BBQ
matthewcrist
85
9.4k
Making the Leap to Tech Lead
cromwellryan
133
9k
Practical Orchestrator
shlominoach
186
10k
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