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

UbieにおけるサーバサイドKotlin活用事例

 UbieにおけるサーバサイドKotlin活用事例

14c9795d267f5b85abb98ca5e8780646?s=128

Taro Nagasawa

February 18, 2021
Tweet

Transcript

  1. Ubieにおける サーバサイドKotlin 活用事例 2021-02-18 LINE Developer Meetup #70 長澤太郎

  2. 長澤 太郎 • @ngsw_taro • Ubie株式会社 • 日本Kotlinユーザグループ代表

  3. Ubie(ユビー)

  4. もくじ 1. なぜKotlinなのか 2. Spring Boot いいかんじ 3. Spring Boot

    あれこれ 4. GraphQL 少しだけ使ってる
  5. 1. なぜKotlinなのか 2. Spring Boot いいかんじ 3. Spring Boot あれこれ

    4. GraphQL 少しだけ使ってる
  6. Kotlinは元々 Better Java として産声を上げた! • 発表自体は2011年、実装のリリースは2012年 • 当時はJava 7でLambdaやStream APIがなかった

    • 特にAndroid利用で強みを見せた
  7. いまやJava 15, 16 • KotlinとJavaの文法における差が縮まってきた • それでもKotlinにしかないもの ◦ 名前付き引数 ◦

    拡張関数 ◦ suspend関数 ◦ プロパティ ◦ null安全 ◦ 型エイリアス (etc…) • Kotlinエコシステムも充実してきた
  8. UbieでサーバサイドKotlinを導入した経緯 • 2018年、太郎 Ubie入社、6人目の社員 • 当時 Web APIはRuby on Railsアプリ1個だけ

    • 新たな機能を追加するにあたってKotlinでWeb APIを開発 • 理由: ◦ 複雑な医療データを扱う上で静的型を欲した ◦ 僕自身、手の馴染む道具だった(Javaの利用経験もあった) • 大原則として、合理で判断。Kotlinにこだわりはない。
  9. 1. なぜKotlinなのか 2. Spring Boot いいかんじ 3. Spring Boot あれこれ

    4. GraphQL 少しだけ使ってる
  10. Spring Boot • Javaでも大人気のフレームワーク • 気軽にさくっと始められる Languageから Kotlinを選んで プロジェクトの雛形を ダウンロード

  11. KotlinでさくっとHelloWorld @SpringBootApplication class DemoApplication fun main(args: Array<String>) { runApplication<DemoApplication>(*args) }

    @Service class HelloWorldService { fun helloWorld(): String = "Hello, world!" } @RestController class HelloWorldController(val helloWorldService: HelloWorldService) { @GetMapping("/hello-world") fun helloWorld(): String = helloWorldService.helloWorld() }
  12. なんだかんだ言ってSpring Bootは楽 • アノテーションでDI • アノテーションでルーティング • YAMLファイルに設定値

  13. Kotlinってデフォルトでfinalクラスだよね • Kotlinのクラスはデフォルトでfinalクラス(継承ダメ) • open修飾子で継承を明示的に許可する • @Serviceなどが付いたクラスはSpringによってサブクラスが生 成される(継承を許可する必要がある) plugins {

    ... kotlin("plugin.spring") version "1.4.21" } プラグインがうまいことやってくれるから 意識する必要ないのです!
  14. WebFlux: Reactorごりごり使うスタイル @RestController class DemoController(val demoService: DemoService) { @GetMapping("demo") fun

    handle(): Mono<String> = Mono.zip( demoService.getMonoA(), demoService.getMonoB() ) .flatMap { demoService.getMonoC(it.t1, it.t2) } .map { it.answer } }
  15. WebFlux: async/awaitでやってMonoに変換 @RestController class DemoController(val demoService: DemoService) { @GetMapping("demo") fun

    handle(): Mono<String> = mono { val a = async { demoService.getItemA() } val b = async { demoService.getItemB() } val c = async { demoService.getItemC(a.await(), b.await()) } c.await().answer } }
  16. WebFlux: suspend関数で素直に @RestController class DemoController(val demoService: DemoService) { @GetMapping("demo") suspend

    fun handle(): String { val a = async { demoService.getItemA() } val b = async { demoService.getItemB() } val c = async { demoService.getItemC(a.await(), b.await()) } return c.await().answer } }
  17. Ktorはどう? • JetBrains公式のWebマイクロフレームワーク ◦ 非常に薄い ◦ DSL、ノンブロッキングなどの特徴 • だからこその苦労はありそう→考えることたくさん ◦

    DIどうする…? ◦ DBアクセスは…? ◦ コントローラとか、ファイル分割、アーキテクチャ ◦ やりたいことが明確に決まってるならSpring Bootでよさそう • UbieではPHR基盤プロジェクトでKtor採用を真面目に検討し ていた。が、断念。
  18. 1. なぜKotlinなのか 2. Spring Boot いいかんじ 3. Spring Boot あれこれ

    4. GraphQL 少しだけ使ってる
  19. バリデーションに注意 class PatientPostBody ( @NotNull val age: Int, @NotBlank val

    name: String ) class PatientPostBody ( @field:NotNull val age: Int, @field:NotBlank val name: String ) class PatientPostBody ( @field:NotNull val age: Int?, @field:NotBlank val name: String )
  20. Kotlin DSLでBean登録 @SpringBootApplication class DemoApplication fun main(args: Array<String>) { SpringApplicationBuilder()

    .sources(DemoApplication::class.java) .initializers(beans { bean { HelloWorldService() } }) .run(*args) } class HelloWorldService { fun helloWorld(): String = "Hello, world!" }
  21. ルーティングもDSLに! fun main(args: Array<String>) { SpringApplicationBuilder() .sources(DemoApplication::class.java) .initializers(beans { bean

    { HelloWorldService() } bean { HelloWorldController(ref()) } bean { router { GET("/hello-world") { ref<HelloWorldController>().helloWorld() } } } }) .run(*args)
  22. DBアクセスはJdbcTemplateで • 我々はSQLを知っている(学習コスト低でとっつきやすい) • 重厚なORMのAPIはおろか、癖や生成されるSQLを気にする 必要はない • やりたいことをスッとできる、痒いところに手が届く • 記述すべきコードは増えるけど脳みそ使わず筋肉使う

  23. Ubieのコーディングガイドライン公開中 https://github.com/ubie-inc/kotlin-coding-style

  24. Ubieコーディングガイドラインのポイント • スタイルはktlintに従う • シンプルに保つ ◦ Kotlinは表現力が高い分、エレガントの極みを目指すと可読性が下がって本末転 倒になるおそれが • テストコードは素直に

    ◦ テストに必要なものが、一目ですべて手に入る世界がいいな • 型を明記する • !!を使用しない ◦ 代わりにrequireNotNull関数を使用する • lateinitは使用しない ◦ 本来NullableなのにNotNullにしたいがための抜け道 ◦ テストコードの@Autowiredなプロパティにはlateinitを使用
  25. 1. なぜKotlinなのか 2. Spring Boot いいかんじ 3. Spring Boot あれこれ

    4. GraphQL 少しだけ使ってる
  26. Ubieのアーキテクチャ(一部) 患者用問診タ ブレット 医師用 デスクトップ

  27. Kotlin x Spring Boot x GraphQL type Query { drugs(yjCode:

    String!) : [Drug!] } type Drug { yjCode: String! name: String! } @Component class DrugQueryResolver( val drugService: DrugService ): GraphQLQueryResolver { fun drugs(yjCode: String): List<Drug> { return drugService.getDrugs(yjCode) } } しらじさんによるサンプルコード https://github.com/ubie-inc/kotlin-graphql-sample
  28. GraphQLやるときの登場人物 • QueryResolver: API、問い合わせの入口に相当 • Resolver: ネストで取得したいリソースを指定したとき • DataLoader: N

    + 1を回避するための遅延ロード機構 フレームワークが提供するインタフェースを実装し @Componentなりを付ける
  29. 1. なぜKotlinなのか 2. Spring Boot いいかんじ 3. Spring Boot あれこれ

    4. GraphQL 少しだけ使ってる
  30. まとめ • KotlinはBetter Javaとして有用 • SpringとKotlinは仲良し!多くの場面で自然に使える • Ktorは薄いがゆえに大変そうか?個人的な見解 • GraphQLもKotlin

    x SpringでOK サーバサイドKotlin いいよ!