Blog::kfly8

prove t/foo/bar/baz.t

コード書くときに意識するよになった3つ

社会人として、コードを書くようになって、もう一年半くらい経ってしまった、、
HHKを買って盛り上がっているうちに、偉そうなこと書いてみます。

f:id:kfly8:20120722211416j:plain
http://instagram.com/p/K1hB2fIDGe/


ソーシャルゲームを作っていると、
仕様が変わったり、追加されることがよくあります。

そういう時でも対応しやすいコードを書くために、
最近、大きく3つのことを意識するようになりました。


1個目!

そのコード、直感的?


責任範囲を超えた"なんでもバスケット"みたいなコードは、
どんな使い方ができるか想像しがたいと思っています。

  • 何するコード?
  • お前がやるべきこと?
  • どう使えれば気持ちいい?

とブツブツ唱えてから作ると嬉しいなと思います。

もっぱら方法として効果があると思うのは、

使い方を書いてから、中身を実装すること!


2個目!

コードを書かない

エンジニアとして働いていて、幸い、自分はコードを書くのが好きです。
(ハッカソンしたいーーー。)

なんですが、

  • ゲームとしてすべきことの把握
  • 企画の目的の把握
  • アプリのコードの把握

ができていると、コードを書かないって選択肢がまま取れます。

「もうその機能はあるから5分でできるよ!」

好き嫌いが分かれるかもですが、
意味のあるコードを書くのに時間を使えた方が自分は幸せだと思うので、
「コードを書かない」って選択肢を手札に入れています。


あのモジュールがあるから
「コードを書かない」という選択は取りきれていないので、
精進精進、、



3個目!

コードを書くのに本気にならない

本気で書いたコードは、もしものときに殺される可能性大だからです。

ソーシャルゲームを作っていると、

  • 問い合わせの対応
  • 不具合
  • 仕様変更
  • 新機能!

など、大概作るより強力な弾丸が飛んできます。
作るのに本気だと、あとあと打ち返せないと思っています。

どんだけ怠慢なんだよと思われるかもしれませんが、
自分は全知全能な人でなく、凡人なんだという思想からです。

  • 仕様の先読みした抽象化

は難しい選択肢だと思っています。
ゲームの理解、アプリのコード理解、技術理解など、把握すべきところが多いと思います。
迷うくらいなら、様子を見るべきだと思っています。


以上、自分への戒め!でした。

Perl で配列回すときにデリファレンスしといた方がいいと勘違いしてました、、

避暑地でハッカソンがしたい。

前置きー。

JavaScript で、配列の長さを評価する必要がないとき、
以下のよう配列長をキャッシュすると思います。

配列の長さが変わらないなら、、

