やっぱりassertThatは良いよねという話
追記 2016/6/12
テスト結果のメッセージを読みやすくしたいだけなら、assertThatにreasonを書く方が楽ですね。
@Test public void test() { File file = new File("/tmp/hoge"); assertThat(file.getAbsoluteFile() + " should exist", file.exists(), is(equalTo(true))); }
java.lang.AssertionError: /tmp/hoge should exist Expected: is <true> but: was <false>
追記終わり
assertThatやっぱ便利ですねー、という話です。
assertEqualsは何のテストに失敗しているのか分かりにくかった
public class AssertEqualTests { @Test public void test() { final File test1 = new File("/tmp/test1.txt"); final File test2 = new File("/tmp/test2.txt"); final File test3 = new File("/tmp/test3.txt"); assertEquals(true, test1.exists()); assertEquals(true, test2.exists()); assertEquals(true, test3.exists()); } }
ファイルが存在しているかどうかをテストするだけです。
で、これを実行してみると、テストが失敗しました。
java.lang.AssertionError: expected:<true> but was:<false>
これだとどのファイルで失敗したか分からないですね。
まあスタックとレースをちゃんと見れば何行目のassertEqualsで失敗しているか分かるので判定はできるのですが、あまり直感的ではありません。
Matcherを作って原因を分かりやすくしよう!
そこでassertThatとhamcrestの出番です。
もっとわかりやすいメッセージを返してくれるMatcherを作ってみました。
public class FileExist extends TypeSafeMatcher<File> { private final boolean isEexpectedResult; private File inspected; public FileExist(boolean exceptedResult) { this.isEexpectedResult = exceptedResult; } @Override public void describeTo(Description description) { description.appendText(inspected.getAbsolutePath()); if (isEexpectedResult) { description.appendText(" exist"); } else { description.appendText(" does not exist"); } } @Override protected void describeMismatchSafely(File item, Description mismatchDescription) { mismatchDescription.appendText(inspected.getName()); if (isEexpectedResult) { mismatchDescription.appendText(" does not exist."); } else { mismatchDescription.appendText(" exist."); } } @Override protected boolean matchesSafely(File item) { this.inspected = item; return item.exists() == isEexpectedResult; } @Factory public static <T> Matcher<File> exist() { return new FileExist(true); } @Factory public static <T> Matcher<File> NotExist() { return new FileExist(false); } }
TypeSafeMatcher
ファイルを受け取って期待通り存在しているか、もしくは存在していないかをテストできます。
そしてdescribeToで成功時のメッセージを、describeMismatchSafelyで失敗時のメッセージを作成しています。
テストは以下のようになります。
public class AssertThatTests { @Test public void test() { final File test1 = new File("/tmp/test1.txt"); final File test2 = new File("/tmp/test2.txt"); final File test3 = new File("/tmp/test3.txt"); assertThat(test1,exist()); assertThat(test2,exist()); assertThat(test3,exist()); } }
そして実行結果。
java.lang.AssertionError: Expected: /tmp/test2.txt exist but: test2.txt does not exist.
test2.txtが存在していないというのが一目でわかりますねー。素敵です。
Matcherを簡単に作れるというのは、結果の分かりやすくする事にも役立つんですね。
ちょっとはまったこと。
Matcherを作るとき、どうしてもdescribeMismatchSafelyが見つからず@Overrideがエラーを吐いてしまいました。
原因は我らがstackoverflowで見つかりました。
第19回折紙探偵団コンベンション
今年も折紙探偵団コンベンションに参加してきました。
盛況でしたねー。
相変わらず老若男女国内外と様々な人達が参加していました。
折り紙のファン層って不思議ですね。
今回は初めてユニット系や難易度が低めの教室に参加しました。
いや・・・その・・・久しく折っていなかったので難易度が高めのを折る自信が無かっただけです。はい。
- U-cube ★★★ 霞 誠志
- セミ ★★★ 世浪 健
- 富士山 静岡View ★★ 鈴木美恵子
- バランスとんぼ ★★★ 中村淑子
最大でも星3個(中級?)。弱気な選択でしたが、リハビリにはちょうど良く楽しめました。
以下は展示されていた作品です。
正直、これらを見るだけでも大満足です。
Java8のLambdaの型推論が実行時にならいと型が分からない理由(追記あり)
JJUGナイトセミナー「Inside Lambda」に参加してきました。
Java8のLambdaの概要と、実装方法についてのお話でした。
非常に面白かったのですが、その中でLambdaの型推論が実行時にならいと型が分からないという話があったのでまとめてみます。
Lambdaの型推論
Lambda式の中ではコンパイラが推測できる場合は型を省略する事が可能です。
Comparator<Integer> comp = (x , y) -> x -y;
しかし、実際に型が決まるのはコンパイル時ではなく実行時になります。
それはなぜでしょうか?
Lambdaの実装
その答えは、ナイトセミナーの宮川さんの発表で理解できました。
それは、Lambdaがinvokedynamicを使って実装されているからです。
invokedynamicについては・・・これまた宮川さんの資料が分かりやすいです。
私の理解では、
- JVMで実際にメソッドを実行したりするのがInvokeなんたらのお仕事
- その中でもinvokedynamicはJava以外の動的型付け言語をJVMで動かすための機能
- そのためinvokedynamicは実行中にクラスファイルを動的に生成したりできる
という感じです。
で、Java8のLambdaはinvokedynamicを使って実装されているそうです。
そのため、実際に型が分かるのが実行時ということになります。
仕様?
@nagaseyasuhito いえ、違います。invokedynamicを使うかどうかは実装の問題です。 #jjug
— Yuichi Sakuraba (@skrb) 2013, 7月 22
@nagaseyasuhito invokedynamicが使われていないで、コンパイル時に無名クラスを作っていた時代もありましたよ ^ ^;;; #jjug
— Yuichi Sakuraba (@skrb) 2013, 7月 22
実装がたまたまそうなっている、という話だそうです。
なのでJava8が正式リリースされた時には、ひょっとしたらコンパイル時に型が決まるようになっているかもしれませんね。
実害はあるのか?
ちょっと考えてみたのですが思いつきませんでした。
実行時に決まるからどんな型になるかわからない?!って事はないですよね、これ。
あくまでコンパイラも型推論チェックをやっているので、実際に予期せぬ型になってしまうことはなさそうです。
まとめ
Scalaを使おう!
追記
きしださんからコメントをもらいました。
@sakamoto_desu 「型推論が実行時にならいと型が分からない」というの、「型がわからない」という表現は違うと思います。型は「Comparator<Integer>」だとわかっているので。
— きしだ (@kis) 2013, 7月 26
@sakamoto_desu 型推論としてはコンパイル時に「Comparator<Integer>」だと確定した時点で型が決まって、これ以上は型推論の話ではないです。
— きしだ (@kis) 2013, 7月 26
@sakamoto_desu そうですそうです。Runnable r = hoge(); で、hogeメソッドが返してきて実際に変数rに割り当てられるインスタンスの型が実行時まで決まらないのと、言語上でやってるかVM上でやってるかの違いだけで同じものという感じです。
— きしだ (@kis) 2013, 7月 26
というわけで、正確には「ラムダ式の型は実行時にならないと決まらない」という話でした。
タイトルも含めて書き直そうかとも思ったのですが、きしださんにコメントもらえた記念ということで追記だけにしておきます。
他のMacのTime Machineバックアップからデータを復元する方法。
メインで使っていたMac Book Proに水をぶっかけてしまい、泣く泣くMac Book Airへデータを移行しました。
その際、iTunesやらiPhotoのデータを復旧するのに苦労したのでメモしておきます。
この質問が参考になりました。
1. Finderをコンピュータに移動
新Macに外付けHDDをつないだら、まずこれをやっておくとスムーズに作業ができます。
Finderメニュー -> 移動 -> コンピュータ で移動できます。
2. 他のバックアップディスクをブラウズ
Time Machineをaltを押しながら起動すると、「他のバックアップディスクをブラウズ」というメニューが出てきます。
これを選ぶと他のMacで保存されたバックアップを選択できるようになります。
旧Macのバックアップデータを選択します。
3. 旧Macの最新バックアップを選ぶ
「他のバックアップディスクをブラウズ」すると、普段と違ってピンク色の時系列データが表示されます。
それが旧Macのデータです。
濃いピンク色になっているものを選択すれば、自マシンと同じようにデータを取り出せます。
4. データを選べない?
ただし、最初の「Finderをコンピュータに移動」をやっておかないと、透けたピンク色になって選択できない場合があります。
これは、Time MachineがFinderで操作中のディレクトリがバックアップの中にあるかどうかで、選択可・不可を判断しているのが原因のようです。
例えば、新旧でユーザー名が変わっており、以下のようだったとします。
新Mac操作中のFinder:/Users/user2/Document 旧Macで欲しいデータ:/Users/user1/Document/awesome.txt
新Macにはuser1というユーザが居ないので、/Users/user2/Documentは存在しません。
この状態でTime Machineを起動すると、透けたピンクとなってデータを選択できません。
しかし、コンピュータ(要するに絶対パスのroot)からたどると/User/user1にたどり着く事ができ、データも選択できるようになります。
そのために、最初にコンピュータに移動する、という手順にしました。
Time Machine起動後でもコンピュータに移動はできますが、移動メニューなどが出ないので先にやっておいた方が楽です。
(自分がショートカット覚えてないだけですが。)
Scala Conferenceスタッフやってみた(謝罪あり)
3/2(日)、Scala Conference in Japan 2013が開催されました。
私はスタッフとして準備に奔走していましたが、無事終了しほっとしております。
多くの方にご来場頂き、誠に感謝です。
そんな中で、次はスタッフを手伝いたい!という声を多数聞いたので、参考までに実際のスタッフ業務とはどんな感じだったのかをまとめておきたいと思います。
謝罪
まずは謝罪から。
メイン会場が寒いという情報はキャッチしていたのですが、なかなか改善できませんでした。
実は空調設備の使い方を勘違いしていて、ずっと空調がOFFになっていました。
申し訳ございませんでした。
どんな仕事?
期間は?
2012年7月21日(土) からスタートしました。
現在も後処理が進行中です。
どれくらい時間を取られるの?
ミーティング
ミーティングは全8回行いましたが、全員が毎回出席した訳ではありません。
恐らく全部出席したのは座長と副座長だけではないでしょうか?
他のメンバーはまちまちです。
忙しい時期は?
- 初期:会場選定
- 中期:スポンサー対応、ゲスト招致、広報など
- 後期:全担当
1日のうちどれくらい作業したの?
これも担当内容によってまちまちですが・・・
毎日メール書いたりサイトを更新したりしている人もいれば、短期間集中で担当タスクを片付けて終わり、という人もいました。
私の場合は、後期は平均毎日30分程度(共有情報のチェック、外部とのメール、会場設計)タスクに時間を割いてました。
前日・当日スタッフ
ここまでの説明はコアメンバーのケースです。
その他にも、前日・当日のみ手伝うという方法もあります。
今回は7名の方に前日・当日スタッフとして参加して頂きましたが、大変助かりました。
どんな仕事があるの?
- 前日まで
- 会計
- 会場選定、デザイン
- スポンサー対応
- ゲスト招致
- プログラム作成
- サイト作成
- ノベルティ作成
- ランチ手配
- 懇親会手配
- チケット販売
- 翻訳
- 広報
- etc
- 当日
- 会場(司会、質問マイク、スピーカー対応など)
- 受付(チケット確認、ノベルティ配布、ランチ配布など)
- 会場設営、撤収
- 翻訳(リアルタイム翻訳tweet)
- 案内
- 撮影(動画撮影、写真撮影)
- etc
- 終了後
- アンケート集計
- 会計
- 広報
- etc
どうやって情報共有したの?
- ミーティング
- メーリングリスト
- co-meeting
- GitHub
仕事の流れは?
あれやらなきゃね -> じゃあ僕やります -> ... -> 終わりました -> ... あれやらなきゃね -> じゃあ僕やります -> ... -> すいません忙しくてできません -> じゃあ代わりにやります
最終的にはチームでなく個人にタスクを割り振る形に落ち着きました。
全部自分達でやるの?
受付、ロゴデザイン、撮影、アンケート集計などは業者に依頼しました。
お金はどこから?
全部スポンサー様の支援を元に活動しています。
スタッフは何者?
Scala詳しくないけど大丈夫?
初心者でもOKです。
英語できなくでも大丈夫?
大丈夫です。
英語が必要なタスクは、堪能な方々にお願いしました。
開催直前のスタッフ募集では英語が必要といったニュアンスでしたが、タイミング・リソース的にそういった人材だとよりありがたかっただけで、全員に英語必須という訳ではありません。
なんでスタッフやったの?
私の場合は、生活に変化が欲しかったのと、Scalaが広まって欲しいという思いからです。
メリットは?
- 交友広がった
- 盛り上がりの輪の中に居れた
- やり遂げた感は異常
懇親会では気持ち悪いぐらいスタッフ同士褒め合いました。
お金貰えるの?
ボランティアです。
次回は?
次はあるの?
未定です。座長(@kmizu)の言葉を待て!
どうやって参加するの?
次回があるとしたら、座長がまた募集すると思います。座長の言葉を待て!
途中参加、前日・当日参加のみもOKです。
macでデフォルトのcore出力設定を変える方法
環境
- OS X 10.8.2 Mountain Lion
ulimit
coreはデフォルトでは出力サイズが0になっているので出力されません。
出るようにするにはulimitコマンドを使います。
まずは現状の確認。
$ ulimit -a core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited file size (blocks, -f) unlimited max locked memory (kbytes, -l) unlimited max memory size (kbytes, -m) unlimited open files (-n) 256 pipe size (512 bytes, -p) 1 stack size (kbytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 709 virtual memory (kbytes, -v) unlimited
無制限に変更します。
$ ulimit -c unlimited $ ulimit -a core file size (blocks, -c) unlimited data seg size (kbytes, -d) unlimited file size (blocks, -f) unlimited max locked memory (kbytes, -l) unlimited max memory size (kbytes, -m) unlimited open files (-n) 256 pipe size (512 bytes, -p) 1 stack size (kbytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 709 virtual memory (kbytes, -v) unlimited
これでcoreが出力されるようになります。
launchd.conf
ただし、ulimitの設定は再起動すると失われます。
デフォルト設定を変えるには、/etc/launchd.confを使うのが簡単です。
/etc/launchd.confに以下を記述します。デフォルトではlaunchd.confは存在しないので作成します。
limit core unlimited unlimited
launchd.confは、launchdの設定ファイルです。
launchctlのコマンドをそのまま記述できます。
後輩に教えたら喜ばれたキーバインドの話
ある日の事。
ぺこぺことキーボードを叩きながら後輩とペアプロしていたら、「その操作どうやるんですか?ショートカットとか覚えたいっす!かっこいいっす!」と情熱的な眼差しを向けられました。
俺も昔、全く同じ事を思ったなあと回想しながら、さて何を教えようと逡巡したので、その結果をまとめておきます。
前提
- プログラマー向けの話です。
- Windowsのキーボードは109配列キーボードを想定しています。
キーを入れ替えよう
- Escキー
vimを使っているとEscキーを多用しますが、Windowsの場合は左上隅にあるので押しにくいです。
そこで、半角キーとEscキーを入れ替えちゃいましょう。すると、Escの位置がぐっとホームポジションに近くなるので押しやすくなります。半角キーを多用する人は、半角キーもスペース横のかな変換キーなどと交換してしまいましょう。
キー交換には、change keyとかが便利です。
- Ctrlキー
Emacsその他IDEを使っていると、Ctrlキーを多用しますが、これまたWindowsは左下、右下と押しにくい位置にあります。
そこで、CapsロックキーとCtrlキーを入れ替えちゃいましょう。CtrlキーはIDEに限らずあらゆるアプリケーションのショートカットキーで使われるので、おすすめの設定です。
Emacsバインドを覚えよう
新しいIDEを使う事になったとき、またショートカットを覚えるのかとうんざりしませんでしたか?
でももしEmacsのキー操作を覚えていると、その負担は激減します。
Emacsの代表的なキー操作(上下左右/行頭行末への移動、削除/、検索など)は、以下の環境で使う事ができます。
EclipseやIntellj IDEAなどはキーバインドの設定変更が必要ですが、それ以外はデフォルトで使う事ができます。
個人的に特に効果を感じるのは、Bash操作とMacですね。
Bashのコマンドラインでは行頭、行末移動ができるだけで、かなり操作効率が上がります。
さらにMacはメモ帳、ターミナル操作、ブラウザのアドレスバーまでEmacs操作ができます。いちいちトラックパッドや矢印キーを使わないでいいのは素敵ですね。
Dvorak配列を覚えよう
現在の標準的なキーボードは、qwert配列ですが、こいつは決して人間向きな配列ではありません。
母音が離ればなれになっており、手が疲れやすいです。
そこで考えだされたのがDvorak配列です。
この配列は母音が一塊で並んでおり、指の移動距離が短く疲れにくいという特徴があります。
これをマスターすれば1日中タイピングをしても疲れしらず!
Windowsでは窓使いの憂鬱とかのどかを使えばDvorakに変更することができます。
Mac/LinuxではDvorakのキー配列がデフォルトで搭載されているので、簡単にDvorakにかえる事ができます。
ただし弊害として、
- 自分のPCを他の人が操作できない
- 客先作業とかで急にqwertを触るとおたおたして仕事できない人に見える
のような問題があります。まあ・・・それをふまえてもよいと思いますよ、Dvorak。