スゲい簡単なPerl入門 11th Day : Perlベストプラクティス、書き方、

[Perlベストプラクティス](http://www.amazon.co.jp/Perl%E3%83%99%E3%82%B9%E3%83%88%E3%83%97%E3%83%A9%E3%82%AF%E3%83%86%E3%82%A3%E3%82%B9-Damian-Conway/dp/4873113008)を半分くらい読んだので、注意しようと思ったところをまとめます。

![スクリーンショット 2013-10-04 2.51.20 PM.png](https://qiita-image-store.s3.amazonaws.com/0/18705/532f4d5e-8297-dfa9-5b36-c74d2f859dfe.png)

# 基本的なスタンス
**コードが明確になることは、保守がしやすくなり発見しにくいバグや特異なケースが発生しにくくなる**

# 1. PostFix型でなくBlock型の利用が推奨

```pl:ダメな例
my $hoge = &fuga(a,b,c) if ( $value > $MAX ); 
```

```pl:良い例
if ( $value > $MAX )
    my $hoge = &fuga(a,b,c); 
}
```

```pl:例外
die("Error $!") if ( $value > $MAX );
```

* next, last, redo, return, goto, die, croak, throw は分かりやすく記載される為に、極力左側に配置する


# 2. 否定はあまり推奨されない

## 2.1. unless, until などを使うときは以下は使わない

```pl:否定演算子
!, not #値の否定
!~, !=, ne #値の不等
<,>,<=,>=,<=>, #数字の大きさ
lt,gt,le,ge,cmp, #文字列の大きさ
```
## 2.2. 例

```pl:NG
next NAME unless $name ne 'Harry';
redo NAME unless $name !~ m/Mud{1,2}/xms;
```

```pl:OK
next NAME unless $name eq 'Harry';
redo NAME unless $name =~ m/Mud{1,2}/xms;
```

# 3. パッケージ変数は使わない
* レキシカル変数(my で宣言するやつ)を使いましょう

# 4. else前後のカッコ

```こうしましょう
if () {
 hoge
}
else {
 fuga
}
```

# 5. => の呼び名
* fat comma （ファットコンマ）

# 6. $_ は非推奨
* 紛らわしいから。レキシカル変数で代用できるところは代用しましょう

# 7. 非レキシカルループ反復子
* forループの反復子変数は常にmyで宣言する
* forループで明示的な反復変数を使用する際は、必ずmyキーワードを使用して、レキシカル変数として明示的に宣言する

```pl:ダメな例
my $client;
SEARCH:
for $client (@clietns) {
 last SEARCH if $client->holding();
}
if ($client) {
 $client->resume_conversation();
}
```

myを省略するとループの手前で宣言されたレキシカル変数は再利用されなくなる。
代わりに、反復子変数として（同じく$clientという名前の）新しいレキシカル変数がこっそりと宣言される。
この新しいレキシカル変数のスコープは常にループブロックに限定され、外側のスコープで同じ名前を持つ変数を全て隠蔽する。
つまり、 **forループ前の$clientとは別物** 。

```pl:つまり
my $client;
SEARCH:
for $different_client_just_named_client (@clietns) {
 last SEARCH if $different_client_just_named_client->holding();
}
if ($client) {
 $client->resume_conversation();
}
```

つまりif文は実行されない

```pl:よい例
my $client_holding;
SEARCH:
for my $client (@clietns) {
 if ($client->holding()){
  $client_holding = $client;
  last SEARCH;
 }
}
if ($client_holding) {
 $client_holding->resume_conversation();
}
```

# 8. リストの生成
## 8-1. 古いリストから新しいリストを作成するときはforでなくmapの利用

```pl:ダメ
my @sqrt_result;
for my $result (@results) {
 push @sqrt_result, sqrt($result);
}
```

> @sqrt_result配列を設定する度に内部でメモリの再割当てが繰り返される。
> 配列の要素は予め割り当てられている為、pushを使用するとその後ろに新しい要素が配置されるので、
> 事前に領域を割り当てるとしたら、明示的なカウンタを使用しなくてはならない。

```pl:事前にメモリの割り当て
my @sqrt_result;
#$resultの要素集に応じて事前に領域を割り当てる
$#sqrt_result = $#result;
for my $next_sqrt_result (0..$#result) {
 $sqrt_result[$next_sqrt_result] = sqrt $result[$next_sqrt_result];
}
```

代替案としてmapを使うといい
コード量も見栄えもシンプルになる。
内部でどのような処理が行われるか明示的になる。

```pl:map
my $sqrt_result = map { sqrt $_ } $result;
```

## 8-2. リストの値の検索にはforでなくgrep,firstを利用
* リストから不要な要素を削除したい場合

```pl:良くない例
my @disqualified_candidates;
for my $name (@candidates) {
 if (cannot_tell_a_lie($name)){
  push @disqualified_candidates, $name;
}
```

grepを利用すると以下の様に済む。

```pl:良い例_grepを利用
my @disqualidied_candidates = grep { cannnot_tell_a_lie($_)} @candidates;
```

* 特定の要素を検索する場合

```pl:良くない例
my $scapegoat = $disqualified_candidates[rand @disqualified_candidates];
SEARCH:
for my $name (@disqualified_candidates){
 if ( chopped_down_cherry_tree )($name){
  $scapegoat = $name;
  last SEARCH;
}
print {$headline} "Disgraced $spacegoat Disqualified From Election\n";
```

firstを利用すると以下の様になる。

```pl:良い例:firstを利用
use List::Util qw( first );
my $spacegoat = first { chopped_down_cherry_tree{$_}} @disqualified_candidates;
if (!defined $scapegoat){
 $scapegoat = $disqualified_candidates[rand @disqualified_candidates];
}
print {$headline} "Disgraced $scapegoat Disqualified From Election\n";
```

# 9. ドキュメント
> ドキュメントはセックスに似ている。よいときはすごくよいし、よくなくてもないよりはマシだ。 Dick Brandon
> ドキュメントは将来の自分に書くラブレターである、

* Pod (Plain Old Documentation) を利用する

```pl:podの書き方
=head1
 SCRIPT NAMESomeScript.pl

=head1 DESCRIPTION
This script is used to do ....

=head1 USAGE
perl SomeScript.pl file1 file2 ...

=head1 SUBROUTINES/METHODS
メソッドについて

=head1 CONFIGURATION AND ENVIRONMENT
モジュールが使用するコンフィグシステムや環境変数などを説明

=head1 DEPENDENCIES
依存関係
バージョン情報、
必須モジュール

=head1 BUGS AND LIMITATIONS
問題や将来にリリース予定
パフォーマンス上の問題や未対応のデータ型など

=head1 INCOMPATIBLITIES
このモジュールと併用できないモジュール

=head1DIAGNOSTICS
エラーやメッセージ
発生しないはずのものも含む
問題毎に完全な説明、原因として考えられるもの、推奨される修復作

=cut
```

* こうしたドキュメントファイルはファイルごとに一箇所にまとめる必要がある

# 10. コンストラクタの呼び出しではアロー演算子を利用する
コンストラクタの呼び出しはアロー演算子を使用するのがよい。
Perlではコンストラクタと他のメソッドに実質的な違いはない。

```pl:arrowOperand
my $obj = SomeClass->new;
```
間接オブジェクト呼び出しは、将来的には非推奨になる可能性がある。

```pl:indirectCall
my $obj = new SomeClass();
```