for ( var i = 0 ; i < arr.length; i++ ) { //do something}

配列長の変数に入れておく。

for ( var i = 0, l = arr.length; i < l; i++ ) { //do something}


それで、Perlでもおんなじ風味で、
キャッシュしておいた方がいいと思うと、やっぱり予想通りでした。

use strict;
use warnings;
use Benchmark qw/cmpthese/;
 
my @arr = 0..100;

# Benchmark js style
cmpthese(100000, {
    'js' => sub {
        my $total = 0;
        for (my $i = 0; $i < scalar @arr ; $i++) {
            $total += $arr[$i];
        }
    },
    'js cache' => sub {
        my $total = 0;
        for (my $i = 0, my $l = scalar @arr; $i < $l ; $i++) {
            $total += $arr[$i];
        }
    },
});

ベンチ。

            Rate       js js cache
js       51020/s       --     -19%
js cache 63291/s      24%       --

この後の本題のために、この例のfor文を簡素化してみてベンチ。

use strict;
use warnings;
use Benchmark qw/cmpthese/;
 
my @arr = 0..100;

# Benchmark coding style
cmpthese(100000, {
    'array' => sub {
        my $total = 0;
        $total += $_ for @arr;
    },
    'js cache' => sub {
        my $total = 0;
        for (my $i = 0, my $l = scalar @arr; $i < $l ; $i++) {
            $total += $arr[$i];
        }
    },
});

変数の代入が無い分速いのかな?と疑問は残りつつ、前置き終了。

             Rate js cache    array
js cache  66667/s       --     -39%
array    108696/s      63%       --

本題ー。

ここで予想したのが、

「配列長をキャッシュしておいた方がいいなら、
配列のデリファレンスしたものもキャッシュしておいた方がいいのかな?」

でした。

ですが、違いました以下のように配列のキャッシュを十分活かせない形だと、デリファレンスするコストの方が高くなるようです(2013-11-19修正)

具体的には、以下のベンチ。

use strict;
use warnings;
use Benchmark qw/cmpthese/;
 
my @arr = 0..100;
my $arr = \@arr;
sub get_arr { return @arr; }
sub get_arr_ref { return $arr; }

# Benchmark dereference
cmpthese(100000, {
    'array' => sub {
        my $total = 0;
        $total += $_ for @arr;
    },
    'get_array' => sub {
        my $total = 0;
        $total += $_ for get_arr();
    },
    'get_array cache?' => sub {
        my $total = 0;
        my @a = get_arr(); #キャッシュ?
        $total += $_ for @a;
    },
});


# Benchmark dereference
cmpthese(100000, {
    'array_ref' => sub {
        my $total = 0;
        $total += $_ for @$arr;
    },
    'get_array_ref' => sub {
        my $total = 0;
        $total += $_ for @{ get_arr_ref() };
    },
    'get_array_ref cache?' => sub {
        my $total = 0;
        my @a = @{ get_arr_ref() }; #キャッシュ?
        $total += $_ for @a;
    },
});

ベンチ結果。

                     Rate get_array cache?        get_array            array
get_array cache?  40161/s               --             -43%             -64%
get_array         69930/s              74%               --             -38%
array            112360/s             180%              61%               --

リファレンスとして扱った方

                         Rate get_array_ref cache?  get_array_ref      array_ref
get_array_ref cache?  49261/s                   --           -55%           -56%
get_array_ref        108696/s                 121%             --            -3%
array_ref            112360/s                 128%             3%             --
       2%    --


デリファレンスしておいたものを変数代入(キャッシュ?)しておいた方が遅かったです。

どうしてこういう結果になったのか、腹落ちしてないので、たぶん、、調べる、、、、

  • 代入のコストが意外と大きい?
  • あと意外なのが、ger_array より、get_array_ref の方が速かったこと。

蛇足。

Sledge のコードを読んでいて、登録されているトリガーをぶん回しているところを読んでいて沸いた疑問でした。
miyagawaさんが、書くなら、それがいいんだろうと思ってベンチを取ってみて、やっぱりそうでした。

追記

sort についても、、、
ループのたびに評価されるって思ってた、、、完全な勘違い、、残念すぎる、、orz


use List::Util qw/shuffle/;

my @num = shuffle 0..9;

# Benchmark dereference
cmpthese(1000000, {
    'simple' => sub {
        my $s = '';
        $s .= $_ for sort @num;
    },
    'cache?' => sub {
        my $s = '';
        my @sorted_num = sort @num;
        $s .= $_ for @sorted_num;
    },
});

ベンチ

           Rate cache? simple
cache? 128041/s     --   -58%
simple 305810/s   139%     --

追記2 2013-11-19

ベンチが十分、arrayのキャッシュを活かせる形じゃなかった。
コメントのnyaさんの指摘で気づきました。ありがとうございます><

雑日記。


休日に会社のPCでYouTubeを見てるのは誰ですか?俺です。すみません。
引っ越したばかりでネット繋がってなくて、、←

4月に自分携わっているアプリがリリース、
あとプライベートで、いろいろいろ、、で、
多忙させてもらってました。


人生にいくつか転機があると思いますが、
自分は今と思ってがんばらせてもらってます。


ふわっとし過ぎ。


以上、近況報告!!

Kyoto.pmに参加。温泉発火村のLTもやらせてもらった。

こんばんは。
初開催のKyoto.pm Tech Talks #01に参加させてもらいました。
そして、温泉ハッカソンを企画した話で初LTもさせてもらいました。

会場を貸してくださった、はてなさん。
運営の方々。楽しい時間をありがとうございました!
参加されている方とも交流できてよかったですー

f:id:kfly8:20120317210008j:plain

発表資料


夜遅くまで懇親会に参加させてもらって、
Perlのコミュニティっていいなーと思ったのでした。
YAPCやハッカソンなどでも何度も感じさせてもらってて、
使っている技術で繋がれるのっていいですね。

例えば、id:xaicronさんが懇親会から参加したりするのって、
Perlのコミュニティの魅力がとってもあるか、@xaicronさんが変なのか
どっちかだと思うんですよね。


仕事を始めて、約1年。
エンジニアって仕事を選んで良かったなと思ったのでした。



めもめも

id:nekokak さん

  • Teng開発者募集
    • コミュニティで開発できたらいい
  • ORM
    • データとオブジェクトの溝を埋める

id:karupanerura

  • XOClock
    • 指定時刻にジョブを実行する
    • 冗長性を持たせられたら、うまー。

id:hakobe932 さん

  • ruby-git
  • Git.pm
  • Git::Class / Git::Wrapper
  • Git::Repositry
  • Guita::Mapper::Git
  • libgit2

LT

  • Text::Hatena:oEmbed
  • SQL::Object
  • Test::Successful
  • Test::Flatten
  • DBIx::QueryLog

余談

観光地のpmは、翌日も楽しめていいですねんw

JSでそういえばな、こと。

もう三月なのか、、、
JSでそういえばな、こと。

} else { を改行して書くかどうかで迷った。

行末にセミコロンを挿入してくれた状態で解釈されるので、改行しないパターンで行こう。

"use strict";

var hoge = function(){
    return 
    {
        name: 'ry_mizuki'
    } 
}

console.log(hoge());//undfined

var fuga = function(){
    return {
        name: 'ry_mizuki'
    } 
}

console.log(hoge());// { name: 'mizuki_r' } 

if else に関して、全く触れてないという、いい加減さ、、

for ( i in obj) { ... } の in がjs でダメなのって、

obj のprototypeまで調べようとするからだけど、
objに何が入ってるか分かってるシーンなら別にいいんじゃね?とも思ったけど、そんな事はーなかった
理由は、Objectコンストラクタが拡張されているかもだから。んー消極的な理由、、
Objectが拡張されているかどうかは、すぐ分かる状態であればいいかもだけどの。

for文の最適化。

順序は逆だけど、評価式が、 0との比較になるから。whileでもいいの。

for( var i = arr.length; i--; ){ ... } 

apply を使ってリファクタリング

id:karupanerura の書いてたコードを読んでて、面白いなーと思った。(しかし頭は混乱)
適用がしがし使ってるなら、こんなリファクタリングもできるかなと思ったのでした。

callbackを直列化してみる遊び
http://d.hatena.ne.jp/karupanerura/20120219/1329646657

  • BEFORE
     var args = [cb];
     for (var i = 0; i < arguments.length; i++) {
        args.push(arguments[i]);
     }
     next.apply(this, args);
  • AFTER
  next.apply(this, [cb].concat([].slice.call(arguments)));


ほげー。

公開用テーブルと非公開用テーブルを作りたい

忘れるので、メモ。

# テーブル構造をコピー
CREATE TABLE private_hoge like hoge;
 
# テーブルの中身もコピー
INSERT INTO private_hoge SELECT * FROM hoge;
 
# テーブル名を変える (公開非公開切り替え)
DROP TABLE IF EXISTS tmp_hoge; 
RENAME TABLE hoge TO tmp_hoge, private_hoge TO hoge;


http://dev.mysql.com/doc/refman/5.1/ja/rename-table.html