| Top Page | プログラミング | Perl 目次 | prev | next | 索引 |
これまでにもたびたび触れましたが,プログラムを読みやすく 書くことはとても大切です. 読みやすいプログラムには,あとから見てもなにをやってるか分かりやすい, そのためにバグ(まちがい)を発見しやすいし,管理・拡張もやりやすい, というメリットがあります.
どんなプログラムもそうですが,研究者が研究用に書くプログラムでは 動作の正しさは絶対条件です. 正しく動作するように書けているかチェックするには, 読みやすく書いてある必要があります. また,読みやすく書こうとすることで,最初からバグが混入しにくくなります.
また,研究の進展とともにプログラムを改造したくなることもよくある でしょうが,読めないプログラムは改造できません.しょうがないから 最初から書きなおして無駄なエネルギーと時間を使ったり, 改造をあきらめて,やってみたかった解析もあきらめる, あるいは不十分・不適切であることを知りつつこれまでのやり方ですます, ということにもなります. これではいけません.
すでに書いたことの反復も多いですが,読みやすいプログラムを書くための ヒントを整理してみました.
ブロック内の文をインデントする(頭を下げる)ことは,プログラム全体の 構造を視覚的に把握しやすくするうえで必須です. 下の二つのプログラムを比べてみれば,どちらば見やすいか明らかです.
while ($line = <>) { chomp $line; ($message, $times) = split /\s+/, $line; if (defined $times) { for ($i = 0; $i < $times; ++$i) { print $message, "\n"; }}}
while ($line = <>) { chomp $line; ($message, $times) = split /\s+/, $line; if (defined $times) { for ($i = 0; $i < $times; ++$i) { print $message, "\n"; } } }
なお,何重もループや条件判断が重なると,インデントがどんどん深くなって しまいます.ブロックの入れ子構造が複雑になってきたら,プログラムの設計を 考え直してみましょう.落ち着いて考えるとずっと簡単なアルゴリズム(計算手順) で処理できることもよくあります.サブルーチンも積極的に活用しましょう.
複数の単語からなる名前を付けるときは, $two_words のように下線で区切る流儀と $twoWords のように単語の 先頭文字を大文字にする流儀があります.自分が好きな方法でつけてください.
なお,for 文で繰り返し回数を数える変数には,習慣で $i, $j, $k などがよく使われます (おそらく FORTRAN の変数の型と 名前の関係についてのルールに由来する).これらの変数名が使ってあれば, その場で回数を数えるためだけの使い捨て変数だな,と想像できます. 繰り返しが終わったり,抜け出したりしたときのこれらの 変数が重要な意味を持っていて,あとあと何度も参照するのなら, 意味のある名前の変数に一度代入したほうが読みやすくなるでしょう.
サブルーチンの名前は処理の内容が分かるようにつけようという話は すでに書きました. >サブルーチンのページ
プログラムをしまっておくファイルの名前も,中身が想像しやすい名前にしましょう. program01.pl だの, analysis_a.pl だの,test.pl だのではまったく想像 できません.また,森林のデータの解析をいろいろやってる人が forest1.pl, forest2.pl,… という名前をつけても,forest はほとんど情報になってませんね.
プログラム中に適切なコメントを書いておくと,あとでプログラムを 読むときに大きな助けになります.
なお,このページは Perl の基礎の解説ページなので,プログラム例中の コメントは文法の説明を兼ねて饒舌に書いてあります. 実際に使うプログラムではこんなに書く必要はありません.
では,どんなことをコメントに書くか.基本原則としては, プログラムを書いているときには分かっているけど,数日たったら 分からなくなりそうなことを書きましょう.
たとえば,$i++; に 「$i をひとつ増やす」などというコメントを 付けてもほとんど意味がありません.文法の基礎が頭に入っていれば, いつ見ても分かることですから.
きっちりと字がつまったプログラムよりも,適度に空白文字や空白行が入ったプログラムは ずっと目にやさしく読みやすくなります. 文法上必要ではない余白ですが,読みやすいプログラムにするには重要です. 演算子の前後に空白文字を入れる,ひとまとまりの処理の前後に空白行を入れる, それだけでプログラムは読みやすくなります.たとえば
for ($i=1;$i<$max;++$i){ if(($a[$i]<$mean-2*$sd)||($mean+2*$sd)<$a[$i])) { print "out of range\n"; } }
よりも
for ($i = 1; $i < $max; ++$i){ if( ($a[$i] < $mean - 2 * $sd) || ($mean + 2 * $sd) < $a[$i]) ) { print "out of range\n"; } }
のほうが(たぶん)読みやすいでしょう.
Perl では,今まで出てきていない変数名が現れると,その時点で 新しく変数を作ってくれます.おかげで手軽にプログラムが書けるという メリットもありますが,一方で,どんな名前の変数がどのように使われて いるのか,じっくりプログラム全体を読まないと分かりにくいという難点も あります.
たとえ必要ではなくても,あえて変数をはっきり定義して使うと読みやすく なることがあります.たとえば,
while (<>) { ++$count; } print $count;
と書けばそれでいいんだけど,あえて
$count = 0; # 行数のカウンタの初期設定 while (<>) { ++$count; } print $count;
と書くとか,
while ($line = <>) { chomp $line; ($id, $h, $d) = split /\s+/, $line; $height{$id} = $h; $diameter{$id} = $d; }
でいいんだけど,あえて
%height = (); # 各個体の高さを記録するハッシュ %diameter = (); # 各個体の直径を記録するハッシュ while ($line = <>) { chomp $line; ($id, $h, $d) = split /\s+/, $line; $height{$id} = $h; $diameter{$id} = $d; }
と書くようなスタイルです.
さらに,サブルーチンの中や,ブロックの中だけで使う変数は,my を使って 明示的に定義すれば,この範囲内でしか使わない変数だということも明示的に 示すことができ,プログラムを読むときの手がかりにもなります (※読みやすさ以外の my の効用については,すでに 変数の局在化のページで説明しました).
プログラムをサブルーチンに分けることの効用は, サブルーチンのページで 紹介しました.
はじめに簡単なプログラムを書いてから,だんだん機能を足していくと, いつのまにやらメインのプログラムやひとつのサブルーチンが長大化して しまうことがままあります.
サブルーチンを使い慣れないうちはついおっくうで,プログラム全体が サブルーチンなしのメイン部分だけ,変数はみんなグローバル(プログラム全体 のどこからでも参照したり代入したりできる),というプログラムを書いて しまいがちですが,はじめは少々無理をしてでもサブルーチンに分割して 読みやすいプログラムにする努力をしてみましょう.
プログラム中になんのことわりもなく数値リテラル(直書きの数字)が出てくると, これはいったいなんなのか悩んでしまいます.そんな直書きの数字は マジックナンバー とも呼ばれ,プログラム解読の障害になります.一度,意味のある名前の変数に しまってから使えば,ずっとわかりやすくなります.たとえば,
for ($i = 0; $i < 10; ++$i) { $amount = 10000 * (1 + 0.005) ** $i; print $i, "\t", $amount, "\n"; }
と書くよりも,
$inital_amount = 10000; # 元金 $intrest_rate = 0.005; # 利率 $for_years = 10; # 期間 for ($i = 0; $i < $for_years; ++$i) { $amount = $inital_amount * (1 + $intrest_rate) ** $i; print $i, "\t", $amount, "\n"; }
と書いたほうが読みやすくなります.
また,プログラムの数ヶ所でおなじ数値を使っている場合は,変数に値を 代入しているところだけ変えれば全体の動作を変えられて便利だし, 直し忘れも防げます.