発火後忘失

FIRE AND FORGET

VirtualBox上になるべく小さくCentOS7 X環境を作る

VirtualBox上のCentOS7になるべく小さめなX環境を構築しようと考え、実行した時の作業メモです。

インストール時にGUI環境を選択した場合は5GB程度になるのに対し、この手順でインストールした場合は1.6GB程度になりました。

インストール〜X起動まで

  1. (お好みで)仮想マシンの設定: システム>マザーボードEFI有効化をONにしておく。
  2. インストールディスクから最小限の構成でインストールを完了させる。
  3. sudo yum update
  4. sudo yum groupinstall "X Window System"
  5. sudo yum install epel-release
  6. sudo yum install icewm liberation-mono-fonts
  7. ホームディレクトリに .xinitrc ファイルを作り、1行 icewm と記述。
  8. xinit コマンドでX起動。

マウス統合機能の有効化

  1. sudo yum install kernel kernel-headers kernel-devel dkms bzip2 gcc
  2. kernelのバージョンが上がっているのでOSを再起動させる。
  3. VirtualBoxのメニューから "デバイス > Guest Additions CDイメージの挿入" を選択。
  4. sudo mkdir /mnt/cdrom && sudo mount /dev/cdrom /mnt/cdrom
  5. sudo sh /mnt/cdrom/VBoxLinuxAdditions.run

標準のGNOMEではクリップボード共有もこれでOKでしたが、icewmであのクリップボードにアクセスするにはどうしたら良いんだろう…

f:id:yukihaned:20160213172242p:plain
(xeyesxorg-x11-appsパッケージに入っています。)

VDIファイルをコンパクト化

上記の手順で作成したvdiファイルは保存しておいて、必要に応じてコピーして使いまわしたいのでファイルサイズをコンパクト化しておきます。

  1. 不要ファイルを削除する。
    • (yum一時ファイルについて) sudo yum clean all
  2. 下記コマンドを実行して空き領域を0埋めする。
sudo dd if=/dev/zero of=/bigemptyfile bs=4096k
sudo rm -rf /bigemptyfile

終わったら仮想マシンをシャットダウンし、続いてホストOS上で実行。

  1. コンパクト化: VBoxManage modifyhd centos.vdi --compact

バックアップをとっておく。

  1. 上記手順で作成したvdiファイルをコピー。
  2. VDIファイルUUIDの変更: VBoxManage internalcommands sethduuid centos-copy.vdi

SQLのランダム関数がランダムすぎる、あるいはランダムでない

ネタ元はこちら:

create table my_table (my_number integer);
insert into my_table values (0), (1);

としたテーブルに対して

select * from my_table where id = <ランダム関数を用いて求めた整数値を2で割った余り>;
// 例: MySQLの場合
select * from my_table where id = (floor(rand() * 100) % 2);

このようなSQLを実行すると、どのRDBMSの場合でも、結果は必ずどちらか1レコードのみが得られる…わけではない、と。
0行だったり2行だったりするRDBMSもあります。

理由はMySQLのリファレンスに書いてあったのですが、

WHERE 句内の RAND() は、WHERE が実行されるたびに再評価されます。

ということで、1レコード目の評価では0だったとして、2レコード目の評価時にも0である保証はない、ということですね。

一方で、SQL Serverではそうではなく、上記のような状況で常に同じ値を返しますので、どちらの評価時にも0、あるいはどちらの評価時にも1の2パターンになります。

気になったので、ランダム関数がどちらのRDBMS方式なのか、メジャーなものを対象に調べてみました。

結果として、SQL Serverだけ特殊、ということになりました。
そういえばASEはどうなんだろう…と検索してみたところ(仮想環境的なものは見つかりませんでした)、オンラインマニュアルに次のような記述がありました。

Unlike rand, rand2 is computed for each returned row when it is used in the select list.

というわけで、SQL Serverと同じ~rand~以外に、~rand2~という関数も備えているようです。
(ただ、used in the select list という意味がわかってません。もしかしたらwhere句では使えないってことなのかも…?)

Androidアプリ開発でMySQL Connector/Jを追加してビルドしようとするとエラーになる

ネタ元:

AndroidJDBCドライバを直接使うっていうのが「その発想は無かったわ!」てな感じでかなり衝撃を受けたのですが、ググってみるとそれなりに事例はありそうです。
まあ、いわゆるDBアプリが今全部Webアプリに置き換わったわけでもないですし、Androidをクライアントに使うとなるとさもありなん、てな感じなんでしょう。

本題です。
Androidアプリビルド時に mysql-connector-java-5.1.37-bin.jar を依存関係に入れていると、次のようなエラーメッセージが出力されます。

Caused by: com.android.dx.cf.iface.ParseException: bad class file magic (cafebabe) or version (0034.0000)

