平均点を上げると飛び抜けて面白いものはできない

最近「有吉弘行のSUNDAY NIGHT DREAMER」をよく聞いてるんだけど、アンジャッシュの小嶋さんがゲストの回での話が興味深かった。

話の流れとしては、有吉さんが人力車の芸人に面白い人間が多いと小嶋さんに話を振ったところ、最近は面白い芸人が出てこなくなってきたと小嶋さんが嘆いていたところから話が始まる。その理由は芸人を管理している人間が変わったことによる弊害らしく、面白いか面白く無いかの判断だけをする人だったのが、ネタに対して変えたほうが良い点も指摘する人間に変わったのが原因だそうだ。なぜそうなるかというと、ネタをダメ出しされた芸人がダメ出しされた箇所をちゃんと変更してくるせいで今まで誰もやったことがないような飛び抜けたネタを作ってくる人間がいなくなってしまったらしい。

これって非常に興味深い話だと思う。

万人が面白いものって実は存在しなくて誰かが面白ければ誰かが面白くないし、どこかの層に強烈に突き刺さるネタっていうのはどこかの層に強烈に嫌われるんだと思う。誰かのフィルターを通せば通すほど丸くなって突き刺さるものは削られて万人が50点をつけるものが出来上がるんだろう。

万人が50点をつけるものが目指すのがいいのか、それとも誰かが100点をつけるけど誰かが−100点をつけるものがいいのかはケースバイケースなんだろうけど、飛び抜けて面白いものっていうのは万人が50点をつけるものではないんだろう。平均点を上げようと頑張れば頑張るほど尖って面白かったものが丸くなって面白くなくなり、結局平均的で汎用な面白くないものができてしまうというのは感慨深いものだと思う。

社内フロントエンドチューニング大会の感想を書いてみる

インフラチューニングに続いてフロントエンドチューニングにも参加したので感想を書いてみます。

ちなみにトップの人のブログはこれ

大会の中身

大会の中身は以下の様なもの。

  • 渡されたGithubリポジトリのHTMLサイトを出来るだけ軽くする
  • リポジトリにプッシュすると自動的にスコアを集計
  • 見た目を崩してはいけない
  • 同じ動作をしなければいけない

この条件でスコアを競います。スコアは以下のタイトルがついていました(どういった基準なのかの詳細は説明がなく推測で判断するしか無い)

  • HTMLファイルサイズ
  • CSSファイルサイズ
  • JavaScriptファイルサイズ
  • 画像ファイルサイズ
  • リクエスト数
  • DOM要素数

やったことを順番に

今回も遠隔地の参加だったのでレギュレーションを軽く読んでGithubにつないでファイルをダウンロード。説明を見た感じファイルをどれだけ軽く出来るかの勝負みたいだったので、とりあえず時間がかかりそうなImageOptimに放り込んで画像ファイルを軽くしてみる。その間にファイルを見てみるとJSとかCSSとか死ぬほど読み込んでる。jquery-uiとかbootstrapとか色々読み込んでるけど、動きを変えちゃ駄目なら削らないほうが無難だろうとこのへんはそのまま進む

触らないほうが無難だと思ったライブラリのJSとCSSたちをまとめて圧縮して上げてみるも何故かエラー。。。CSSの改行とコメント削ってるだけなのになんでエラーになるんだよと思いながらもしょうがないから地道に個別に圧縮して最後にくっつけることにする。あとで聞いたらCSSにバグが仕込まれていたらしくそのせいなんだろう。その時は気づかなかったからライブラリ関連のファイルを個別圧縮して、画像ファイルを軽くしたものを上げてとりあえず満足。

次にcoffeescriptが使ってあったのだけど、jsで動的にコンパイルしていたのでこんな無駄なものないだろうとコンパイルしたものを上げてcoffeescriptを動的コンパイルしているjsファイルを削除。coffeescriptはよくわからないけどjsの中身を見ながら何やってるのかを確認すると、ajaxでjsonファイルを取ってきてテンプレートを使って動的にDOMを構築しているっぽい。DOM要素数がスコアにあるからココらへんをいじくったほうがいいのかなぁと調査を開始。

