TDDBC岡山 2.0に参加してきました。

岡山で2回目のTDD BootCampが開催されました。
前回は一般参加で参加したのですが、今回はTAとして参加しました。
実はPHPのTAをお願いしますと言われてたので、PHPUnitの練習を少ししていたのですが、開催数日前に参加者にPHPの方がいないことがわかったのでRubyのTAになりました。

全体的な流れとしては、

  • 開催挨拶
  • スタッフ紹介
  • @t_wadaさんの講演
  • TDDデモ(Scalaで)
  • ペアプロでTDD
  • 昼食
  • 質疑応答
  • ペアプロでTDD
  • コードレビュー
  • 発表
  • 質疑応答
  • クロージング

という感じでした。

TDDとは何か、なぜTDDをするのか、いかにしてTDDを現場に持ち込むかという話と、勉強するための本の紹介があったのですが、ピアソンエデュケーション
が日本で書籍販売をやめる事になったので、絶版になっている本がかなりありました。なんとかこういう良書は達人出版会とかで販売してほしいものですねぇ。

TAだったのですが、Rubyの参加者が4人に対してTAが3人だったので、2人でペアプロ+TA、1人+TAでペアプロ、1人+TAでペアプロの3組に分かれました。キーボードの問題で(ぇ…)、できないという人もいたので、とりあえずそれでうまくいくように分かれました。ペアプロするにしても、そういう問題があるんすねぇ…。
たしかにキーボードとエディタで困るのは嫌なので、そこはなんとかしていないとダメかもしれません。自分のペアも、相手の人はVim派で、僕がVimを使えないので自分のマシンのIntelliJにしてもらいました。(エディタ戦争したくないのですが、僕はVimもEmacsも慣れるまで耐えられないのでIDE好きです。特にJetBrains製品好きです。)

最初はRSpecの使い方を知らないという事だったので、describe, context, before, it, its, shouldなどの説明をしました。expectの文法は自分があんまり使った事がないので特にしませんでした。まぁ使えるけど個人的にはshouldのほうがわかりやすい気がするんですよね…。でもこれからはexpectで書いていくべきなんだろうか…。

課題は自動販売機を作るという恒例のやつなのですが、要件を確認した後、相手の方が最初に実装を書いてしまいそうだったので、止めて、まずテストを書いてもらいました。TDDですからね。Red, Green, Refactorの順です。TDDって意識しないとコーディングに集中しすぎて実装に取りかかってしまうのが問題だなと自分自身思っていたのですが、他人が同じ事をしようとすると止められるのに自分だと気づかないんすよね…。やっぱりペアプロは気づかされること多いなと思いました。

ペアプロが終わってから、他のチームと一緒にコードレビューをしたのですが、やっぱり色んな書き方というかアプローチがあって、面白かったです。個人的には実装にこだわりすぎるのもどうなんだ?という気がしていて、課題をがんがん進めていくほうが気付きは多いんじゃないかなーと思っているのですが、どっちがいいのかはわからないですね。

あとはどうやって今日学んだことを現場に取り込んでいくかという話を聞いて、クロージング。
懇親会は岡山での定番である、座・スタジアムでした。
参加者が22名だったので、いつもと違って広々とした会場で、いつもより和やかムードでLT大会になった感じでした。
ネタの人、ガチの人、前にやったLTを再度やったりする人と様々でしたが、とても楽しい時間でした!

そしてToggeterでのまとめはこちらです。

次回あるとしたら次はKotlinのTAとして参加したいものです!


Kotlin+JavaFX 2.2でビルドする(追記あり)

(追記)この記事を公開した後、ちえさんからこんなツイートが…。

gistにコードをアップしてもらって、似たような感じに直したあと、確かにartifact設定のままでビルド通りました。また、何が違うのか試そうとコードを元に戻してから再度ビルドをかけたら、また通ってしまいました…。違いがわからないどころか、以前にビルドできなかった理由がわからなくなりました。うーん、謎い…。

もし、KotlinでJavaFxアプリの起動部分がどうしてもうまくいかない、という方のみ、以下を参考にしてみてください。

以下、原文


Kotlin+JavaFXでアプリを作ったら、使えるようにビルドしたいじゃないですか。

以前は以下のURLを参考にアプリをjarにまとめていました。
Kotlin + JavaFX 2.2の場合の実行可能jarを作成する

前はこれで動いたのですが、今の段階になって何故かおかしくなりました。
jarにはなるんだけれど、実行すると動作が変になってしまい…。

そもそもIntelliJにはartifactsを作るときにJavaFx Applicationがあるので、それを選びたいのですが、Kotlinで作ると実行用クラスが存在しないので、選べません。◯◯Packageを指定しても、ダメでした。

ふと思いついたのが、JavaFXを起動するところだけ、Javaで書いてしまう(!!)という方法です。
これを試したところ、artifactsでJavaFX Applicationを選択することができました!かつ、jarではなく、dmgなどの形式にすることができたので、こちらのほうが汎用性がよさそうです。

