1 of 78

既存アプリケーションで�Kotlinを導入してみた

JJUG CCC 2018 Fall 2018/12/15

フリュー株式会社 佐藤慧太(@SatohJohn)

#jjug_ccc #ccc_c5

スライドのURLです!

2 of 78

自己紹介

  • 佐藤慧太(@SatohJohn)
  • フリュー株式会社 ( 京都 )
  • Kotlinの民
  • SpringとVue.jsが好きです

3 of 78

対象のアプリケーション

4 of 78

ピクトリンク

  • プリ画取得サービス
    • プリ画を使ったSNS機能
    • ランキング、クチコミ
    • コスメなどのプレゼント

5 of 78

ピクトリンク

  • 若年女性がターゲット
  • 会員数:1300万人
  • 世間がイベントのときに負荷が�あがる

6 of 78

ピクトリンク

  • 2011年にSPサイトをリリース
  • Android、iOSアプリもリリース

7 of 78

JJUG CCCとピクトリンク

8 of 78

JJUG CCCとピクトリンク

つまりJavaがメインの開発

9 of 78

目的

  • JavaユーザがKotlinを使って書いてみた�知見の共有
  • 会社紹介

10 of 78

今回話すこと

  • JavaユーザがServer Side Kotlinを使って
    • 良かった点
    • 気をつけるべき点

11 of 78

今回話すこと

  • JavaユーザがServer Side Kotlinを使って
    • 良かった点
    • 気をつけるべき点
  • あくまで個人の感想です

12 of 78

今回話さないこと

  • Kotlinの詳しい記法、Kotlinらしい記述
    • Coroutineなど
    • Kotlin JS、 Kotlin Nativeについて

13 of 78

そもそもKotlinって何よ

  • ロシアの領土でフィンランド湾に浮かぶコトリン島が�名前の由来
    • GoogleMapGoogleEarth

14 of 78

そもそもKotlinって何よ

  • JetBrains(IntelliJ IDEAを作っている)が�作成している言語
  • GroovyやScalaなどの糖衣構文などを取り入れている

15 of 78

なぜServer Side Kotlin

  • Kotlinって「Android界隈で」メジャーだよね?
  • Scalaでいいんじゃない?

16 of 78

なぜServer Side Kotlin

  • Java(既存ライブラリ)との相性が非常に良い
  • Spring Frameworkでの公式サポート
  • Kotlin Conf 2018 ではまぁまぁの注目度

17 of 78

Kotlin使って良かった点

18 of 78

使って良かった点

  • 標準で利用できる便利な記法が多い
  • ツールによるサポートが手厚い
  • いろんな場所でkotlinがかける
  • Javaと併用して使える

19 of 78

使って良かった点

  • 標準で利用できる便利な記法が多い
  • ツールによるサポートが手厚い
  • いろんな場所でkotlinがかける
  • Javaと併用して使える

20 of 78

標準で利用できる便利な記法が多い

  • 冗長に感じていたコードの量が減る
    • 短くかける ≠ わかりやすい
    • 新しい記法はチームで利用するにも浸透に�時間がかかるので、徐々に使っていく

21 of 78

標準で利用できる便利な記法が多い

  • 分割宣言
  • スコープ関数
  • Data Class
  • 拡張関数
  • Smart Cast

22 of 78

標準で利用できる便利な記法が多い

  • 分割宣言
  • スコープ関数
  • Data Class
  • 拡張関数
  • Smart Cast

23 of 78

分割宣言

  • 返り値を分割して受け取ることができる
    • 一時的なclassをわざわざ作らなくてもよく�返り値を扱いやすい
    • 使わないやつは _ で無視できる

24 of 78

private StringData getStringData() {

var str = "string";

return new StringData(str, str.length());

}

private class StringData {

private String str;

private int length;

public StringData(String str, int length) {

this.str = str;

this.length = length;

}

}

public void test() {

StringData stringData = getStringData();

System.out.println(String.format("%s, %s", stringData.str, stringData.length));

}

Kotlin

Java

25 of 78

private StringData getStringData() {

var str = "string";

return new StringData(str, str.length());

}

private class StringData {

private String str;

private int length;

public StringData(String str, int length) {

this.str = str;

this.length = length;

}

}

public void test() {

StringData stringData = getStringData();

System.out.println(String.format("%s, %s", stringData.str, stringData.length));

}

Kotlin

Java

内部クラスを作成する必要がある

返り値のクラスのプロパティから取得する

26 of 78

fun getStringData(): Pair<String, Int> {

val str = "string"

return Pair(str, str.length)

}

fun main(args: Array<String>) {

val (str, length) = getStringData()

println("${str}, ${length}")

}

Kotlin

Java

27 of 78

fun getStringData(): Pair<String, Int> {

val str = "string"

return Pair(str, str.length)

}

fun main(args: Array<String>) {

val (str, length) = getStringData()

println("${str}, ${length}")

}