見てみると40個ぐらい同じテンプレートから作られてる要素を発見。ここを変更すればDOMが一気に削減できると綺麗にdivでくくってあるものをガッツリ削ってCSSで見た目を整えてみる。これでDOM要素が減ったけどあまり変わらず。次何するかなーとぼーっと眺める。

どういう感じで作られてるのかとHTMLのClass名でCSSをGrepをかけると結構使ってない奴がある。これを削らないといけないのかと気付き使っていないClassが使われているDOMをガンガン削っていく。Grep→使ってない→削るというすごい地味な作業を繰り返す。後で調べたらCSSの要素で使っていないものを見つけるとかいう便利なライブラリがあるらしいですね。それ使えばよかった。。。

ひと通り削り終わって次何しようかと眺めていると、修正前と修正後の画像が完全に一致していることに気づく。もうちょっと画像を粗く圧縮すればスコア上がるんじゃね?ともう一回ImageOptimに放り込んでみるけどあまり変わらない。もうちょっと圧縮できるライブラリ無いのかなと探したところpngquantがよさ気。こいつを使って画像を更に圧縮して上げてみると画像ファイルが結構軽くなった。

リクエスト数もスコアにあるんでリクエスト数を減らしたいなぁと思いCSS Spriteでもやるかと思ったけど、CSS変更するのがだるい。でも画像ファイルをいっぱいダウンロードしてるのでbase64にしてそれをimgタグに無理やり読み込ませるように変更してみる。タグを削ったテンプレートを作成しているjsonファイルにbase64データを入れるところを作って画像ファイルを全部base64にして読み込ませたものを上げてみたところリクエスト数は減ったけど画像ファイルの劣化が激しく修正前の画像との差分がギリギリラインまで上がってしまった。これ以上画像ファイルをどうにかすることはできないので画像ファイル関連は諦める。

ファイルサイズ下げるならgzip化したほうが楽じゃないかとgzip化を試してみる。ヘッダを見るとExpressを使ってサーバは動いているようなのでExpressで.htaccessとか使えないかと調べてみたけど無理っぽい。色々やってみたけどgzipで読み込ませるのは無理っぽいので諦める。

そうこうしているうちに競技時間の終わりが近づいてきたので今まで圧縮していなかったmain.jsとかindex.htmlとかを圧縮してcss/jsファイルを1Fileにまとめて競技終了。

総評

トップの人との違いを見てみると最初からcss/jsの圧縮をしてしまったのが駄目だったみたいですね。フロントエンドチューニングっていうぐらいだからmain.jsで色々ごちゃごちゃ動かしててそれを削るのかと思ったけど、いらないjs/cssが読み込まれている可能性を考えなかったのが一番の敗因っぽいです。本来ならCSSの使っていない要素をbootstrapから削ったりとか、jsの使っていない関数を無理やり削ったりとかしてあげればもうちょっとスコアは上がるんでしょうけど、その時閃かなかったからだめですね。業務でライブラリの使ってない関数を削るとかライブラリのバージョンが上がる毎に手を入れないといけなくなるからやらないせいで頭が回らなかったと言い訳。

とりあえず、インフラチューニングよりも検討できたんじゃないでしょうか。こうやって色々参加すると自分が足りない点がわかって楽しいですね。次回があるのであればもうちょっと勉強して参加しようと思います。

社内インフラチューニング大会の感想を書いてみる

社内エンジニアのインフラチューニング大会があったので感想を書いてみます。

大会の中身

チューニング大会の中身としては以下の様なもの。

  • セットアップされているMediaWikiをとにかく早くする
  • スコアの集計方法は明かされていないが、随時自分のスコアを確認できるページがある
  • AWSのインスタンスを4台を使っていい
  • 既存のプログラムに手を加えてはいけない
  • 全てをキャッシュにして静的化するなどのデータ更新を確認できないのは駄目
  • 他の人間に攻撃して遅くするとかは駄目

