伝える作法はコメントの書き方である。この作法の要は、冒頭に示した一言に尽きる。しかし、これを真に伝えること、あるいは理解することは、たやすいことではない。
その作法を伝える前に一度考えてみてもらいたいことがある。
コメントを記すための仕様は、プログラミング言語はもちろん、HTMLなどのマークアップ言語や、問い合わせ言語の一種である正規表現まで、ほとんどすべてのコンピュータ言語で規定されている。まるで、その規定がなければコンピュータ言語として失格であるかの如くの徹底ぶりである。果たしてこれは一体何故なのだろうか。
筆者はこう考える。コンピュータ言語とは、コンピュータのためよりも、むしろ人間のための言語であるからだ、と。もし、人間のためよりもコンピュータのためが優先されるのであれば、コンピュータにとってはまったく無意味で無駄で、しかも無視するのにも手間が掛かるコメント機能など、積極的に廃止すべきである。実際、コンピュータのためといえるほぼ唯一の言語である機械語(アセンブリ言語ではない)は、その通りになっている。すなわちコメントという命令が存在しない。
この機械語という例外を除き、コンピュータ言語とは実に奇妙な言語だ。なぜならば、コンピュータ言語を話せる(作文できる)のはコンピュータではなく人間だけであるからだ。コンピュータは、それを聞いて態度を示すのみ。話し返すことができないのだ。そんなコンピュータ相手に会話を成立させるには、コンピュータが示した態度を汲み取りながら、過去に自分や他人が話したコンピュータ言語を自分で読んで、新しい内容を再び話してやらねばならない。
話しもするし、聞きもする。よって、コンピュータ言語により深く関わっているのは、人間の方なのである。
この考察から結論として心得てもらいたいこと。それは、「コンピュータ言語は人間のための言語なのだから、人間が読んで分からない事柄には人間の言葉で補足を加えねば意味がない」ということである。プログラムとは、正しく動きさえすればよいというものでは、決してない。
コメントの重要性、そして何のためにコメントを書くのかについて理解してもらえただろうか。
ではコメントを書くとして、どのように書くべきなのだろうか。もちろん、ただ書けばよいわけではない。人間がプログラムを理解できるように書かなければ意味がない。
そのために心得ておくべきコツこそが、今回の表題である「書かれし事書かず、書かざれし事書け」というわけである。コメントの書き方を伝えるために例題プログラム(課題管理表)を用意した。リストは2つあり、リスト1が悪い例、リスト2がそれを修正した例である。これらを見ながら解説していこう。
リスト1. 課題管理表プログラムリスト(改善する前)
#!/bin/sh -xv
#
# 課題管理表リスト表示
#
# 1/18 青木太郎
# 変数の定義
export LANG=ja_JP.UTF-8
export PATH=/home/UTL:/home/TOOL:$PATH
tmp=/tmp/$$
today=$(date +%Y%m%d)
todayhms=$(date +%Y%m%d%H%M%S)
##################################################
# オプション取り込み
dd bs=${CONTENT_LENGTH} |
cgi-name -i_ -d_ > $tmp-name
# 日付指定
day_from=$(nameread DAY_FROM $tmp-name | dayslash -r yyyy/m/d 1)
day_to=$( nameread DAY_TO $tmp-name | dayslash -r yyyy/m/d 1)
isdate "$day_from" || day_from=00000000
isdate "$day_to" || day_to=99999999
sortkay=$( nameread SORTKEY $tmp-name)
sortmuki=$(nameread SORTMUKI $tmp-name)
if isnum "$sortkay"; then
[ "$sortmuki" = "down" ] && sortopt=-k${sortkay}
[ "$sortmuki" = "up" ] && sortopt=-k${sortkay}r
fi
[ -z "$sortopt" ] && sortopt="-k2"
##################################################
# リスト取得
cat DATA |
# 共有サーバ内の課題管理表.xlsを参照
# 完了フラグ2は表示しない
awk '$13!=2' |
tee $tmp-listall |
# 日付の絞り込み
awk '"'"$day_from"'"<=$3 && $3<="'"$day_to"'"' |
# 表示調整
dayslash yyyy/mm/dd 3 9 10 11 |
sed 's/\\n/<br_\/>/g' |
# ソート
sort "$sortopt" |
# 色指定の付加
awk '{print $0,($13==0?"white":($13==1?"silver":"gray")),($13==0?"完了":($13==1?"削除":"エラー"));}' > $tmp-list
# 起草者リストと担当者リスト生成
lineup 4 $tmp-listall > $tmp-writer
lineup 5 $tmp-listall > $tmp-charge
# 出力
echo "Content-type:text/html"
echo ""
cat KADAI_KANRI.LIST.HTML |
mojihame -l###LIST### - $tmp-list |
mojihame -l###WRITER### - $tmp-writer |
mojihame -l###CHARGE### - $tmp-charge |
tee $tmp-html
##################################################
# 終了処理
rm -rf $tmp-*
exit 0
リスト2. 課題管理表プログラムリスト(改善した例)
#!/bin/sh -xv
#
# KADAI_KANRI.LIST.CGI
# 課題管理表リスト表示
#
# t-aoki@usp-lab.com 2013/01/18
# 変数の定義。全シェル共通
export LANG=ja_JP.UTF-8
export PATH=/home/UTL:/home/TOOL:$PATH
tmp=/tmp/$$
today=$(date +%Y%m%d)
todayhms=$(date +%Y%m%d%H%M%S)
##################################################
# オプション取り込み。必須項目なし
dd bs=${CONTENT_LENGTH} |
cgi-name -i_ -d_ > $tmp-name
##################################################
# 起草日の指定範囲
day_from=$(nameread DAY_FROM $tmp-name | dayslash -r yyyy/m/d 1)
day_to=$( nameread DAY_TO $tmp-name | dayslash -r yyyy/m/d 1)
# (範囲指定エラーの際には全件表示)
isdate "$day_from" || day_from=00000000
isdate "$day_to" || day_to=99999999
# ソートキー取得
sortkey=$( nameread SORTKEY $tmp-name)
sortmuki=$(nameread SORTMUKI $tmp-name)
if isnum "$sortkey"; then
# キー指定が有効な時だけ向きを判断してソート順指定
[ "$sortmuki" == "down" ] && sortopt=-k${sortkey}
[ "$sortmuki" == "up" ] && sortopt=-k${sortkey}r
fi
# キー指定エラーの際にはデフォルト(課題番号の昇順)
[ -z "$sortopt" ] && sortopt="-k2"
##################################################
# データ取得
cat DATA |
# 1:キー 2:課題番号
# 3:起草日 4:起草者 5:担当者 6:項目 7:質問 8:回答
# 9:完了予定日 10:完了日 11:検証日 12:検証者
# 13:完了フラグ(0:未完了 1:完了 2:削除)
# 削除レコードは表示しない
awk '$13!=2' |
# 起草者リスト、担当者リスト生成用の全件リスト保存
tee $tmp-listall |
# 起草日の絞り込み
awk '"'"$day_from"'"<=$3 && $3<="'"$day_to"'"' |
# 日付表記と、改行コードの変換
dayslash yyyy/mm/dd 3 9 10 11 |
sed 's/\\n/<br_\/>/g' |
sort "$sortopt" |
# 色指定の付加
awk '{
# 1: ~ 13:
# (次の2フィールドを追加)
# 14:背景色 15:完了ボタンに表示する文字列
print $0,
($13==0?"white":($13==1?"silver":"gray")),
($13==0?"完了":($13==1?"削除":"エラー"));
}' > $tmp-list
# 1:キー 2:課題番号
# 3:起草日 4:起草者 5:担当者 6:項目 7:質問 8:回答
# 9:完了予定日 10:完了日 11:検証日 12:検証者
# 13:完了フラグ(0:未完了 1:完了 2:削除)
# 14:背景色 15:完了ボタンに表示する文字列
# 起草者リストと担当者リスト生成
lineup 4 $tmp-listall > $tmp-list-kisou
lineup 5 $tmp-listall > $tmp-list-tantou
##################################################
# 出力
echo "Content-type:text/html"
echo ""
cat KADAI_KANRI.LIST.HTML |
mojihame -l###LIST### - $tmp-list |
mojihame -l###KISOU### - $tmp-list-kisou |
mojihame -l###TANTOU### - $tmp-list-tantou |
tee $tmp-html
##################################################
# 終了処理
rm -rf $tmp-*
exit 0
リスト1の51-53行目。「担当者」は英語でchargeというが分かりにくい。分かりにくいからコメントがいる。そうするくらいならローマ字でtantouと書いて済ませる方がよっぽどいい。
ただし、開発現場にコーディング規約が存在するならそれに従うべきだ。
「ソートする」だけなら、言われなくてもわかる。
リスト1の44行目。「ソート」とコメントされている。しかし、そんなことは次行の命令を見れば分かる。もし補足を付けたいのであれば、肝心な事は、何の順番でソートするのか、そして、その理由・目的である。
リスト1、2の冒頭行を見比べてもらいたい。後者ではコメント内にファイル名を記してある。
ファイル名は実際のファイルを見れば自明であると思うかもしれない。しかし、ファイル名は意図せず変えられてしまうことがあり、またエディタによっては画面に表示されないこともある。よって、プログラムの冒頭に自ファイル名は書いておくべきだ。
これも、リスト1、2の冒頭行を見比べてもらいたい。後者のように日付や連絡先を付けておけば、ソースコードに疑問や意見が生じた時、誰に相談すればよいかわかる。相談相手と連絡が取れなかったとしても、日時を手掛かりに経緯を調べることができる。
リスト1の47-48行目のAWKは記述が長いだけに、何が行われているのかわからない。そこでリスト2の57-59行目のようなコメントを付ければ、14番目15番目の列を追加している処理であることがわかる。
誌面の都合でprint文の前に記しているが、print文の右に書くことが可能なら、コードと一対一になって更に分かりやすくなるだろう。
リスト1の22-23行は何が行われているのか分かり難い。そこで、リスト2の31行目にはコメントを追加した。
簡潔な表現にすることは大事ではあるが、無理に単語でいうよりも、文章にしてきちんと言いたい事をいうべきである。
リスト1の36行目「完了フラグ2」とあるが、2という数字(マジックナンバー)が何を意味するのかさっぱり分からない。リスト2の44-45行目のようにして、数字の意味を書くべきである。
たとえばリスト2の41-44行目と64-67行目にはまったく同じことが書いてある。冗長に思うかもしれないが、離れているなら(特に一画面に収まらない場合)繰り返し書く方が読みやすくなる。
リスト1の35行目は、その手前の行で読み込むDATAというファイルについて「別途資料参照」で済ませているが、リスト2の41-44行目のように、せめて列の構成くらいは書くべきだ。別途資料を確認するのは手間がかかるし、資料が行方不明になった時困る。
リスト1の26,30行目はコメントがないと分かり難かったため、リスト2の31,35行目ではコメントを付けてある。見出しにはif文と記したが、リスト2の35行目のように暗黙のif文に対しても同様にコメントを付けるべきである。
また、if文の中身が長い場合には、elifやelse、fi句の箇所にも、同じif文の補足を書いてもよいだろう。
リスト1、2共に###……だけの行がある。これは処理の一区切りを明確にするために記している。
処理の一区切りとは、それを単位として他のコードに「コピー&ペースト」できるようになっているものである。日頃からこのような区切りを意識してコードを作っておけば、他のプログラムに対する再利用がやりやすくなる。
リスト1の24-28行目では、keyの綴りをkayと間違えている。意図的に間違える事はないだろうが、日頃から綴りに気をつけると共に、見つけたらただちに修正するように心かけるべきだ。後で読む者はそこでいちいち混乱し、無駄な時間を強いることになる。
これは他のものに比べるとやや曖昧なものであるが、たとえばリスト2の80-82行目のようなファイルの命名規則である。これら3つのファイルは$tmp-listで始まっているが、この名前を見ただけでも互いの関係性について、ある程度想像を付けることができる。
ここで記した数々の具体例は、ユニケージエンジニア達が、現場で遭遇したさまざまな問題にどう対応したらよいかと考え、時に悩んだ末に、辿り着いた書き方である。そのため、多くの案件に対して役立つものであることは間違いないだろう。
しかしこれらの書き方は完成形ではない。彼らは今も現場で、新たな問題に遭遇し、悩みながら書き方を進化させ続けているのである。よってこれらが常に正しいとも限らない。また、このわずかな誌面で伝えた内容で網羅しきれるものでもない。
確かなかなことは、「人間にとって分かりやすい書き方」である。そのことを意識するよう、プログラミングをする時は常に心がけてもらいたい。
USP MAGAZINE 2013 autumn 松浦智之著、「第八回 ユニケージエンジニアの作法」より加筆修正後転載