皆さんはプログラムを書くときに、”コメント”を書いていますか?
コメントは、コードの読み手にそのコーディングの意図を知らせるものとして、大事な役割を担っています。例えば、OSS(オープンソースソフトウェア)のうち、全体の19%はコメントという論文データまであるようです。
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.167.1539&rep=rep1&type=pdf
リーダブルコードというより良いコードを書くための書籍があるのですが、その書籍にも、コメントの目的は、書き手の意図を読み手に知らせることであると記載されています。つまり、
書き手 = 自分
意図 = なぜ
読み手 = 次触る人、自分
に対して、伝わるコメントを書くことがポイントだと考えています。
良くないコメント
嘘をつく
- ケース
/**
* 名前の取得
* @param string $userId
* @return boolean
* @throws Exception
*/
public function fetchTags($userId, $mediaId)
{
上記の例を見ると分かるのですが、コメントとプログラムが一致していません。コメントには、paramに$userIdと記載されていますが、実際のプログラムは、$userIdと$mediaIdが書いてあります。
- 嘘のパターン
このように、メソッドコメントが違うことがあります。(引数、返り値、型、例外など…)
上記例は、メソッドコメントの説明が実は他のメソッド内容でした。推測ですが、メソッドコメントと引数が間違っていることから、コピペしてしまった可能性もありそうです。 -
対処法
プラグインを入れよう
これに尽きると思います。PHPStorm、Vim、Atom、Sublimetextなど、皆さんはどのエディタを使っていますか。メソッドコメントを補完してくれるエディタはいろいろあるので、エディタに任せるのが良いです。人が頑張って直すものではないので、機械に任せてしまいましょう。
翻訳
- ケース
// 集計対象アカウントを取得
$users = $this->fetchUser();
if (count($users) < 1) {
throw new Exception('update user_list is empty...');
}
foreach ($users as $user) {
// 投稿データを更新する
$this->updatePost($user);
}
コメントに見れば分かることを書くのはやめましょう。fetchUser()という処理に対して、集計対象アカウントを取得というコメントを書く必要はありません。
- 対処法
可読性を気にするなら、命名を適切に行なおう
コメントにやってることの見出しを付けたい気持ちは分からなくはないですが、コメントに見れば分かることを書くのは意味ないです。ただの翻訳になってしまっています。読みやすいさという観点からすれば、メソッド名の命名をよりわかりやすいものにできるように工夫しましょう。
パーティションにする
- ケース
// ---------------------------------------------------------
// 各種前処理
// ---------------------------------------------------------
session_start();
$inputData = [];
// ---------------------------------------------------------
// ログイン
// ---------------------------------------------------------
$loginObj = new Login();
if ($loginObj->isLogin($_SESSION['access_token']) === false) {
header('Location: ' . LOGIN_URL);exit;
}
// ---------------------------------------------------------
// レポートデータの取得
// ---------------------------------------------------------
try {
$analysisObj = new Analysis();
$analysisData = $analysisObj->main();
このように、// ————— で括っているパーティションのようになっている部分を指していますが、これはあまり良くないです。こうなってしまう時というのは、やってる仕事が多すぎるときになりがちです。
- 対処法
責務を小さく、スコープを短くしよう
クラス、メソッド、関数を使い分けて、1つの処理の責務を小さくしていきましょう。スコープを短くしていけると、可読性の良いコードになってきます。
処理を説明する
- ケース
// $paramがredのときは$dataに代入して、それ以外のときはgreenを代入する
$data = ($param === 'red') ? $param : 'green';
このコメントは、三項演算子の説明になってしまっています。
- 対処法
“何を”じゃなくて、”なぜ”しているかを書こう
何をやっているかはコードを読めばわかります。コメントを書く上で必要なのは、なぜその処理をやっているか伝える必要のあるときです。なので、なぜしているかをポイントに書いていきましょう。
自己主張
- ケース
$data = ($param === 'red') ? $param : 'green'; // add by sato
上記のように、add by sato といった誰が追加したのかをわざわざ書く必要はありません。誰がいつ書いたのかは、コーディングをする上で、誰も興味がありませんし、必要なら他の手段で見ることができますので、コメントに書くのは不適切です。
- 対処法
git(バージョン管理)を使おう
gitを使っていれば、こんなことをする必要はないと思います。コミットログを見れば、誰がいつ追加したかは見えるので、わざわざコメントに書かずにバージョン管理をしておきましょう。
良い例
冒頭にも記載しましたが、コメントの目的は、書き手の意図を読み手に知らせることです。ここを意識できると、コメントの書き方も変わってくると思います。
ハマりやすいところを伝える
// DateIntervalオブジェクトは、["y"] => 0, ["m"] => 0, ["d"] => 1.... のように計算された差分が配列として入っている
// DateInterval::format は入っている値を取り出しているだけなので、%sだと分単位の差分を無視してしまうため、%iで分違いがないかも見なければならない
if ($interval->format('%s') > 10 || $interval->format('%i') > 0) {
陥りがちなポイントをコメントで説明してあげる
一見不合理なことをしている理由を説明する
$reports = $this->fetchReport(0);
$tmpData = $this->fetchReport(1);
foreach ($reports as $key => $value) {
// 0と1は、レポートデータを日付でパーティションしているが、
// 日跨ぎで前日のレコードが、0テーブルなら1のテーブルに、当日のレコードが1なら0テーブルに
// 入ってしまう現象があるので、やむを得ず、データが入っていない場合は、データを追加する処理を入れる
if (!isset($tmpData[$key])) {
$reports[$key] = $tmpData[$key];
}
}
処理としてはふさわしくないが、そうせざるを得ないときに、なぜそうしているかコメントで補完する。
把握しづらい外的な仕様を説明(謎の処理の意図を説明する)
// 1億円以上の数値が入ることは有り得ないので、そのケースがあった場合は、0にする。
if ($price > 100000000) {
$price = 0;
}
サービスの特性上、処理を加工する必要がある場合は、きちっとコメントを残してあげましょう。
まとめ
コーディングを進める中で、コメントは必要です。コメントをしていく上でポイントなのは、何をやっているか書くのではなく、なぜやっているかを書くことです。コードじゃ伝わらないことをコメントに残していくと綺麗なコードになっていくんじゃないかと思います。