この枠組の中でどれだけ早く出来るか?を競っていたのですがインフラエンジニアでも何でもない僕が戦うにはレベルが高すぎました。

やったことを順番に

遠隔地での参加だったので説明をよく聞くこともできずにレギュレーションの資料とサーバの資料(IPとログインID)を渡されたのでとりあえずhttpでアクセスしてみるかとブラウザからアクセスしてみてが404。ルートが違うのかと思ってapacheのコンフィグファイルとか見てルートを合わせてみたけど変わらず404・・・。なんだこれと思ったら、apacheが起動されてないだけだった。ここからスタートなのかとしょっぱなからつまずく先行き不安な展開。。。

起動してブラウザでアクセスしてみるとWikiページが表示された。けどものすごい重い。たしかPHPを激速にするモジュールが合ったなぁと調べたところeAcceleratorが早いってGoogle先生がおっしゃっているのでeAcceleratorを入れてみる。eAcceleratorが入った状態で立ち上げなおしてアクセスしてみるとまさかの500エラー・・・。ちょっと調べてみてわからなさそうだったのでAPCへと変更。こっちはすんなりと起動して大体スコアが倍近くまで上がったのでちょっと満足する。

既存プログラムをいじれないならあとはMySQLだろとSlowQueryを吐き出すように設定してみると3秒近くかかっているクエリがあることがわかる。こいつをどうにかしようとexplain見てindexを確認してみたもののindex的に間違いはなさそう。しょうがないからinnodbのメモリ量とかクエリキャッシュとか入れてみたがスコアは全然変わらない。そういえばCPU使用率を見てなかったなと確認したところ、WikiにアクセスがあるとMySQLが150%ぐらいCPUを使っている。。。MySQLがボトルネックなのはわかったのでこいつをどうにかしようと考えていると、上位のスコア5万とかなっていて僕のスコア(2000ぐらい)と1桁違ってたのでなにがしかの抜け道があるんだろうと推測。

もう一度SlowQueryのログを見てみると重いクエリが30万件ぐらいから絞り込んでいることがわかる。これindexおかしいだろうと片っ端からindexを貼っては消してを繰り返してみるも全然早くならない。調べてみるとGroup ByとOrder Byのdescを指定するとindexはうまくきかないよって記事を見つける。これが原因かとわかったものの解決策はサブクエリを使いましょうとかそんなものなんで既存プログラムをいじれないからどうしようもない。。。やけっぱちでMySQLのバージョンが5.5だったので5.6系にあげてみようと色々試してみるが失敗。ファイルがconflictを起こしてるとエラーが出てうまく上がらない。ファイル消して無理やり上げてやろうかとも考えたが壊れてしまったら復旧できる自信がなかったので諦める。

そういえば4台インスタンスを配られてるってことは負荷分散すべきなんだよなと頭を切り替えてMySQL Clusterを導入してみようと試行錯誤してみるも既存プログラムいじれないならどうしようもないなぁとはたと気付きやめる。全てをキャッシュにして静的コンテンツを返答させるのは禁止と書いてあるけど全てじゃなければいいのかなとApacheのアクセスログを確認してスコアの集計に使っているURLを抽出してみる。アクセスを確認するにPOSTとGETを交互に送っているみたいで、POSTでページを更新してちゃんと更新されているかをGETで確認しているとスコア計測のPGを推測してみたが、それならキャッシュ効かせた時点でアウトじゃね・・・。そうは言うものの、他にやることも思いつかなかったのでapacheのdisk cacheを導入してみたけど全くスコアは変わらない。

やっぱりMySQLがボトルネックだよなぁとMySQL Clusterを導入すべきなのか?とか考えながらも時間がねぇよなぁとちょろちょろと他の設定をいじっている間にタイムアップ。結果としては中の下ぐらいのポジションで最初のAPCを入れてからほぼスコアが変わっていないという散々な結果。。。

総評

