2015-08-23 YAPC::Asia 2015 のハッカソンでコピペ検出器っぽいオモチャを作りました


YAPC::Asia のハッカソンに初参加しました。今まではスピーカー(しかも年によっては選ばれた人だけ?)しか参加できなかったけど、今年はマイクロソフトさんと @myfinder さんのご好意によって、参加者でも参加できて本当に最高だと思う。

さてさて、表題の通りコピペ検出器、具体的には「似たような構造を持った Perl のソースファイルを探すプログラム」を作った。

正確には以前からいくつか試行錯誤していたけれど、なかなかうまくいかなかったのが、一応なんとか使えそうなレベルまでたどり着いた、という感じである。

基本的な考え方

ソースコードもある種の文章であり、文字列の塊である。(かどうか、本当は分からないけど、とりあえず僕はそう仮定した)。

なので、アルゴリズムとしては、「2つの文章の類似度を比較する」というのが基本戦略になる。文章あるいは文字列の類似度を比較する手段が候補になる。

候補0: mixi の Compiler::Tools::CopyPasteDetector(ダメじゃないハズなのだけど、ダメだった)

Perl プログラムのコピペの検出といえば、まず最初に候補に上がるのが、mixi さんのコピペ検出器Compiler::Tools::CopyPasteDetectorである。

こいつが使えれば、僕みたいな一般人が変なコード書かなくて済むので、一番良い。

ところが、、インストールは問題なくできたのだけれども、動かしてみたら、アプリのディレクトリの外のモジュールを use しているところで死んでしまい、「????」となった。へーしゃのプロダクトの構成が変すぎるせいなのだろうけど、これじゃあ動かせないし、動きが分からなすぎて怖いな、と思って使用を断念した。

さらに追記:

とのことで、作者の @goccy54さんから連絡いただきましたので、こっちも再度試してみますです。

候補1: 特徴ベクトルとコサイン類似度 (ダメだった)

既存のツールがダメなので、自分で書くしか無い。(一応調べたけど、他の事例とかプロダクトは無いハズ)

最初に検討したのが、特徴ベクトルを作って、コサイン類似度で比較する方法である。文章だと多分割と定番で、雑に作ってもそこそこ早くて精度も出る。

TF/IDF から特徴ベクトルを作って、コサイン類似度を計算する方法(定番だし、昔やったことあったので良さそうと思った)でやってみた。ソースコードはキーワードがいっぱいあるから、IDF がいい感じで効いてくれるのではないか、という期待があった。

で、やってみたところ、全然いい数字が出ない。どうしてかと思って、ベクトルを見てみたら、次元が非常に大きいのに、値はほとんど0のベクトルになっていた。これじゃぁ無理だ。。。別の方法を考えよう、と思った。(今思ったのだけど、候補2以降でやってるように、「トークン」ではなく「トークンの品詞」でやればこのアプローチも有効なのかもしれない)

候補2: 編集距離(結果は悪くなかったけど、速度とメモリ的にダメダメだった)

次に検討したのが、編集距離を比較するアルゴリズム。文字列やバイナリがどのくらい似ているか、違うかを算出するものである。「編集距離」とか「レーベンシュタインの編集距離」とかでググると色々出てくる。

簡単に説明すると、文字列を同じものにするために、何文字分の編集操作が必要かを計算するものである。

で、文字列(トークンそのもの)でやると大変そうなので、トークンの種別(たとえば「変数の宣言」)みたいな単位ごとに編集距離を出す方法でやってみた。数個のファイルで試した感じでは直感ともだいぶ一致するし、結果は概ね良好であった。

...速度とメモリ使用量以外は!

とりあえず 1ファイル分計算するのにも数秒くらいかかる。(定番で簡単なダイナミックプログラミングを使っているせいもある。論文に書いてあるような超早いアルゴリズムを使うと早くなる可能性はある)。またメモリ使用量がやばく、数GBまで達してしまう。(これもアルゴリズム変えればいけるのか?あと、現状のデータ構造がダメダメだからそれ直せばもうちょいマシになるのかも) Test::LeakTrace でリークして無いか確認したが、どうやらリークではないらしい。完全にやばい。

