プログラミング作法

プログラミング作法（en:Programming style）の記事では、コンピュータ・プログラミング及びプログラムのスタイル（書法）についての話題を述べる。この分野の古典は、1970年代の書籍『プログラム書法』（The Elements of Programming Style）である。古典であるゆえにプログラミング言語も古く、例がもっぱらFORTRANであるため言語の設計の古さによる制限に由来する記述も多いが、本質（Elements）は不変・普遍である。
なお、『プログラミング作法』は "The Practice of Programming" という書籍の邦題、『ソフトウェア作法』は "Software Tools" という書籍の邦題である。
あるプロダクトに見られるスタイルは、単にその作者の好みの問題という場合もあるし、何らかの「コーディング標準」や「コーディング規約」などと呼ばれるものによるものという場合もある。PythonのPEP-8、PHPのPEARのように、言語のメンテナらによる、標準的なガイドラインがある言語もある。

見た目

ここでは主にソースコードの見た目を扱う。ソースコードの見た目は、可読性に影響する。
見た目に含まれるうち、フォーマットに関するものは、ガイドラインではなくルールとして、何らかのプログラムによる自動整形に任せてしまう場合もある。その場合、命名法などが残りの関心事となる。プログラムにソースコードのフォーマットを任せてしまうのは、時間の節約の他、ある程度より開発の規模が大きい場合の統一が極めて容易という利点もある。ただし、理由があって変則的なコードの場合に回避できるか、して良いか、など、議論が残る可能性は皆無ではない。またそのフォーマットするツール自体の出来が悪いと、逆に問題になりうる。
また、以下の規則類の上位規則として、例えば「規則に従うと極端に行が長くなる」などといった理由が無い限りは、複数の流儀があるものについてはどの流儀を選んでもよいが、基本的に、一貫した書き方にせよ、というものがある。

空白類

太古のFORTRANでは空白類は、ほとんど全ての場合にあっても無くても同じであり、80桁のパンチカードに適切に並べることが重要だった。その後の言語では、「そこに空白が無ければ、トークンが連結してしまう」という場合には意味があるが、複数個の空白による位置の調整には特に意味が無く、また、改行も通常の空白と同様の扱い、という言語が増えた（ただし改行には、1行コメントの終了という重要な意味があることもある）。
積極的にインデントを利用するオフサイドルールを採用している言語もあるが、それらについてはここでは触れない（オフサイドルールの記事を参照）。
以下では、広義の空白類の扱いに関係する、各種のスタイルの話題を述べる。

字下げ

字下げスタイルは、制御構造やブロック（複文）を識別し易くする。構文規則上、begin 〜 end のキーワードや、波括弧でブロックの範囲が決まる言語では、字下げスタイルは意味には無関係だから、純粋に見た目の問題である。しかし一貫した論理的な見た目により、コードは読みやすくなる。次のコードを比較してみよう。
if (hours < 24 && minutes < 60 && seconds < 60){
   return true;}else{
   return false;}
if (hours < 24 && minutes < 60 && seconds < 60) {
   return true;} else {
   return false;}
   if (hours < 24 && minutes < 60 && seconds < 60) {return true;
   }
   else {return false;
   }
上の2つの例の方が最後の例よりも読みやすいと感じる人が多い。字下げスタイルは複数の構造が入れ子になっている場合に特に重要となる。

改頁

ASCIIで 0x0C、あるいは「^L」などと表現される改頁のコードは、近年のプログラミング言語処理系ではそもそも空白として扱われず、変なコードがあるものとしてエラーになることも珍しくないが、昔、ソースコードをプリントアウトすることが多かった時代には、大きな区切りとして次の部分を紙の先頭から始めたい場合に改行と併用して使ったもので、現在でもたまに古いソースコードで見掛けることもある。エディタの言語モードや、ソースコードをPostScriptやHTMLで読みやすく変換するツールなどが、これに対応していることもある。