インフラエンジニアってすげーなぁと思いつつも、勉強不足を痛感しました。スコアが1桁違う人達はどうもnginxのproxy機能を使ってほぼキャッシュで返していたらしい。それってデータの更新ってどうなの?って思ったけど、expireの時間を短くすることで対応したのかなぁとか想像。さらに終わったあとに既存プログラムは触っちゃいけないけどMediaWikiの設定ファイルであれば触ってよかったってことがわかり、それならもうちょっとやることあったのかなぁとか思いました。遠隔地での参加だったので会場の雰囲気を味わえなかったのはちょっと残念ではありましたが、終わった感想としては面白かったの一言に尽きますね。自分の勉強不足も分かりますし、社会人になってきっちりと順位が出るような試験ってなかなか無いので定期的にこういうコンテストがあると面白いと思いました。

AndroidStudioでandroidannotationsを使う

毎回ビルド環境を渡して作ってもらうのはだるいのでGradleを使いたくなり、EclipseからAndroidStudioへと変えてみた。その時に作業したandroidannotationsでの変更点

基本的に↓のサイトを参考にすればよい。

で、annotationが効いてファイルが作成されているにもかかわらずリビルドでエラーが出る場合があるけど、無視してデバッグしたらなぜか動いた。

リビルドとパスの解決方法が違うのかなぁと勝手に推測してる。

更に別のもGradleで入れてると以下のエラーが出る場合がある。

“duplicate files during packaging of APK”

これは以下を追加すれば動く。

android { packagingOptions { exclude ‘META-INF/DEPENDENCIES.txt’ exclude ‘META-INF/LICENSE.txt’ exclude ‘META-INF/NOTICE.txt’ exclude ‘META-INF/NOTICE’ exclude ‘META-INF/LICENSE’ exclude ‘META-INF/DEPENDENCIES’ exclude ‘META-INF/notice.txt’ exclude ‘META-INF/license.txt’ exclude ‘META-INF/dependencies.txt’ exclude ‘META-INF/LGPL2.1’ } }

ここに載ってるけど、AndroidStudioのバグらしい。

0.7で治るらしいので心待ちにしましょう

「出会い系アプリに関する物議」を読んで作っている側が思うこと

読みました。

仕事で健全で真面目な出会い系を作っている立場から発言させてもらうと本来の意味での出会い系ではないアプリ等は迷惑極まりないです。

記事内にも記載されていますが掲示板等の多対1のアプリは本来の意味での出会い系アプリではありません。出会い系アプリとして作成するには警察への届け出も必要ですし、何も起きないように犯罪をほのめかす発言や売春をほのめかす発言等はできないようになっています。また、犯罪が起きた後に誰が何をしたかをわかるようにログ等もきっちりとります。ちゃんとやっているところはちゃんとやって、ユーザが安全に使える環境を作ることに多大な労力を払っていますが、どこか一つでも訳の分からない本来の意味での出会い系ではないアプリで犯罪が起きると「やっぱり出会い系は危ない」という話題が上がってしまうのは迷惑な話です。

出会い系での悪いイメージが払拭される日はいつか来るんでしょうかねぇ。本来の意味で「出会い」は悪いことではないと想います。男女が出会わなければ子孫は反映しないわけですし、技術の進化によってみんなが使うツールが変われば出会いの方式が変わっても何ら問題は無いと思うんですが、たった一握りの自分の利益しか優先しない業者がリリースしてしまったアプリと、それを使用するユーザの中でもたった一握りのブレーキの効かない人間によって、本来は歓迎すべきツールが忌むべきツールになるのは作っている側からすると寂しい限りです。

インターネットが普及しだしてまだ10数年ですし、法整備が間に合わないのはあたりまえだと思います。開発者という立場は法の隙間を縫えばなんでもできてしまう立場なのかもしれませんが、法の隙間を狙って使う側のことを無視して自分の儲けのみを考えて稼ぐようなことはせずに、作ったコンテンツでみんなが安全に楽しんでもらえることを念頭にがんばっていけば楽しい未来が待っているんじゃないでしょうかね。開発者も経営者も全て善人なわけではないので法で制御される前に稼ぐだけ稼いでしまえという人間によってこれ以上出会い系という場所を荒らさないことを祈るばかりです。

