Kotlinでサーバサイドを始めよう!

 Kotlinでサーバサイドを始めよう!

14c9795d267f5b85abb98ca5e8780646?s=128

Taro Nagasawa

May 22, 2019
Tweet

Transcript

  1. Kotlinで サーバサイド を始めよう! 2019-05-22 長澤太郎

  2. もくじ 1. Kotlinのすごいところ 2. KotlinでSpringアプリを始める 3. Kotlinでユニットテスト

  3. 事実上のKotlinエバンジェリスト 長澤 太郎

  4. 医療機関向けサービス AI問診 Ubie Kotlin三兄弟や 現役医師が在籍する 楽しい職場♪

  5. 1. Kotlinのすごいところ 2. KotlinでWebアプリを始める 3. Kotlinでユニットテスト

  6. 実践主義 の文法

  7. データクラス、プロパティ、コンストラクタ // Java public final class User { private final

    Long id; private final String name; public Person(Long id, String name) { this.id = id; this.name = name; } public Long getId() { return id; } public String getName() { return name; } @Override public boolean equals(final Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; final User user = (User) o; if (!id.equals(user.id)) return false; return name.equals(user.name); } @Override public int hashCode() { int result = id.hashCode(); result = 31 * result + name.hashCode(); return result; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + '}'; } public User withId(Long id) { return new User(id, name); } public User withName(String name) { return new User(id, name); } public static Builder { private Long id; private String name; public User build() { return new User(id, name); } public Builder id(Long id) { this.id = id; return this; } public Builder name(String name) { this.name = name; return this; } } } data class User( val id: Long, val name: String ) Java Kotlin
  8. Null安全 val a: Int = null // コンパイルエラー val b:

    Int? = null // OK b.toString() // コンパイルエラー s?.length if (s != null) s.length else null 同じ if-elseは式 (評価されて値になる) 厳しいけど、扱いやすい
  9. 拡張関数 fun String.hello() { println("Hello, ${this}!") } val name =

    "world" name.hello() // Hello, world!
  10. 守備範囲 の広さ

  11. Kotlinで作れるアプリ • CLIアプリケーション • デスクトップアプリケーション • Androidアプリ • iOSアプリ •

    ブラウザアプリ(AltJS) • Webアプリケーション
  12. マルチプラットフォーム・プロジェクト Common Platform (JVM) Platform (JS) Regular (JVM) Regular (JS)

    矢印は依存の方向 // Common module expect fun hello() // JVM module actual fun hello() { System.out.println("Hello!") } // JS module actual fun hello() { console.log("Hello!") }
  13. 仲間たち

  14. Kotlin財団 JetBrains × Google

  15. 日本Kotlinユーザグループ

  16. 1. Kotlinのすごいところ 2. KotlinでWebアプリを始める 3. Kotlinでユニットテスト

  17. Spring Bootプロジェクトの雛形作成 Webサイト または IntelliJ IDEA で 簡単にプロジェクト雛形を作 成可能

  18. アノテーションベースのいつものSpring @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() }
  19. KotlinDSLによるDIとルーティング設定も 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) } Bean 登録 routing 設定
  20. 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
  21. Kotlin向けWebアプリフレームワーク Ktor • https://ktor.io • JetBrainsにより開発 • いわゆるマイクロ・フレームワーク • Kotlin

    DSLによるルーティング設定 • ノンブロッキング、コルーチン対応 fun main(args: Array<String>) { embeddedServer(Netty, 8080) { routing { get("/") { call.respondText("Hello, world!", ContentType.Text.Html) } } }.start(wait = true) }
  22. 1. Kotlinのすごいところ 2. KotlinでWebアプリを始める 3. Kotlinでユニットテスト

  23. テスト関係のフレームワークやライブラリ • JUnit5 - Jupiter • Spring Test - WebTestClient

    • AssertJ • MockK • DbSetup-kotlin
  24. JUnit5 class FooTest { @Nested inner class fooMethod { @Test

    fun `should throw exception`() { assertThrows<MyException>() { Foo().foo() } } } }
  25. class FooTest { @Nested inner class fooMethod { @Test fun

    `should throw exception`() { assertThrows<MyException>() { Foo().foo() } } } } JUnit5 メソッドをグルーピングしてテストの見通しを良く
  26. JUnit5 class FooTest { @Nested inner class fooMethod { @Test

    fun `should throw exception`() { assertThrows<MyException>() { Foo().foo() } } } }
  27. AssertJ val got = sut.findUser(id) assertThat(got).isNotNull assertThat(got?.name).isEqualTo("ほげ")

  28. そもそもデータクラスで比較すべし val got = sut.findUser(id) val expected = User(id =

    1, name = "ほげ") assertThat(got).isEqualTo(expected)
  29. MockK interface UserService { fun createUser(id: Long): User suspend fun

    findUser(id: Long): User? } val userService = mockk<UserService>() every { userService.createUser(1) } returns user coEvery { userService.findUser(1) } returns user
  30. モック生成は一度、都度リセット class DesignControllerTest { private val repo: DesignRepository = mockk()

    private val client: DesignClient = mockk() private val controller: DesignController(repo, client) @BeforeEach fun init() { clearMocks(repo, client) } } 参考 https://www.youtube.com/watch?v=RX_g65J14H0
  31. WebTestClient - expectBody拡張関数 webTestClient.get() .exchange() .expectBody<MyApiBody>() .isEqualTo(expectedBody) import org.springframework.test.web.reactive.server.expectBody

  32. まとめ • Kotlin 書きやすく読みやすい! • カバーしている環境が多岐に渡る • 強力な後ろ盾があり、コミュニティもよさそう • Kotlinでも普通にSpringが使える

    • GraphQLも簡単にできそう • データクラスの内容をテストするときはデータクラスと比較する とレポートが読みやすい • モックライブラリはMockKがよさそう   サーバーサイドKotlin よい