と、いうわけでこの方法もお蔵入りになった。(一応実装は残してある)

候補3: 出現頻度(とりあえずコレを採用している)

上記のような苦労を YAPC::Asia 以前にしていて、八方塞がりになっていたので、YAPCの終了後飲み会の道中 で @hide_o_55さんに相談してみたら、「出現頻度にして、 bigram とかコードの場所ごとに重み付けするとかやってみたら?」と言われたので、とりあえず出現頻度の bigram とかその周辺を試してみた。(これを今日のハッカソンでやっていた)

ぱっと見、編集距離とだいたい同じような結果が出て、めっちゃ早い。

trigram とか色々試したけど、あんまり代わり映えしない(速度も精度も)ので、適当でいいや、と思って出現頻度の bigram をとっている。へーしゃのプロダクトにさっきかけてみたら、数分で終わったので、これなら許容範囲である。

そもそも何でそんなもの作ったの?

基本的にはリファクタリングをちゃんとやるため、である。

Github の Ben Lavender さんの、YAPC 本編トークAdventures in Refactoringでも、冒頭で「どういうリファクタリングが良いか」みたいなことを言っていた。僕のところでも、リファクタリングが独りよがりなものにならないように、最近いくつかのメトリクスを取り始めている(行数とか複雑度とかカバレッジとか)。

で、その一環でコードのダメさの指標の一つとして、「コピペ」とか「コピペっぽさ」みたいなのを測れるといいなぁ、と思っていて、ここ1ヶ月くらい(業務の合間に少しずつ)作業していた。

で、コイツが出す数値はあてになるの?

タイトルに「オモチャ」って書いたし、あてになるわけないでしょう。こんな雑な手法でコピペが見つかるなら苦労は無いと思う。ただ、全く意味が無いかというと、そんな事はなくて、本当に完全にコピペしたら見つけれるし、コピペじゃなくても、構造が似てるやつを見つけてくれる可能性はあるから、参考にはなるはず。github の p-r フックに入れようと思っていて、その際に「既存のコレと似てるけどどうよ」って提示されて、そこで人間様がちゃんと考える事が大事だと思っている。

で、成果物は?

p5-App-CopyPasteDetector

まだまだ荒削りだし、ドキュメントとかちゃんと書いて無いけど、一応使えるはずです。(インストールすると cpd ってコマンドが入るのでそれを使う。)

会社の CI サーバとか pull request フックであれこれする物体とか、今後やっていこうと思うので、そのついでにもう少し改善されるかも。

と、いうわけで、現場からは以上です。YAPC の感想ブログ書いて無いので、まだ僕の YAPC は終わってい無いのですが、感想ブログはきっと明日以降になりそうだな。。。



2015-08-22 YAPC::Asia 2015 1日目(前夜祭) の感想


YAPC::Asia 2015、お疲れ様でした。今年もとても楽しかったです。初日(前夜祭)のトークの雑な感想文です。

PHP帝国の逆襲!(を願うPHPerが話す最近のPHPについてのクイックツアー PHP7対応版)(uzulla さん)

僕はPHP 普段書かないのだけど、uzulla さんの PHP の話は昨年の YAPC や Hachioji.pm で聞いていてとても面白いので今年も聞いてみた。すごいテンポで、膨大なトピックを分かりやすく面白く説明していて凄かった。

はてなブックマークのトピックページの裏側 (skozawa さん)