nodeで「Cannot read property ‘secure’ of undefined」が出力される

node.jsで以下のエラーメッセージが出た

Cannot read property ‘secure’ of undefined

理由をググっていたらsessionに直接値を入れているのがまずいらしい

req.session = {
    hogehoge: hugahuga
}

ちゃんと1つづつ値を入れてやれば問題ない

req.session.hogehoge = hugahuga

mongoose#queryでsortのする

調べてたら引っかかったし、ブコメでも同じようにハマっている人がいるようなので回答を。

Word.find().sort([['created','ascending']]).each(function(doc){
  console.log(doc);
});

ちゃんと指定しているはずなんだけどなぁ。。この辺の原因分かる方は教えてくれると助かります。

この書き方だと引数が違いますし、Model.find()で返答されるものはMogoose#Queryです。なので、eachメソッドも存在しません。

ドキュメントは以下。

// sort by "field" ascending and "test" descending
query.sort({ field: 'asc', test: -1 });

// equivalent
query.sort('field -test');

なので、この形で記載するなら以下のようになります。

// 連想配列
Word.find().sort({'created','ascending'}).exec(function(err, doc){
  console.log(doc);
});
// 文字列
Word.find().sort('created').exec(function(err, doc){
  console.log(doc);
});

バージョンが違うのかもしれませんけど、3.8.0だと上記のようにすれば動くと思います。

と、書いてみたものの伝わるのかなー。

proguardを使って難読化

ちょっとハマったのでメモ代わりに。

ファイルの指定

project.propertiesに以下の一行を付け加えましょう。検索で引っかかるのproguard.cfgが多いけど、最新だとproguard-project.txtって名前になっているのでこっちを指定してあげないといけない。

proguard.config=proguard-project.txt

除外ファイルの設定

ライブラリとかほかから持ってきたものに関しては基本難読化しないほうがいいので、難読化から外す。以下の様な記載方法

-keep class com.google.gson.** { *; }

GSONを使っている場合

ここが一番ハマったんだけど、GSONを使っている場合は解析用のClassも難読化から外さないとうまく動かない。難読化は中身ごと外さないといけないんで、以下の様な記述が必要。一つづつ指定するのが面倒なのでpackageで一括でやったほうが楽。

# 解析が必要なモデルが含まれているpackageを指定 -keep class jp.exsamples.model.** { *; }

まとめ

modelを難読化したらダメってのはなんとなくわかったんだけど、「-keep class jp.exsamples.model.**」だとファイル名だけしか難読化しなようにならないってのがすごいハマった。動くようにはなったけど記載方法が間違っているような気もする。。。

「インターフェースデザインの心理学」を読んだ

この本は面白い。時間を置いてもう一回読みなおしたいと思えるぐらい面白かった。以下は心に残ったことの覚書。

ストレス

  • 同じ場所で違うことをやられると人間はストレスを感じる
  • 同じ要素で違うことをやられると人間はストレスを感じる

記憶

  • 人は4±1が瞬時に記憶できるものの最大値
  • それ以上の物を見せる場合は親子関係を作ると良い

認識

  • 人間は選ぶのが好き。だから大量の物があると立ち止まる
  • 人間は大量のものがあっても2,3しか見ない
  • 大量のもので立ち止まった人より2,3のものを見て立ち止まった人の方が次の行動を取る確率が高い

やる気

  • 目標に対する達成度をみせると人間はやる気が起きる
  • 競争意識によってやる気を出させる場合は人数を絞る必要がある

文章

  • 人は長い文章より短い文章を好む
  • 長い文章のほうが短い文章より読むスピードは速い
  • 文字の大きさは重要性を表す重要な要素の一つである

まとめ

なんとなく自分で理解しているものに対して裏付けをつけるという意味で心理学というのは学問として面白い。でも、結局はこういう心理を持つ人が「多い」というだけであって、万人に当てはまるわけではないってのは注意しないといけないんだろうなぁ。