B-Teck!

お仕事からゲームまで幅広く

【Kotlin】Server Side Kotlin やってみた

tl;dr

  • Server Side Kotlinは特に特殊なことはないよ
  • Kotlinの言語仕様は便利だよ
  • Null安全の機構を導入することでアプリ側とのすり合わせがしやすくなるよ
  • Kotlinかわいい

はじめに

Kotlinってかわいいですよね。
サーバーサイド開発者の皆さん、Android開発者がうれしそうにKotlinの話をしているときに、
嫉妬したことはありませんか? 私はあります

今年1月に転職してから、色々と新しい事をやらせてもらえる環境になったので、
思いつきでKotlin入れませんか?と言ってみたところ上長から快諾され、導入できました。
そんなこんなで2018年後半はずっとSever Side Kotlinを書いていた感じでした。

なぜKotlinを導入したのか?

Android界隈でさんざん語られ尽くしている話題なので今更感もあるのですが、一応。
Kotlin導入以前のシステムは、主にJava8+Lombokでできていました。
なので、実は環境的に不満はあまりなかったんですね。
でも、Lombokのアノテーションとか毎回書くのめんどくさいじゃないですか、とか。
あとは込み入った処理になるとどうしても記述が多くなって読みづらくなってしまう、
Javaを使っている故の制約を感じるとか。
そういう細かい部分で気になることが多くて解決策を探していたところ、
Better Java(この言葉最近良く見ますね)としてKotlinを挙げる記事を多く見かけました。
特に気になったのはこの辺の仕様です。

  • mutable、immutableな値の宣言の簡潔さ
    • 型レベルでわかれてるのも良い。(List <-> MutableListとか)
  • data classの簡潔さ
    • そもそもclassでもgetter setterがいらない部分とか
  • Javaとの相互運用性(特に気にせずライブラリを呼び出せる)

タイミング的にも、エムスリーさんが導入事例を広く公開しだした時期だったため、
話題性で上司にプッシュしやすかったという理由もあります。
エムスリーで「サーバサイドKotlin」を導入したチームに話を聞きました - エムスリーテックブログ

実際にKotlinを導入してみた

元々Java + Jersey2で稼働しているシステムがあったので、
イチから作り直すという選択肢はありませんでした。
折よく新規API開発の案件が降ってきたので、ものは試しと新規API部分のみKotlinで書くことに決定。

私は下記の連載を読みながらとりあえず書いてみるという形で進めました。おすすめです。
一週間程度書いていれば手に馴染んでしまうのではないでしょうか。
毎日Kotlin | シリーズ | DevelopersIO

mavenの記述にKotlinへの依存を追加しそのままktファイルを作成してみたところ、
いくつか困る部分はあったものの割とすんなり導入に成功。
懸念していたJavaとの接続部分も特に問題なし。優秀です。

困った部分で一番大きかったのが下記記事に書いた件です。
アノテーションの対象を明示的に書いてやらないとうまく作用しないというのがわからず、
無限に時を溶かしました。
【Kotlin】KotlinでJava EEのBean Validationを使うときの注意点 - B-Teck!

もう一個かなり困ったのが、EclipseだとKotlinのplugin入れてもかなり厳しいということです。
Kotlin導入するなら素直にIntelliJ IDEA買いましょう。。。

導入成功に気を良くして、もりもりKotlinを増やしていたら新しいプロジェクトが始まったので、
実績を盾に開始時から基本的にすべてKotlinで書いています。
どうしてもKotlinに書き換えるとうまく動作せずJavaで書いた箇所はありますが、
概ね95%程はKotlinで書かれています。
最近では流行に乗ってCoroutinesも入れてみたりしました。

Server Side Kotlin導入のPros/Cons

Pros

  • 書きやすい!記述が少ない!
    単純に少ない記述で書ける事は正義です。
  • data classが神!
    サーバーサイドではアプリへの返却値作成のため、値を保持するクラスを大量に使います。
    用途にマッチしたdata classは本当にありがたいです。
  • アプリとNullableな値について認識を共有しやすい
    これまでは認識を合わせた上で返却値を実装で縛るしかなかったのですが、
    実装の時点でNullableの値を決められるので、認識の共有や実装がシンプルかつスムーズ
  • アプリ開発者が触りやすい
    Kotlinは、Android開発者はもちろん、Swiftにも記法が似ているため、
    アプリ開発者も比較的馴染みやすいようです。
    実際、プロジェクト内でもiOS開発者がサーバーサイドの実装を行い、
    2〜3時間程度のペアプロ・レクチャーで簡単なAPIを作成しました。