Kotlin

Java

受け取る際に展開されるのでそのまま利用できる

28 of 78

分割宣言 - 注意点

  • Publicなメソッドで利用するのは�やめよう
    • 順番が決まっているので間違えやすい
    • GitHubでのレビューでは分かりにくい

29 of 78

標準で利用できる便利な記法が多い

  • 分割宣言
  • スコープ関数
  • Data Class
  • 拡張関数
  • Smart Cast

30 of 78

スコープ関数

  • 特定の変数に対しての処理を�後続してかける
    • スコープを短く文脈を持って書くことができる
    • 詳しくは Kotlin スコープ関数 用途まとめ を参照

31 of 78

public static void main(String[] args) {

var param = "parameter";

System.out.println(param);

TestObject result = create(param.toUpperCase());

}

private class TestObject {

private final String param;

public TestObject(String param) {

this.param = param;

}

}

private TestObject create(String param) {

return new TestObject(param);

}

Kotlin

Java

32 of 78

public static void main(String[] args) {

var param = "parameter";

System.out.println(param);

TestObject result = create(param.toUpperCase());

}

private class TestObject {

private final String param;

public TestObject(String param) {

this.param = param;

}

}

private TestObject create(String param) {

return new TestObject(param);

}

Kotlin

Java

一時変数をおいて処理を

実行していく必要がある

33 of 78

fun main(args: Array<String>) {

val result: TestObject = "parameter".also { param ->

println(param)

}.let { param ->

create(param.toUpperCase())

}

}

private class TestObject(val param: String)

private fun create(param: String) = TestObject(param)

Kotlin

Java

34 of 78

fun main(args: Array<String>) {

val result: TestObject = "parameter".also { param ->

println(param)

}.let { param ->

create(param.toUpperCase())

}

}

private class TestObject(val param: String)

private fun create(param: String) = TestObject(param)

Kotlin

Java

paramという形で短い

スコープで実装できる

35 of 78

fun main(args: Array<String>) {

val result: TestObject = "parameter"

.also { println(it) }

.let { create(it.toUpperCase()) }

}

private class TestObject(val param: String)

private fun create(param: String) = TestObject(param)

Kotlin

Java

引数を取らずにitとする�こともできる

36 of 78

スコープ関数 - 注意点

  • 種類が多いので決めてしまっても良いかも
  • itやthisを考えずに使わない
    • このit or thisは一体何にならないようにする

37 of 78

標準で利用できる便利な記法が多い

  • 分割宣言
  • スコープ関数
  • Data Class
  • 拡張関数
  • Smart Cast

38 of 78

Data Class

  • cloneやtoStringなどをclassに�追加してくれる
    • 言語的に取り入れられているので�Lombokなどのライブラリに頼らなくて良い

39 of 78

import lombok.AllArgsConstructor;

import lombok.Data;

@AllArgsConstructor

@Data

public class User {

private String uid;

private String name;

private String mailAddress;

}

data class User(

var uid: String,

var name: String,

var mailAddress: String

)

Kotlin

Java

40 of 78

import lombok.AllArgsConstructor;

import lombok.EqualsAndHashCode;

import lombok.Getter;

import lombok.ToString;

@AllArgsConstructor

@Getter

@ToString

@EqualsAndHashCode

public class User {

private String uid;

private String name;

private String mailAddress;

}

data class User(

val uid: String,

val name: String,

val mailAddress: String

)

Kotlin

Java

41 of 78

import lombok.AllArgsConstructor;

import lombok.EqualsAndHashCode;

import lombok.Getter;

import lombok.ToString;

@AllArgsConstructor

@Getter

@ToString

@EqualsAndHashCode

public class User {

private String uid;

private String name;

private String mailAddress;

}

data class User(

val uid: String,

val name: String,

val mailAddress: String

)

Kotlin

Java

varは再代入可能なので

valにするだけ

42 of 78

Data Class - 注意点

  • 無いですね
    • 分割宣言ができるclassにはなるが、�使わないようにする

43 of 78

標準で利用できる便利な記法が多い

  • 分割宣言
  • スコープ関数
  • Data Class
  • 拡張関数
  • Smart Cast

44 of 78

拡張関数

  • すでに定義されたclassにメソッドを�追加できる
    • 既存のJavaのclassにもできる
    • Nullableなclassにもできる

45 of 78

class Account

fun Account?.isExist() = this != null

fun main(args: Array<String>) {

val account: Account? = if (args.isNotEmpty()) Account() else null

if (account.isExist()) {

print("存在するアカウントだよ")

} else {

print("存在しないアカウントだよ")

}

}

Kotlin

Java

46 of 78

拡張関数 - 注意点

  • classの修正が面倒だからと言って�ガンガン追加しない
  • どこに関数群をまとめるのかを決める

47 of 78

標準で利用できる便利な記法が多い

  • 分割宣言
  • スコープ関数
  • Data Class
  • 拡張関数
  • Smart Cast

