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
72
ビジネスロジックを「型」で表現する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
PHPからGoへのマイグレーション for DMMアフィリエイト
yabakokobayashi
1
170
多領域インシデントマネジメントへの挑戦:ハードウェアとソフトウェアの融合が生む課題/Challenge to multidisciplinary incident management: Issues created by the fusion of hardware and software
bitkey
PRO
2
110
Amazon Kendra GenAI Index 登場でどう変わる? 評価から学ぶ最適なRAG構成
naoki_0531
0
110
2024年にチャレンジしたことを振り返るぞ
mitchan
0
140
プロダクト開発を加速させるためのQA文化の築き方 / How to build QA culture to accelerate product development
mii3king
1
260
ずっと昔に Star をつけたはずの思い出せない GitHub リポジトリを見つけたい!
rokuosan
0
150
PHP ユーザのための OpenTelemetry 入門 / phpcon2024-opentelemetry
shin1x1
1
220
ゼロから創る横断SREチーム 挑戦と進化の軌跡
rvirus0817
2
270
kargoの魅力について伝える
magisystem0408
0
210
Google Cloud で始める Cloud Run 〜AWSとの比較と実例デモで解説〜
risatube
PRO
0
100
Wvlet: A New Flow-Style Query Language For Functional Data Modeling and Interactive Data Analysis - Trino Summit 2024
xerial
1
120
Oracle Cloud Infrastructure:2024年12月度サービス・アップデート
oracle4engineer
PRO
0
180
Featured
See All Featured
Git: the NoSQL Database
bkeepers
PRO
427
64k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
28
2.1k
Making Projects Easy
brettharned
116
5.9k
Building a Modern Day E-commerce SEO Strategy
aleyda
38
7k
Fashionably flexible responsive web design (full day workshop)
malarkey
405
66k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
44
9.3k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
8
1.2k
Writing Fast Ruby
sferik
628
61k
[RailsConf 2023] Rails as a piece of cake
palkan
53
5k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
229
52k
Unsuck your backbone
ammeep
669
57k
For a Future-Friendly Web
brad_frost
175
9.4k
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