PerlのWebプログラミング効率化のTips

id:Csideのメインブログに書くまでもない技術メモ、雑記などを書き散らすグループ

PerlのWebプログラミング効率化のTips

PerlのWeb開発の初心者のためのTips

( -> プレゼンモード

目次

追記

感想いただきました。よい補足になっていると思うので、こちらも併せて。


Agenda

  • デバッグしやすいコードを書く
  • 保守のしやすいコードを書く
  • ミスを想定した工夫を入れる
  • 同じことを繰り返さない
  • print debug tips
  • ボトルネックをなくす

デバッグのしやすいコードを書く


デバッグのしやすいコードとは

  • 小さく試せること
  • 部品に適切に分割されていること
  • 各部品が疎結合であること

デバッグしにくいコード - 1つの関数が巨大

  • main 関数や httpd スクリプト(.cgi, .fcgi, .psgi, etc...)が巨大
  • 100行を超える関数
sub main {
    my $result;

    # ...
    # 処理 A を何十行にもわたってする
    # ...

    # ...
    # 処理 B を何十行にもわたってする
    # ...

    # ...
    # 処理 C を何十行にもわたってする
    # ...

    return $result;
}
  • $result の値がおかしい場合
    • 処理A~Cどこに問題があった? => 推測しにくい
    • それぞれが単体で正しく動くか検証が難しい

関数を切り分ける

  • なぜ関数に切り分けるのか
  • 部品ごとのテストが可能
sub func {
    do_A();

    do_B();

    do_C();

    return $result;
}

sub do_A { ... }
sub do_B { ... }
sub do_C { ... }

テストのしやすいコードを書こう

よくテストされた、ちいさなパーツをくみあわせて、ソフトウェアをつくるのがバグのすくないソフトウェアを短期間でくみたてるよい方法

tokuhiromさん

Web開発で疎結合なコードにするコツ

  • コントローラーにロジックを詰め込まない
  • コントローラーに依存しない処理は、単体で動くモジュールとして開発する
    • テストしやすい
    • 修正 -> httpd再起動 -> 修正 -> httpd再起動 -> ... という手間がかからなくなる副産物も

保守しやすいコードを書く

引数の順番で混乱しやすいサブルーチンをつくらない

sub send_mail {
    my ( $from, $to, $subject, $body, ... ) = @_;
    ...
}

send_mail( $arg1, $arg2, $arg3, $arg4, ... );

代わりに:引数に名前付きハッシュを使う

  • 引数の順番に迷うことがない
send_mail(
    from    => $from,
    to      => $to,
    subject => $subject,
    body    => $body,
    ...
);

sub send_mail {
    my ( %args ) = @_;
    my $from    = $args{from};
    my $to      = $args{to};
    my $subject = $args{subject};
    my $body    = $args{body};
    ...
}

ミスを想定した工夫を入れる

バリデーション

  • 使う人(自分自身含む)が間違った値を渡す可能性があることを想定して作る
  • 明らかに間違った値が渡されたらそこで落ちるようにする
    • 使う人に「間違ってるよ!」と伝える
  • バグに気づきにくいのは「間違って渡された値がなまじ途中まで動いてしまう」ケース

警告をだしてくれるのはまだいい方で、間違った値を黙ってそのまま使うというのが一番やっかいです。それくらいなら、初めからはっきりと「値が間違っている」といって例外を吐いてくれた方がデバッグしやすいのではないでしょうか。

Re: バリデーションはどの位置で必要か - Islands in the byte stream
  • example
use Data::Util qw(is_string);

sub validate {
    my $str = shift;
    die "Not a string: $_" unless is_string($str);
    ...
}

使う側のミスを想定した関数に

  • さっきの関数を、もうちょっと使う人フレンドリーに改良
  • たとえば: key を typo して使われた場合、どうなる?
    • 使う人は typo にめちゃめちゃ気づきにくい
send_mail(
    form => $from, # <- Typo!!!!!!
    ...
);

sub send_mail {
    my ( %args ) = @_;
    my $from = $args{from}; #=> undef が代入される
    ...
}
  • 人はTypoする生き物
  • 未知の引数が渡ってきたときに落ちるように一工夫
sub send_mail {
    my ( %args ) = @_;
    my $from = delete $args{from};  # deleteを使う
    my $to   = delete $args{to};
    ...

    die "Unknown param: $_" foreach keys %args;
}

同じことを繰り返さない

車輪の再発明を避ける

  • いかなるコードも未来には負債になる
  • 最大の効率化は「書かなくいいコードを書かない」
  • 世界で既に書いた人がいないか
    • Perl CPANモジュールガイド
    • 基本的なCPANモジュールはおさえておくと吉
      • 使い方まで覚えておく必要はない
        • (今この瞬間も仕様が変わっているモジュールもあるし、使い方を覚えることのはナンセンス)
      • モジュールの存在だけ頭にマッピングしておき、必要なとき本なりperldocなり参照できるようにする

使い方を調べる時間をなくす


同じ単語やコマンドを入力する時間を短縮する


ボトルネックの解消

  • Perlは広大だが、つまづきやすいポイントは限られている
    • そこだけピンポイントに力をかければ、あとは怖くない
  • 典型的なはまりポイントは資料が揃っている

文字化け

コンテキスト

正規表現

リファレンス


Print Debug Tips

Print デバッグは最後の手段

ときどき、いざ問題を解決せん、ということで、頭で考えて大体の当たりを付ける前に、突然デバッガーを起動して色々なところにブレークポイントを置いてみたり、プロファイラーを起動したり、ソースコード間を行ったり来たりしてディスプレイの前で腕を組んで首を傾げ、一向に開発が進まない、という人がいる。

もしこういうはまり方をしやすい人がいたら、その人に対するアドバイスとして、一度ツールを使うのをやめてみることを提案したい。

はまった時にまず最初に行うことは、ツールを立ち上げることではなく、「どの辺りに問題があるのか」について、頭で考えて当たりをつけることだ。そして、その関連箇所のソースコードを読んで処理内容を確認することだ。

プログラマーの開発速度は「はまる」時間の長さで決まる : 小野和俊のブログ

Data::Dumper

データ構造のままDump

use Data::Dumper;
warn Dumeper($data);
# $VAR1 = {
#           'human' => 'Dan Moroboshi',
#           'transform' => 'glasses',
#           'power' => [
#                        'Emerium Beam',
#                        'Eye Slugger',
#                        'Wide Shot'
#                      ],
#           'name' => 'Ultra Seven'
#         };

Carp

  • スタックトレースを吐ける
  • 「この処理どっから渡ってきたの?」を調査するとき便利
use Carp qw(cluck confess);
confess例外
cluck警告に留める

Devel::SimpleTrace

  • あらゆる例外もしくは警告のスタックトレースを自動で出力

おわりに:参考資料

  • 以下の研修用資料がめちゃめちゃ丁寧にまとまっているので、ぜひ一読すべきでしょう。
  • mixi新人研修用資料
  • はてな新人研修用資料