まぁJavaFXの起動部分もKotlinで書いた状態でJavaFX Applicationが選択できるようにIntelliJが進化してくれるまではこれで凌ぐほうがよいかなーと思います。


KotlinでPreferencesクラスをシングルトンで。

AndroidのSharedPreferencesみたいなのはないのかなー?と思っていたら、@skrbさんにあることを教えてもらいました。java.util.prefs.Preferences。そのまんまやった…。

これを使って設定用クラスをKotlinで書いてみた。ついでにシングルトンにしつつ、項目をプロパティ(メンバ変数)として扱えるようにしてみた。
見た目がカッコいい。Javaで同じ事をしようと思ったら、setter, getterメソッドだらけになるけど、Kotlinならその辺りを隠蔽できる。(やってることは同じなんだけど)

object ProjectPreferences {
    val UPDATE_INTERVAL_SECONDS = "UpdateIntervalSeconds"
    val START_WITH_CHECK = "startWithCheck"

    val prefs by Delegates.lazy { java.util.prefs.Preferences.userRoot()!!.node("ProjectName") }

    var updateIntervalSeconds: Int
        set(seconds: Int) = prefs.putInt(UPDATE_INTERVAL_SECONDS, seconds)
        get() = prefs.getInt(UPDATE_INTERVAL_SECONDS, 3600)

    var startWithCheck: Boolean
        set(check: Boolean) = prefs.putBoolean(START_WITH_CHECK, check)
        get() = prefs.getBoolean(START_WITH_CHECK, false)
}

こう書く事で、

ProjectPreferences.updateIntervalSeconds

で値を取得できるし、

ProjectPreferences.updateIntervalSeconds = 300

で値を設定できる。startWithCheckも同様に = trueとかで値を設定できる。

見た目が綺麗になるし、コード量も減るからいいね!Kotlinは!


JavaFXでMacのスクリーンメニューバーを使う

JavaFX + Kotlinでアプリを作っているのですが、メニューバーがWindowsみたいになってダサい。Macなら上のメニューバーに表示されたいじゃないですか。あれはいったいどうやってるんだろうか?と思ってググってもなかなか出てこなかった。そもそもMacのメニューバーってなんていうのだろうか?と思っていたら、スクリーンメニューバーって言うらしい。ふーむ。

で、どうするのかと思っていたら、すごく簡単だった。知らないとできない、みたいな感じ。

MenuBarクラスに、setUseSystemMenuBarメソッドがあるから、それでtrueを指定すればよさそう。

一応リンクはっとく。
MenuBar

ただ、これはFXMLでも指定できる。

<MenuBar
    useSystemMenuBar="true">
    <menus>
        <Menu text="ファイル">
            <item text="開く" />
            <!-- 省略 -->
        </Menu>
        <!-- 省略 -->
    </menus>
</MenuBar>

これだけで急にMacのアプリっぽくなる。


Kotlinでsynchronizedを実現する

PHP出身の俺はスレッド周りの知識が非常に乏しい。
スレッドの勉強はときどきやってるんだけど、今回もその一環。
だが、Kotlinでやってる。
Javaの本を読みながら、synchronizedメソッドを実装しようとしたところ、なんとsynchronized修飾子がKotlinには存在しない!!
(synchonizedブロックはある)

synchronizedブロックで実現できるかなと思っていたのだが、自分のやり方が悪いのか、なんでかうまくいかなかったので、いろいろと調べていたら、Lockというのを発見した。

Lockを使うのが最近はよさそうらしい。ということで使ってみた。
ReentrantLockでLockを作り、withLockブロックで排他制御する。

このサンプルは、ボトルに入っている1000mlをyamadaとtanakaが200mlずつ飲んでいくというものである。
ちゃんと中身があることを確認した上で飲むというふうにしているのだが、中身があることを確認するタイミングがかぶると、あると思って飲み過ぎてマイナスになるので、withLockを使って排他制御している。
withLockが、飲む人がボトルを持っている状態と思ってもらえるとわかりやすい。

package com.okolabo.KotlinThreadChallenge

import kotlin.concurrent.thread
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock


fun main(args: Array<String>) {
    val bottle = Bottle()
    val drink = {
        while (bottle.drink(200)) {
            println(Thread.currentThread().getName() + " did drink water")
            Thread.sleep(200)
        }
    }

    val yamada = thread(name="yamada", block=drink)
    val tanaka = thread(name="tanaka", block=drink)
    yamada.join()
    tanaka.join()
    println("water: " + bottle.water)
}

class Bottle {
    var water = 1000
    class object {
        val lock = ReentrantLock()
    }

    private fun contains(amount : Int) : Boolean = amount <= water

    public fun drink(amount : Int) : Boolean {
        return lock.withLock {
            if (contains(amount)) {
                println("before water: " + water)
                water -= amount
                println("after water: " + water)
                true
            } else {
                false
            }
        }
    }
}

メソッド全体をlock.withLockで囲んでしまうことで、synchronizedメソッドっぽいことができるかなと思う。