その他の空白

次のC言語のコードを比較してみよう。
int count;for(count=0;count<10;count++){
  printf("%d",count*count+count);}
int count;for (count = 0; count < 10; count++){
  printf("%d", count * count + count);}
この2つのコードは、どちらがより良い表現と言えるのかはかなり個人差が大きい。空白を多めに取るスタイルでは、演算子の関係などは明瞭になるものの、一つの行としてのまとまりを欠く。「地の行では空白を入れるが、括弧内は詰める」といった折衷的なスタイルなどもあり得る。

適切な変数名

「変数名の適切な選択」が指導原理と言えよう。不適切な変数名はコードを読みにくくし、理解しにくくする。
例えば次の擬似コードを見てみよう。
get a b c 
if a < 24 and b < 60 and c < 60
  return true
else
  return false
変数名の選択方法がよくないため、この関数のコードは何をしているのか理解しにくい。しかし次のように変数名を設定すると、より分かりやすくなる。
get hours minutes seconds 
if hours < 24 and minutes < 60 and seconds < 60
  return true
else
  return false
コードの意味が分かりやすくなった。すなわち「与えられた時刻情報が24時間制に合っているなら true、合っていないなら false を返す」である。
適切な変数名の選択は、プログラム全体で一貫性を持った命名を行うことで、さらにその効果を高める。

判断構造におけるブーリアン値

プログラマによっては、上のようなブーリアン型の計算結果と判断が単純に対応した判断構造は、冗長すぎるし間違いやすいと考える。次のように、そのまま直接、論理式で表現してしまうべきと考えることもある。
return (hours < 24) && (minutes < 60) && (seconds < 60);
これらの違いは意味には影響しない。最近のコンパイラはどちらも同じオブジェクトコードを生成する。
逆に前者のスタイルを好む場合もある。その理由としてデバッグの容易さ等が挙げられる。ブーリアン型の条件式の中で変数への代入も行われる場合、その計算後に変数の値をデバッガで確認したいとすると、前者の方が確認が容易である。後者では、その行の実行完了後に停止させると関数から抜けてしまっており、値を確認できない（命令単位のステップ実行なら確認可能）。特に、この例には含まれていないが、条件判断に関数呼び出しが入る場合など、カバレッジを見るにも、文として分かれていたほうが扱いやすいと感じる場合がある。

ループと制御構造

ループなどの制御構造についても、スタイルの議論となる。適切なループ方法により可読性が向上する（命令型プログラミング言語の場合）。例えば、次の擬似コードを見てみよう。
 count = 0
 while count < 5
   print count * 2
   count = count + 1
 endwhile
このコードは変数名や字下げは問題ないが、次のようにfor文を使った方がずっと読みやすい。
 for count = 0, count < 5, count = count + 1
   print count * 2
多くの言語では、このようなパターンは次のように短縮できる。
 for count = 0 to 5
   print count * 2
 print "Ended loop";
ブロック（複文）のある言語で、制御構造の本体が「文、または、ブロック」である場合、ブロックにすることを原則とすることがある（PerlやGoなど、言語自身の構文規則でこのように強制しているものも多い）。
 for (count = 0 to 5) {
   print count * 2;
 }
 print "Ended loop";
これは例えば、次のような「誤ってセミコロンを付けた」発見に時間のかかるバグを回避する。
 for (count = 0 to 5);  // この行の最後のセミコロンがバグ   print count * 2;
 print "Ended loop";
あるいは、次のようにループ内で実行する行を増やしたときも中括弧を予めつけておけば、バグを回避できる。
 for (count = 0 to 5)
   log "loop reached " + count;
   print count * 2;  // この行が「実はループ内ではない」のがバグ print "Ended loop";
さらに、「プリプロセッサによって本体が削除されてしまい、意図していなかった次の行が本体になってしまった」というような場合も防げる。
 for (count = 0 to 5)
 print "Ended loop";