Cons

  • サーバーサイドKotlinの日本語の知見がだいぶ少なかった
    前述したBeanValidationの情報は最初全然見つからなくて、
    下記の記事を見つけたときは本当に嬉しかったです。
    jpa - kotlin data class + bean validation jsr 303 - Stack Overflow
    今はだいぶ増えたので、困ることは少ないかもしれないです。
  • 公開されている知見がアプリばかり
    当然といえば当然なんですが、Kotlinに関する知見がほぼアプリのものなので、
    そのまま適用できるのかどうかがわからず難しかったです。
  • KotlinのコミュニティはAndroidと密結合で、参加しづらかった
    知見の話にも共通するのですが、Androidに関係なくKotlinの話ができる場所、
    コミュニティが少なく感じました。
    Server Side Kotlinが広まるにつれて増えてほしいなと思っています。
  • 解決できないときに、原因の切り分けが難しかった
    Server Side Kotlin特有の問題か、そうでないのかの切り分けが難しかったです。
    これも今は事例が増えたので困らないかもしれないですね。
  • IDEA使わないで書くのが地獄
    Kotlinを書くならIntelliJ IDEA一択なのが辛いです。
    Eclipseを使っている人に勧めづらく、プロジェクトで利用するなら全員で移行する必要があります。
    IDEとしては優秀なのでとても好きですが。。。

まとめ

既存Javaプロジェクトへの部分的な導入も簡単!
既存ライブラリとの相互運用性もバッチリ!
簡潔でモダンな記述でイケイケエンジニアになれる!
事例が増えてきて、情報少ない問題も解決しつつある!
Server Side Kotlinは怖くない!みんなもやろう!!

【Kotlin】文字列の日時が指定の期間内に含まれているかを判定する

KotlinのDateにはRange演算子(Ranges - Kotlin Programming Language)が実装されているので、
簡単に大小や範囲を判定することができる。

下記は文字列の日時をSimpleDateFormatでDateに変換して、
0時から3時の間に含まれるかを判定しているサンプル。

 import java.text.SimpleDateFormat
 fun main() {
     println(isDateInRange("2018-11-26T01:50:00")) // true
     println(isDateInRange("2018-11-26T08:50:00")) // false
 }

fun isDateInRange(input : String) :Boolean {
    return SimpleDateFormat("yyyy-MM-dd'T'HH:mm").let{
        // 年月日だけ取り出す
         val date = SimpleDateFormat("yyyy-MM-dd").let{
             val parsed = it.parse(input)
             it.format(parsed)
         }
         // 指定範囲を作る(例として0時から3時)
         val range = it.parse("${date}T00:00:00")..it.parse("${date}T03:00:00")
         // 含まれているかを確認する
         range.contains(it.parse(input))
    }
}

【JavaScript/jQuery】後から生成されたDOMからイベントを発火させる

jQueryの場合

昔こういう事するときはjQueryのlive()を利用していたんだけど、1.9で死んでた。

$("p").live("click", function(){
    $(this).after("<p>これもクリックできる</p>");
});

1.9以降で同じ挙動させるならonを使う

$(document).on('click', 'p', function() {
    $(this).after("<p>これもクリックできる</p>");
});

documentの部分を別のjQueryオブジェクトにすると、
そのオブジェクト配下だけで動的にイベントが付与される。

// hoge配下にp要素ができたときだけイベントを付与
$("#hoge").on('click', 'p', function() {
    $(this).after("<p>これもクリックできる</p>");
});

jQueryの場合のサンプル

See the Pen EOwjbB by beatdjam (@beatdjam) on CodePen.

pure JSの場合

pure JSの場合は、親要素にイベントを仕込んで、eventのtargetの属性を見ることで対応するっぽい。
対象のelementの条件がidか、classか、tagNameかによって挙動が変わって分かりづらい。
正直jQueryのほうがきれいだと思う。

document.addEventListener('click', function (e) {
    // idの場合はこう
    // if (e.target.id === 'hoge') {
    // class名指定の場合はこう
    // if (e.target.classList.contains('hoge')) {
    // タグ名指定の場合はこう(大文字で取れるのでtoLowerCaseしている)
    if (e.target.tagName.toLowerCase() === 'p') {
        e.target.insertAdjacentHTML('afterend', "<p>これもクリックできる</p>")
    } 
});

JSでもaddEventListenerするelementを絞ってやることができる。

document.querySelector("#hoge").addEventListener('click', function (e) {
    if (e.target.tagName.toLowerCase() === 'p') {
        e.target.insertAdjacentHTML('afterend', "<p>これもクリックできる</p>")
    } 
});

JavaScriptの場合のサンプル

See the Pen WYZvOd by beatdjam (@beatdjam) on CodePen.

insertAdjacentHTMLについては下記参照。便利。
innerHTML より insertAdjacentHTML を使う - Qiita