クラスファイル解析しようとしたけどファイル形式がおかしいので失敗した、ということなんですが、大抵の場合はAndroidが対応していないバージョンのライブラリを追加した場合にこのエラーになります。

で、その大抵の場合、見るべきポイントは version (0034.0000) の部分で、今回は数値が 34 となっています。
WikipediaのJavaクラスファイル のページ内をこの 34 で検索すると、Java8向けのファイルであることがわかり、AndroidではJava8未対応なので無理なんだな、と納得できます。

なぜ5.1.37(以降)はJava8向けなんだろう、という点については、おそらくJDBC4.2対応のためでしょう:

It is also the first release of MySQL Connector/J to support the Java Database Connectivity (JDBC) 4.2 API.

MySQL :: MySQL Connector/J Release Notes :: Changes in MySQL Connector/J 5.1.37 (2015-10-15)

補足すると、おそらく通常のJava上で使用する分にはJava8は要求されません。なぜなら、Java8未満で使用する分には、JDBC4.2関連のクラスをロードする必要がないためです。JDBC4.2関連クラス以外はJava5向けにビルドされているようです。

javap コマンドを.classファイルに対して実行すればバージョンがわかりますので試してみましょう:

$ javap -v VersionFSHierarchyMaker.class |grep "major version"
  major version: 49

(Androidコンパイラは16進表記でしたが、こちらは10進表記ですね)

Androidコンパイラがエラーを出すのは、実際に使用している/していないにかかわらず、jarの中の.classを全て解析しているからです。
コンパイル時にはまだ実際に必要かどうかは判断できないですからね。

Eclipse4.5でimportの編成を行うと並び順が変わる

参考リンク

元ネタはこちら:

関連するバグレポートは、(上記回答にも書きましたが)こちら:

今回使用したソースはこちら(Mainクラスでimportソート順が見られます):

事象

Eclipse(4.4/4.5とも)のimportの並び順は Organize Imports で設定できるのですが、デフォルトでは以下のようになっています。

f:id:yukihaned:20151220164039p:plain

この設定のまま 4.5 で Source > Organize Imports (Ctrl+Shift+O; 日本語ではimportの編成、でしょうか)を行うと次のような並び順になります。

import java.net.HttpURLConnection;
import java.util.ArrayList;

import javax.swing.JFrame;

import org.w3c.dom.DOMException;

import com.ClassCom;

import a.ClassA;
import javaj.ClassJavaj;
import jp.mycompany.myproject.ClassJp;

日本語で説明するとこんな感じでしょうか。

  • 設定で順序が明示されているものはその順に並ぶ。
  • 設定で順序が明示されていないものは、明示されたパッケージの後ろに、アルファベット順で並ぶ。

次に 4.4 の場合です。

import java.net.HttpURLConnection;
import java.util.ArrayList;

import javaj.ClassJavaj;

import javax.swing.JFrame;

import jp.mycompany.myproject.ClassJp;

import org.w3c.dom.DOMException;

import a.ClassA;

import com.ClassCom;

こうして比較して見てみると、随分違いますね。
前述bug reportには "best match" という用語が何度か登場していて、特定のアルゴリズムを指す名称のような雰囲気があるのですが、具体的にどういうアルゴリズムなのかは検索しても分かりませんでした。
そこで実際に試してみたところ、並び替えた結果は次のようになっているようでした。

  • 設定で順序が明示されているものはその順に並ぶ。
  • 設定で順序が明示されていないものは、アルファベット順に並べたとき、直後にくる明示されたものの設定に従う。

今回の場合ですと、それぞれ、 javajjavaxjporgacom の設定に従っているわけですね。

対策

日本で使っていてこの問題に遭遇する頻度は jp パッケージが最も高いと思うのでこれを例に挙げると、 Java > Code Style > Organize Imports の設定で、 javaxorg の間に jp を追加しておけば、4.4の並び順が4.5でも再現できることになります。

アドバンス

そもそもEclipseのデフォルト設定がなぜこの順になっているかを考えると、

  • 標準的なパッケージほど先頭に置く
  • (逆に言うと)自作パッケージは最下部

という想定なのだと思われます。
ここで自作パッケージは com (とか org )しか考慮されていないのが非アメリカ人にとって問題だったのでしょう。
日本人としては、Organize Importsの設定で、最下部に jp が入っていれば問題が起きにくかったと言えます。

4.5の挙動はその意味では妥当だと思います。が、以前のコードに変更が入るとなると、すんなりとは受け入れられない場面もあることは容易に想像できますね…

teratailってどんななの?

teratail で週間1位を取りました!

f:id:yukihaned:20151220114358p:plain

…というわけでアカウント作って多分2週間くらいなんですが、少し感想を書いてみたいと思います。
ちなみに私が同類で他に利用しているサービスとして Stack Overflow日本語版(SO) がありまして、以下、念頭にSOと比較して…なんてのもあります。

