Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Server-side Kotlinを使うスタートアップでどんなDetektルールが育ったか / Detekt rules made in start-up working with Server-side Kotlin

Kengo TODA
December 10, 2022

Server-side Kotlinを使うスタートアップでどんなDetektルールが育ったか / Detekt rules made in start-up working with Server-side Kotlin

Kotlin Fest 2022で使用した発表資料です。

https://fortee.jp/kotlin-fest-2022/proposal/1f737120-934f-48ac-b6f3-66da69d433d4

Kengo TODA

December 10, 2022
Tweet

More Decks by Kengo TODA

Other Decks in Programming

Transcript

  1. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest トーク概要
 株式会社ヘンリーではサーバサイドをKotlin(gRPC, Ktor,

    Koin etc.) で書いています。サービスの品質を高めるため、また拡大期にある チームへのボーディングを簡単にするため、Detekt拡張を実装して 利用しています。
 
 このセッションではどのような課題を解決するためにDetektを利用し たか、その結果どのようにコーディング体験が改善されたかをご紹 介します。
 
 https://fortee.jp/kotlin-fest-2022/proposal/1f737120-934f-48ac-b 6f3-66da69d433d4
 2
  2. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest 自己紹介
 Kengo TODA

    ( @kengo_toda)
 株式会社ヘンリー SRE
 
 最近の活動
 • @actions/setup-java に依存キャッシュ機能を入れた
 • 〃にGradle Version Catalog対応を入れた
 • detektのgood first issueにあった機能を実装した
 • Terraform周りではtfmigrate & tfactionのGCP対応
 3
  3. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest 拡大期のスタートアップとは
 プロダクトの方向性が見えてき て、アクセルを踏む時期。


    仮説検証の速度だけではなく、価 値を顧客に届けるスループットも 同時に高める必要がある。
 完全新規の開発に加え、機能拡 張や機能改善の比率も高い。
 6 "調達した資金は、中小病院向けクラウド型電子カルテ・レセコ ンシステムの開発および営業・サポート体制の強化に充当し、 事業拡大に合わせた採用・組織体制の強化を図ってまいりま す。" "年内で組織を2倍に拡大"
 https://prtimes.jp/main/html/rd/p/000000001.000102549.html 

  4. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest エンジニアから見た
 拡大期のスタートアップとは
 採用拡大によるオンボーディング

    負荷の増大。
 少数に共有された暗黙知では回 らなくなる=ドメイン知識やチーム への慣れがなくても参入しやすい プロジェクトが必要。
 ”ちょっと汚いけど簡単な変更”の 誘惑。コードがとっ散らかったり負 債が増えたりしがち。
 7
  5. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest 静的解析ツールで解決できる課題
 オンボーディング負荷の低減
 •

    「そうも書けますよね、でも今はこの書き方で行こうと思ってます」を 人間がフィードバックしないで済む
 
 機械的に発見可能な負債の抑制
 • 人が気づいていない潜在的課題や「なんとかなるだろ!👿」に対し て機械的に「ダメですよ😇」と言ってくれる
 ”第二のコンパイラ”
 8
  6. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest Kotlinが提供するrequire, requireNotNull, check,

    checkNotNullは便利 だが、エラーメッセージがわかりにくい。
 例えばrequireが投げるIllegalArgumentExceptionのメッセージは “Failed requirement” だけで、起こった問題を理解するための情報を 提供しない。
 わかりにくいエラーメッセージの撲滅
 10
  7. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest 本番環境でこのメッセージが確認された場合に、以下のような情報を 得られずにコードを読む必要が生じてしまう。
 •

    この例外はユーザにどのような影響があるのか
 • この例外はどの機能に関連しているのか
 • この例外について詳しいのはどのチームか
 
 最悪の場合、障害対応の初動が遅れる理由になりかねない。
 わかりにくいエラーメッセージの撲滅
 11
  8. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest わかりにくいエラーメッセージの撲滅
 detekt拡張によって、require, requireNotNull,

    check, checkNotNullを説 明なしに使うことを抑制する。障害に対する初動を早め、MTTRの短縮 に貢献する。
 requireNotNull(records[item.inspectionCode]) // エラー:assertionを行う場合、Sentryに表示される // ことを念頭にメッセージを設定してください。 requireNotNull(records[item.inspectionCode]) { "検査番号 (${item.inspectionCode}) に対応する院外検査が見つかりません" } // OK 12
  9. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest 日付とタイムゾーン
 誕生日などを表現するときに java.time.LocalDate(年・月・日の

    情報を持つクラス)を利用すること がある。
 これを時刻すなわち java.time.Instantに変換する場 合、どのタイムゾーンを使うかが 重要になる。
 
 15
  10. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest 日付とタイムゾーン
 例えば localDate.atStartOfDay()

    は実行環境のデフォルト タイムゾーンを使う。
 実行環境依存の実装は予期しない挙動の原因となるため、コードの 可搬性を保つためにも、デフォルトタイムゾーンに依存しない事が必 要になる。
 
 ※Java18でデフォルトのCharsetが「UTF-8」になるまでは、文字コード に対しても同様の配慮が必要だった。
 16
  11. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest 「今日」を表すLocalDateの生成
 LocalDate.now() //

    NG, デフォルトタイムゾーンに依存 LocalDate.now(jstZoneId) // OKだが書き方統一のため避ける Instant.now().toJstLocalDate() // OK, Instantに拡張関数を追加して共通化 17
  12. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest LocalDateからInstantへの変換
 localDate.atStartOfDay().toInstant() //

    NG, デフォルトタイムゾーンに依存 localDate.atStartOfDay(jstZoneId).toInstant() // OKだが書き方統一のため避ける localDate.toJstStartOfDayInstant() // OK, Instantに拡張関数を追加して共通化 18
  13. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest java.time.Clockの利用を推進
 Instant.now() //

    NG, 単体テスト実行時に不便 clock.instant() // OK, コンストラクタを通じて得たClockを利用 // kotestを使うならkotest-extensions-clockが便利 19
  14. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest Repositoryのメソッドの命名を統一
 repository.get(...) repository.list(...)

    repository.load(...) // NG, find or findByXxx に統一 repository.find(...) repository.findByDoctor(...) // OK 20
  15. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest IDの扱い
 ID系クラスを自動生成し、扱いに統一的なルールを設ける。 class

    UserRecord(id: EntityID<UUID>) : UUIDEntity(id) { companion object : UUIDEntityClass<UserRecord>(Users) // ExposedのRecordでPKを参照するには.entityIdを使う val entityId = UserId.of(id.value) // FKを参照するときは拡張関数を使う val doctorId by Sessions.doctorUuid .transformToEntityId(UserId.Doctor::of) 21
  16. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest 積み上げた「ひと工夫」を伝えるルール 23 知っていてほしいことをREADMEにまとめたり新人向け資料に盛り込

    んだりすることも大切ですが、コンピュータの力を借りてオンボーディ ングをスケーラブルにすることもできる。 コードの質が底上げされ、エラーメッセージやログが改善されれば、運 用も次第にやりやすくなる。チーム拡大はもちろん、SRE観点からも 価値ある施策だと言える!
  17. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest Detektの実行速度
 コンパイルやテスト実行に比べれば、Detektの実行時間は小さい。現 時点ではビルドのボトルネックになってはいない。


    
 とはいえコードや適用ルールが増えてくればこの限りではないので、 他のタスクと並列実行できるような工夫(後述)も必要になるかもしれ ない。
 25
  18. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest フォーマットをDetektに管理させるか?
 Detektにはktlintベースのルールが提供されている:
 https://detekt.dev/docs/rules/formatting/


    
 一方で、フォーマットはktlint, ktfmtといった自動フォーマッタに任せて Detektを利用しないという手もある。採用した自動フォーマッタとの噛 み合わせが悪い場合や、GitHub Actionsにフォーマット適用させたい 場合などは、Detektを利用しないほうが良いかも。
 26
  19. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest Detekt以外の解決方法
 主に依存関係の課題であれば、Detektや自動フォーマッタ以外にも解 決に使える手段がいくつかある。

    • Gradleプロジェクトをマルチプロジェクト構成にすることで不要な依 存を見えなくする
 
 • ArchUnitでパッケージ間依存に制限をかける
 27
  20. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest マルチプロジェクト構成の利点
 28 例えばexposedがinfrastructure

    プロジェクトの実装上の依存であ りAPIとして露出していない場合、 infrastructureを利用する applicationからはexposedが見 えない。 domainプロジェクトがktorや exposed、 openapiなどのライブ ラリを見ることもなくなる。
  21. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest マルチプロジェクト構成の利点
 29 Gradleはプロジェクトごとにタスク

    を実行する。つまりプロジェクトの 数だけタスクを並列実行する可能 性が出てくる。 マルチプロジェクト構成にすること でCPUコアを効率的に使いビルド 時間を短縮できる可能性がある。 Kotest実行 ドキュメント作成 Kotlinコンパイル
  22. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest マルチプロジェクト構成の利点
 30 また若干変則的だが、Detektを

    実行するGradleタスクを(比較的 暇な)ルートプロジェクトに置くこと で、並列性を高められる場合があ る。 Kotest実行 ドキュメント作成 Kotlinコンパイル root Detekt実行
  23. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest Detekt extensionをPackagesで配布
 自前実装したExtensionを配布する方法としてPackagesを利用した。こ

    のとき各プロジェクトにPackagesから依存をダウンロードするための設 定を書くと複雑になるのを避けるため、Wantedly社の事例を参考に Gradle Pluginを実装して設定を簡素化した。
 https://github.com/bw-company/henry-maven-repository
 
 31
  24. Copyrights(c) Henry, Inc. All rights reserved. #kotlinfest We are Hiring

    !
 
 • 医療DX
 • 難しい課題の解決
 • 社会貢献
 
 これらのキーワードが気になる方、
 ぜひ一度カジュアルにお話ししましょう!
 
 採用サイト
 https://jobs.henry-app.jp/
 
 33