FlyleでのDBとの堅牢な付き合い方と
パフォーマンス改善への取り組み
株式会社フライル: 吉澤直哉
自己紹介
・ふそやん azihsoyn@twitter
・釣り好き
・お酒とアニメが好き
・rehash.fmというポッドキャストをやってました (しばらく休止中のため過去形)
・フライルには2022年9月に入社
会社紹介
Flyleとは 詳細はこちら(https://flyle.io/jp)
3
1
2
多様な経路の
顧客フィードバックを集約
顧客データを活かした
製品開発の意思決定を支援
プロダクトマネジメントの
立ち上げをサポート
多様な経路の
顧客の声の集約・連携
NPS等のサーベイ
AIによる自動分類(開発中)
優先度づけ
ロードマップ
顧客が求める機能を分析
組織立ち上げサポート
ツールの使い方の
サポート
プロダクトマネジメント
研修の実施
複雑なプロダクトマネジメント業務を効率化する多様な機能を揃えています。直近ではNPSなどのサーベイ機能をリリース。今後は、AIによる自動分類・分析機能を大きく強化予定。
各職種募集中です!
https://herp.careers/v1/flyle
Flyleのバックエンド環境
・SpringBoot 2.7でHibernate 5
・RDS MySQL 8.0.29
Flyleのバックエンド環境
・SpringBoot 2.7でHibernate 5 (SpringBoot3出ましたね)
・RDS MySQL 8.0.29 (MySQL 8.0.32出ましたね)
堅牢にするために
MySQLのCHECK制約を使う
・IDフィールドの桁数チェック
・textカラムの空文字を除外してnullに統一
・使える文字の制限
など
kotlin関係ないですが...
チェック制約の例
チェック制約の挙動
堅牢にするために
ドメイン型
ドメイン型とは
こんなやつ
参考: https://www.postgresql.jp/document/12/html/domains.html
不正な値の混入を防げる
ドメイン型のバリデーション
initで変なデータが入らないようにチェックしてる
init時にバリデーションを実行
引数の取り違えを防げる😊
ドメイン型を使ったJPARepositoryのinterface
ドメイン型の課題
そのままではHibernateで使えない
解決策: カスタムコンバーターを書く
カスタムコンバーターの課題
ドメイン型が増える度にカスタムコンバーターを書く手間...
解決策: KSPで自動生成しよう!
KSPとは
KSP(Kotlin Symbol Processing)は、Kotlinコンパイラの拡張機能であり、Kotlinのコンパイル時に、コンパイルされたコードにアノテーションベースの処理を追加することができます。KSPを使用することで、Kotlinのコードジェネレーションを簡素化し、自動化することができます。KSPは、Dagger HiltやRoomなどのライブラリーでも使用されており、Kotlinプロジェクトの開発を効率化するための貴重なツールの1つです。
By ChatGPT
https://kotlinlang.org/docs/ksp-overview.html
KSPのイメージ
KSPによって自動生成されたコンバーターたち(の一部)
ドメイン型とカスタムコンバーターの課題
nativeQuery内では使えない...
nativeQueryとは
JPARepositoryの命名では表現しきれない複雑なSQLを直接書ける
解決策: nativeQuery内ではメソッドが使える!
Listも対応可能(ややトリッキー)
さらに堅牢にするために
nativeQuery内のtypoなどをチェックできるようにRepositoryのメソッドが実行可能かを全件テストしてる
堅牢にするために
Enum型
Enum型
Enumな値はテーブルで管理
Enum型
Enumな値はテーブルで管理
Enum型
Kotlinのコード
Enum型の課題
DBの値とKotlinのコードが乖離する
対策: 起動時にSELECTしてチェック
パフォーマンス問題
ある時
データを10000件CSVでエクスポートしたい
→ SELECTしたものを返すだけだから余裕余裕😆
→ API Timeout(15秒)
→ 😱
考えられる原因
・無駄にレコードを取得しているのでは?
・indexが効いてないのでは?
・トランザクションのロックかかってる?
・N+1になってないか?
・ドメイン型のinitのバリデーション(正規表現)が重い?
・そもそもHibernateが遅い?
考えられる原因
・無駄にレコードを取得しているのでは? → ❌
・indexが効いてないのでは?→ ❌
・トランザクションのロックかかってる?→ ❌
・N+1になってないか?→ ❌
・ドメイン型のinitのバリデーション(正規表現)が重い?→ ❌
・そもそもHibernateが遅い? →😇
全部違った
原因
独自の型をカスタムコンバーターで変換する場合、その型はSerializableである必要がある
By ChatGPT
修正(1行のみ)
10000件のSELECTに15秒以上かかっていたのが1秒ぐらいまで短縮🎉
まとめ
・MySQLのチェック制約を積極的に使う
・IDフィールドにドメイン型を使うことで堅牢なインターフェースに
・Enumはテーブルで管理
・KSPを使って自動でカスタムコンバーターを生成
・nativeQuery内では引数のメソッドを使える
・ドメイン型はSerializableに