簡潔に言うと

  • 宿題を丸投げしているような質問も比較的受け入れてくれる
  • 回答のスピードは早いことが多い、ただし、的を射た回答か/妥当性はあるのかというのは怪しいことも少なくない
  • 現時点では「プログラマ限定」的な広告の謳い文句によって、ある程度以上のリテラシは保たれているように思う

もうすこし詳しく、私が感じたteratailの特徴(主に回答者として)

  • 回答すれば得点を得られる*1
    • 本来「情報の追加・修正依頼」として書かれるべき内容が、回答として書かれがち(前者だと得点が得られない)。(「情報の追加・修正依頼」欄が目立たなさすぎる問題もありますが)
  • Wikipediaで言うところの「要出典」「独自研究」的な回答が少なくない
    • 質より量回答した方が得点を得やすいため。
  • 投票機能があまり適切に機能していない
    • これも回答するに当たって質より量へインセンティブを働かせる効果になっている。適当なことを書いてマイナス1票入ってもトータルで±0とかなので。
  • 質問者が適切だと思う回答(ベストアンサー)に付与する得点が高い
    • 分からない(から質問しているわけで)人がベストかどうか判断できるのだろうか?という問題。
    • 投票機能が機能していないのでベストアンサーが最も適切な回答であると誤解を招く(本来の意味は質問者の問題これで解決した、というだけ)。

利用していて個人的に最も気になったのが上で書いたうち「要出典」な回答*2。ベストアンサーなんて付いてると特に。
ここでツッコんでもおそらく質問者はもう興味無いだろうし、仮に回答者とfightになったら自分/回答者/コミュニティ誰も得しないし…とか考えてしまい、結局そのまま放置することに。
SOより質問及び回答の有効範囲やライフサイクルは限定的なのだ、と割り切るがほとんどです。

その他、サービス自体について

  • RSSフィードが無いのは非常に不便
  • モバイルページとPC用ページを切り替えるとログイン状態が想定と異なることになっている
    • 詳しく見たわけではないのですが、スマートフォンで見るときモバイル表示だと操作しづらいのでPCに切り替えたりその逆をやってると、さっきログイン状態だったのにログアウトしてる、ってことがよくあります。
  • ログアウト状態で書き込みを行うとログイン処理後書き込もうとしたメッセージがなくなる
    • 上記の予期せずログアウト状態になってるのと組み合わせるとかなり凶悪です…

後発のサービス(検索してみたところ2014年7月頃スタートしたようです)ならでは!みたいなところは無く、逆にちょっと残念な感じかな、と。
前節に記載した得点配分についても、もうちょっと工夫の余地はあるんじゃないかと考えます。

まとめ

teratailのファーストインプレッションを忘れないうちに書きとどめました。
総じて、何も書かないより変なことでも書いた方がまし、というような設計(得点設計)になっており、それが冒頭で述べた特徴につながっているのだと思います*3
利用者の参加に対する心理的ハードルは下がる代わりに、運営者の難易度は上がる調整ですね。

*1:SOでは回答しただけでは得られない

*2:こちらの言い回しを借りると、本来十分に「確認できる情報」であったとしても

*3:SOでは変なこと書くくらいなら何も書かないほうがましな設計になっていますね

「マークダウンする」

今年のモヤモヤコンピュータ(?)用語第1位です。

コードはマークダウンして記述してください。

某所で見かけた文章ですが、これを見つけて以来頭から離れません…(で、blogにでも書き出せば区切りつけられるかな、と)。

何がモヤモヤの原因か考えたのですが、次のような感じでしょうか。

  • 実際にやってほしいことは「マークアップする」ことであって、「マークダウンする」だと全く逆のように見える
  • Markdownは固有名詞なわけで、例えばはてなblogの記法で他の用語に差し替えると「はてなする」と同類
  • けどまあMarkdown記法でマークアップして欲しいんだな、ということは伝わる

現状「ググる(Googleする)」が普通に意味通じてるわけで、「マークダウンする」に違和感を持つのは単純に生まれてからの期間の長短の問題なんですかね…

メンバーが全てSerializableでないとシリアライズ出来ない…わけではない

スタックオーバーフローサイトからひっぱてきたネタ です。

問題

下記のような、 Child 型(Serializable をimplementsしていない)をフィールドとして持つクラス Parentシリアライズできるでしょうか?

class Parent implements Serializable {

    private Child child;

    // ...
}

class Child {
}

答え

シリアライズしようとしている対象オブジェクトの状態によります。
常にシリアライズ不能というわけではありません。

最も単純な例で言うと、 child フィールドが null であればシリアライズ時に NotSerializableException はスローされません。
また別の例としては、 Child のサブクラスで Serializable な型のインスタンスがセットされている場合も例外はスローされません。

コードサンプル

実行可能サンプルコードをこちら に置いています。