48 of 78

Smart Cast(Contract)

  • このパターンは問題ないということを�DSLでコンパイラに伝える
    • ドキュメントよりも明示的に利用者を補助する

49 of 78

interface Base {

fun isA() : Boolean

}

class A : Base {

override fun isA(): Boolean = true

fun doSomethingA() = println("A")

}

class NotA : Base {

override fun isA(): Boolean = false

fun doSomethingNotA() = println("NotA")

}

Kotlin

Java

50 of 78

@ExperimentalContracts

fun main(args: Array<String>) {

val create:Base = A()

if (create.test()) {

create.doSomethingA()

} else {

create.doSomethingNotA()

}

}

@ExperimentalContracts

fun Base.test(): Boolean {

contract {

returns(true) implies (this@test is A)

returns(false) implies (this@test is NotA)

}

return isA();

}

Kotlin

Java

51 of 78

@ExperimentalContracts

fun main(args: Array<String>) {

val create:Base = A()

if (create.test()) {

create.doSomethingA()

} else {

create.doSomethingNotA()

}

}

@ExperimentalContracts

fun Base.test(): Boolean {

contract {

returns(true) implies (this@test is A)

returns(false) implies (this@test is NotA)

}

return isA();

}

Kotlin

Java

test() がtrueを返すならinterface Baseはclass Aである

52 of 78

Smart Cast(Contract) - 注意点

  • Kotlin version 1.3ではまだExperimental
    • 現状どんな部分に使えるかわからないが�インタフェースは変わる気がするので�気長にまとう

53 of 78

使って良かった点

  • 標準で利用できる便利な記法が多い
  • ツールによるサポートが手厚い
  • いろんな場所でkotlinがかける
  • Javaと併用して使える

54 of 78

ツールによるサポートが手厚い

  • IntelliJ IDEAを使ったKotlin化がすごい
    • Kotlin to Javaもできる
    • そんなにKotlinっぽくは無いけれど�シンタックス周りは変換される

55 of 78

Demo - convert

56 of 78

使って良かった点

  • 標準で利用できる便利な記法が多い
  • ツールによるサポートが手厚い
  • いろんな場所でkotlinがかける
  • Javaと併用して使える

57 of 78

使える場所が多い

  • GradleをKotlinで書くことができる
    • タスクを全部Kotlinで書ける
    • 既存のgradleファイルと同居させられる
    • まだ完全に導入するのは厳しい印象 ( 記事書きました )

58 of 78

// 重要なとこだけ抜き出してます

apply plugin: 'kotlin'

apply plugin: 'kotlin-spring'

compileKotlin {

kotlinOptions {

freeCompilerArgs = ["-Xjsr305=strict"]

jvmTarget = "1.8"

}

}

dependencies {

implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")

}

Kotlin

Groovy

59 of 78

// 重要なとこだけ抜き出してます

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {

kotlin("jvm")

}

dependencies {

compile(kotlin("stdlib"))

}

val compileKotlin: KotlinCompile by tasks

compileKotlin.kotlinOptions {

jvmTarget = "1.8"

}

Kotlin

Groovy

60 of 78

使って良かった点

  • 標準で利用できる便利な記法が多い
  • ツールによるサポートが手厚い
  • いろんな場所でkotlinがかける
  • Javaと併用して使える

61 of 78

Javaと併用して使える

  • KotlinのclassをJavaからも参照できる
  • Spring Frameworkでの利用が簡単にできる
    • Gradleの場合、依存を追加するだけ

62 of 78

Demo - Spring Boot: searchByName

63 of 78

Kotlin興味でてきました?

64 of 78

休憩: Kansai.ktについて

ここまでで30分ぐらい

65 of 78

気をつけるべきパターン

66 of 78

気をつけるべきパターン

  • 既存のJavaとの連携
  • バージョンアップ
  • JDKとの折り合い

67 of 78

既存のJavaとの連携

  • Java側がNullを返すパターンが�若干ややこしい
    • Nullableで受ければ問題にならない
    • Java側もOptionalを返していれば�問題にはならない。。。はず

68 of 78

Demo - Spring Boot: searchByUid

69 of 78

バージョンアップ

  • Javaよりも激しい印象を受ける
    • Javaのバージョンについていけないチームで�利用するのかを考えた方が良いかもしれない
    • チームのスキルセットと相談しよう

70 of 78

JDKとの折り合い

71 of 78

まとめ

72 of 78

まとめ

  • KotlinはJavaの人が書いても結構使える
    • Java8のStream、Optionalに感謝
  • かっこよく書けるのはある意味、諸刃の剣
    • そのコードで何をしているのかを表現できているのか?

73 of 78

最後に、ちょっと採用について

74 of 78

75 of 78

76 of 78

特に Kotlin書いている�Android エンジニア

77 of 78

参考リンク

78 of 78

fin...