以前見てきた、はてなのセミナー(Hatena Engineer Seminar #4)で見てきたやつの続きっぽい感じだった。前回よりも細かいトピックが増えていて、地道に改善されているのかなぁ、と思った。

技術ブログを書くことについて語るときに僕の語ること (yuuki さん)

ゆううきさんの日本語力(?という表現が適切なのか分からないけど他にいい表現が思いつかない)が、半端ないと思った。前半のタイトルの話とかは僕は全然考えたことがなかったからとても面白かった。



2015-07-25 CD のリッピング環境を見直した話


はじめに

僕はそんなに音楽をたくさん聴く方ではないのだけど、一応音楽が聴ける環境は欲しいところです。最近まで結構異常な環境で リッピングとスマホへの転送をやっていたのだけど、それを改善できたので、その辺の顛末を書きます。

移行前の環境

Ubuntu で Banshee でリッピングして、スマホにそのまま転送していました。環境的な問題は特になかったのだけど、 ソフトウェア的に色々ダメダメで、CDDB がアホで全然データ取れないのと、スマホに転送すると必ず Banshee がハングしてしまうのが、 「どうなのよそれは」、と思っていました。

CDDB がアホアホなのが特に致命的で、CD 3枚くらいリッピングしようとするとその分のデータを手打ちしなければならず、発狂しそうになります。

ミルキィの CD であれば、(頻度的にも気持ち的にも)心を込めて手打ちしても良いのですが、 そうするとミルキィ以外の CD をリッピングすることができなくなってしまい、いくらそんなに音楽聴かないといっても、ちょっと良くないなぁ、と思っていたのでした。

ってか、曲の情報手打ちとか、Rio の mp3 プレーヤー使ってた頃だったらいざ知らず、今2015年だよ!どういう事だよ!と思い色々調べ始めたのでした。

移行先の環境

Linux でまともな CDDB につなげればそれで問題なかったのだけど、色々調べたけどうまくいきそうになかったので、普段使っている Mac に 移行する事に決めました。Mac のソフトも軽く調べましたが、ベタだけどやっぱり iTunes が良さそうだなと思い、iTunes を移行のターゲットにしました。

移行について

Linux でファイル共有(samba)をかけて、Mac でマウントします。で、iTunes でインポートします。よっしゃ、これでおしまい、簡単だぜ!

...って最初は思っていました。

移行されない曲について

ところが、いくつか移行されない曲があることにすぐに気づきました。

Linux に入っていたのはもともと、iPod から吸い出したやつが大半だったので、m4a(AAC)のファイルは問題なくこれでインポートできていました。しかし、Banshee で 取り込んだファイルは ogg 形式だったので、これが読めなくて、移行できていませんでした。

このままではミルキィやみもりんの曲を聴くことができません。大ピンチです。

ogg から AACへの変換について

という訳で、ogg を AAC に変換するソフトを探しました。すると、soundKonverterというやつで 簡単にできそうだったので、ogg 形式(Banshee で取り込んだ CD)のアルバムをピックアップして、これで変換しました。

でインポートはさっきと同じ手順。共有かけて iTunes でインポート。

スマホへの転送について

無事インポートされたので、あとはスマホへの転送手段を確立できれば OK です。

あんまりちゃんと調べていないのですが、iTunes から Android スマホへの転送は、iSyncr というソフトがどうやら定番らしいので、それを使っています。 なんか日本語が怪しいし動作も怪しいし、これが定番ってどういうことだよオイオイ、と思うのですが、そんなもんなんですかね????

音楽そんなにヘビーに聞かないし、僕は林檎信者じゃないのだけれども、それでも iPhone が欲しくなりますね。。。

移行してみて

まともな CDDB ってマジ便利だなー、って思いました。いや本当に。

レキシテキケーイが色々あって、Ubuntu でリッピングせざるを得ない感じになっていたので、仕方ないと思っていたのですが、 こんなに便利だったら、Mac 買った時にすぐにやっておくべきだったなぁと思ったのでした。

現場からは以上です。



2015-07-14 吉祥寺.pmで「Perl とアジャイル開発」という LT をしてきました


先週末の 7/10 に吉祥寺.pm #4 で LT をしてきました。表記の通り、Perl とアジャイル開発というか、僕が 普段仕事でやってるスクラムの話とそれを支える Perl スクリプトとかの話です。

資料はこちら

懇親会で、「ちゃんとバーンダウンができてて(というか進捗してる的な意味かな?)すごい」みたいな事を言われたのですが、 現状も当初の計画とはだいぶずれているし、前にやったプロジェクト2つくらいは辛い水平飛行を続けたままお蔵入りになったりしてたりしてて、 アジャイル開発に限らず、システム開発って難しいなコンチクショウ、というのが正直な感想であります。

Perl 以外のこういう話、する機会があんまりなかった、というか今回が初めてだったので、グダグダかつ訳わからん説明になっていた気がしなくも ないのですが、機会があればぜひまた発表したいな、と思います。

あと、アジャイル開発周りでは、今回紹介したバーンダウンの話とか、リリーススケジュールについてとか、少々ネタというか、思うところがあるので、 それは別エントリとして今後書いていくつもりです。



2015-06-14 Hachioji.pm #51 に行ってきた


本日 6/13 は Hachioji.pm #51でした。

餃子とか野菜とかを食べつつ、いろんな話をしていた気がします。

僕のスライドはこちら。

最近考えている事と、それに付随する悩ましい話です。リファクタリングのいい指標や、それを測るツールがあれば是非是非教えていただきたいところです。



2015-05-27 こういうふうに、書きたい、と思う


あなたの目前にクソコードが広がっているとする。

実力のないプログラマであれば、それがクソなのかそうでないのか判断はできない。そこそこ実力があって、良識のあるプログラマであれば、クソコードを嘆くであろう。

で、問題はここから。

目の前にクソコードがある。しかしそのクソコードはそこそこ実績のあるサービスで、そこそこ収益をあげている、としよう。

そうすると、単純にクソだからといってサービスを捨てたり機能を減らしたりはできない。「リファクタリングしよう!」というのは簡単だけど、クソコードが相手だとテストも不十分だったりするから、それは必要ではあるけれど、やっぱり怖い。「そういう職場はマジやばいので、全力で逃げるべき」っていうのは場合によっては真ではあるけれど、IT も Web も、もうそれなりに歴史のあるものだから、まったくレガシーがない環境はたぶんありえないし、完全新規なベンチャーであれば、未来のレガシーをつくるのは多分そこから逃げたあなた、だ。

で、こういうとき、どうするべきか、僕も答えはないのだけれど、現状に対して、「こういう風に書きたい、直したい」っていう思いが大事なのかな、って思っている。現状がどれだけクソだったとしても、それをどうしたいか、どう直したいか、自分は今のプロダクトを本当はどういう風に書きたいか、ってのを示すことができなかったら、多分それは現状より悪い。

現状がクソであることに文句を言う人、どう悪いか、まで言語化できる人は数多くいるけれども、どう直したいか、どう書きたいか、ってところまで踏み込める人はあまりいないし、そこまで踏み込んでくれる人が増えてくれたら世界はもうちょっと良くなるのかもしれないなぁ、ってちょっと思ったりした。



2015-04-25 今更 screen に入門してみた


プロローグ

screen/tmux を長いこと使っていなかった。

  1. 使ってみようと思ってネットの記事とか調べ始める
  2. 分割とか別にわりとどうでもよくね?と思う
  3. とりあえず、screen を入れる
  4. Ctrl-a を封印されて死ぬ(emacs ユーザなので)
  5. もう二度と使うか!と思ってアンインストール

みたいなループを2年毎に繰り返していた。

僕はおじさんなので、端末は基本的に 80x24 でないと気持ち悪いし、だから分割とかしない。 (emacs はホスト側のやつ最大化して使うけど、こっちも分割使ってないので、分割のメリットが全くわからない。 何か見ながら作業する場合はふつうにバッファ切り替えればいいでしょ?くらいに思っている)

今回、某所で話していたら、「便利な nohup くらいでしか使ってない」みたいな話を聞いて、「逆にそれくらいならいいかも、いけるかも」と思って、 最終的に screen 導入に至ったので、その経緯なんかを書いてみようと思う。

インストール

会社の Linux 開発機に screen が入ってた(tmuxは入ってなかった)ので、とりあえずそれを使ってみることにする。 mac はパッケージ(homebrew)で入れた(気がする。最初から入ってたかも)。

プレフィックスキーについて悩む

デフォルトのプレフィックスキーが Ctrl-a なのがまじで理解できない。これに決めたやつは死んだほうがいいとマジで思う。たくさんの emacs 使いを 惑わせた罪は重い。(ってのは言い過ぎにしても、emacs ユーザじゃなくても、bash とか使ってる人はふつう Ctrl-a 使うでしょ?まじ意味がわからない)

で、キーバインド変えようと思うのだけど、この設定方法がマジで意味がわからない。Ctrl-s とか使わないから、振ろうかとおもったら、うまくいかないし (シェルだか端末だかが先に横取りしちゃうのかもな。そっち直せばいけるのかも)、「Ctrl-; とか、いいんじゃね?」と思ったのだけど、どうやって .screenrc 書くと 設定できるのかマジでわからない(^;^;だとうまくいかなかった)

ぐぐると、Ctrl-z と Ctrl-t の事例ばかりひっかかり、マニュアルを見ても、いまいち設定の方法がわからない。

そのへんの試行錯誤

Ctrl-r 使わないし、そこそこ押しやすそうだから、使おうかと思ったら、今まで使っていないだけで、ふつうに便利機能だった。勉強になった。

最終的に Ctrl-u にした。bash の文字削除は Ctrl-d/Ctrl-k/Ctrl-h くらいしか使わないので、潰してもいいや、と思った。vi の操作にも影響なさそうだし。

シェルの設定をする

とりあえず、プロンプトに、ウインドウの番号をいれるか、と思って、こんな感じの bash 関数を定義した。

__screen_window ()
{
    if [ -n "$WINDOW" ] ; then
        printf "$WINDOW:"
    else
        printf ""
    fi
}

で、PS1$(__screen_window) みたいにして呼び出せば良い。詳細は以前書いた。

今のプロンプトはこんな感じになっている。

ウインドウ名が bash なのがイマイチだと思って、いろいろ調べると、カレントディレクトリにするのが定番っぽいので、その設定を入れる。

# screen の場合のみ。ウィンドウ名をカレントディレクトリにする
if [ $TERM == 'screen' ]; then
  PS1=${PS1}'\[\033k\W\033\\\]'
fi

ホイールマウスの挙動がおかしくて悩む

ホイールでは端末がスクロールして欲しいのに、screen を有効にすると、ヒストリをなぜかたどるようになる(矢印の上キーと同じ動作になるっぽい?)。

これはめっちゃ使いにくい、というか、挙動を勝手に変えるなクソが、と思うので元の挙動と同じになるようにする。

使っている機能

基本的には新しいウィンドウを作るのと、そのウインドウへの移動、ウインドウの名称変更(リモートサーバに繋いだ時とか、reply 起動した時とか)くらいしか使っていない。 全然たいしたことやってないけど、これだけでも十分便利だった。

使ってみて

  • 普通にタブとして便利だった。
    • 端末のタブを使わなくなってしまったので、Ctrl-t に割り当てもアリなのかも
  • リモートサーバにつなぐときのベストプラクティスがまだよくわからん
    • 回線切断とか考えると、リモート側でも screen 起動しておく方がいいのかな
    • ローカル側はあくまでもただのタブ、みたいな感じ
  • detach するのはいいのか悪いのか今の所わからない
    • 幸か不幸か、回線切断を食らっていないため
    • どうせ attach し直しとか無理でしょ?という意見もあるけど、どうなんだろ?

と、いうわけで、設定はまだまだ見直しが必要だし、もう少し使い方も覚えていかなくてはダメだけど、 とりあえず軌道に乗った感じなので、ゆるゆると使っていこうかなぁ、と思っている次第。

追記

なるほどー。Ctrl-z 2連打すれば通常の Ctrl-z と同じ動作になるわけだから、それを使えば良い、と。Ctrl-z の使用頻度を考えるとそれはそれでアリなのかもしれないです。



2015-04-21 本を読んでいない


割と読書が好きで、技術書もそれ以外のも結構読む方で、Booklogで見ると、 だいたい年間で30〜50冊くらい本を読んでいるらしい。漫画とかラノベとかも含めてね。

で、2015年の読書状況を見てみると、4カ月弱で5冊しか読んでなくて、これ明らかにやばいペースなのだけど、 なんでこういう状況なのかな?とか考えてみたら、1月から「探偵歌劇ミルキィホームズTD」やってたせいだ。どう考えても。

余暇時間はほぼすべて、ミルキィの伏線チェックや謎解きに使われていたし、元ネタの調査の一貫で「時計仕掛けのオレンジ」を見たりとか、 そんなことしていたので、そりゃまあそうなるよな、という感じ。

僕の探偵業はまだ終わっていないのですが、1〜3月に比べたらだいぶ頻度は下がってきたので、そろそろちゃんと読書したほうが良さそうである。



2015-04-18 Hachioji.pm #49 に行ってきた


本日 4/18 は Hachioji.pm #49でした。

昨日 Kichijoji.pm に参加したら「久しぶり」って言われて、「あれ?そうだっけ?」って思ったけど、 たしかに、はちぴー久しぶりだし、その前の技術系のイベントははてなのセミナー行ったくらいだから、たしかに久しぶりであった。

タイ料理を食べつつ、いろんな話をしていた気がします。

僕のスライドはこちら。

一つ補足しておくと、基本的には O/R Mapper の処理だけで足りているのだけど、たまにめっちゃ難しい処理を 書かないといけないことがあって、そういうときに継承ができなくてまじつらい、みたいなのを解消したくて いろいろ考えていた。あと、これは僕一人の成果ではなくて、僕のチーム成果であることも補足しておかねばならない。

あとそのあと、いろいろフィードバックをもらった結果、これは「データマッパーなんじゃね?」という結論になった。 フルスタックなデータマッパーとは多分ちょっと違うのだけど、たしかに機能的にはデータマッパーとしておくのがいいのかな。 こういうの難しいし、あんまり変なこと書くと燃えそうだから怖いな、と思う今日このごろです。

毎度書いている気がしますが、はちぴーはゆるふわな話からアニメの話から、ちゃんとした技術の話まで色々できて楽しくていいですね。 今後も参加したいです。



2015-04-11 プラスティック・メモリーズがやばい


こんばんは、ミルキィ難民のおじさんです。

難民ではありますが、今期のプラスティック・メモリーズがやばいです。1話だとニーナが健気で可愛くて、 おじさんの涙腺はマジで限界だ。

この作品も、結構色々伏線を張っているっぽくて、とりあえず1話を見ていて気になったのは下記あたり。

  • 回収されたギフティアの様子がまるで死体のように扱われてるのなんで?
  • アイラは寿命が近い?あるいは、一度記憶を消してる?
  • アイラ人間よりもやたら人間っぽいのはそういう演出なのか、何かあるのか
  • 最後、アイラはニーナに何をしゃべったのだろうか?

んでね、思うところが色々あるのだけど。僕が生きている間に実現できるかどうか分からないけど、ギフティアみたいな、 人間的な感情を持った機械ってのはいつか出てくる、と思う。そういう時代が来た時、機械に対して、人間と同じように接することができるか、 あるいは人間と同じように接して良いのか、みたいな問題が絶対に起こる。

で、僕がもしその時代に立ち会ったら、どう思うのだろう、って考えたのだけど、僕はニーナの覚悟とか最後のシーンとか見て泣いてたので、 多分機械も人間も関係ないんだろうな、って思った。少なくとも嫌いな人間より、好きな機械を大切にするんじゃないか、そもそもそういう区別 すら無いのかもしれない、とか、そんなことをアレコレ考えたりしていた。