プログラムの可読性に関する検討

目次
  1. はじめに(※この記事)
  2. 名前
  3. 式と文
  4. 一貫性と慣用句
  5. 関数マクロ
  6. マジックナンバー
  7. コメント
  8. 長さ(行数,1行の文字数)

はじめに

http://d.hatena.ne.jp/honjo2/20100518/1274178222 を読んでプログラムの「可読性」について考えていたら長くなりそうだったので,イントロ的な記事をまず書いておきます.詳細は,まとまったらと言う事で.

指標の必要性

「可読性」は主観に依存する部分も大きいため,注意深く検討していく必要があります.特に,「可読性が低い」と言う言葉は単に「俺が読めないコードはクソだ!」の言い換えでしかない場合も多いので,そうならないように注意する必要があります.

「可読性」は,単語の指す範囲が広く,また曖昧であるという問題があります.例えば,http://d.hatena.ne.jp/honjo2/20100518/1274178222 では「ある処理を実現するための記述方法が複数存在する」を「可読性が低い」と表現しており,読者を混乱させる要因となっています.「可読性」のように抽象的な概念について検討する際には,もう少し具体的な指標をはじめに列挙しておき,それぞれについて(ある程度)独立して議論する必要があります(参考:禁止語のススメ - Simple -憂鬱なプログラマによるオブジェクト指向な日々-).

「プログラミング作法」での可読性に関する指標

ここ数年は,「可読性」について真面目に検討した事がなかったのであまり新しい資料がないのですが,取り合えず Amazon CAPTCHA の「第1章 スタイル」をベースに検討してみます.

  1. 名前
    • グローバルには分かりやすい名前を
    • 統一しよう
    • 関数には能動的な名前を
    • 名前は的確に
  2. 式と文
    • 構造がわかるようにインデントしよう
    • 自然な形の式(※条件式)を使おう
    • かっこを使って曖昧さを解消しよう
    • 明快に書こう
    • 副作用に注意
  3. 一貫性と慣用句
    • インデントとブレースのスタイルを統一しよう
    • 慣用句によって一貫性を確保しよう
    • 多分岐の判定には else-if を使用しよう
  4. 関数マクロ
    • 関数マクロはなるべく使うな
    • マクロの本体と引数はかっこに入れよう
  5. マジックナンバー
    • マジックナンバーには名前をつけよう
    • 数値はマクロではなく定数として定義しよう
    • 整数ではなく文字定数を使おう
    • オブジェクトサイズは言語に計算させよう
  6. コメント
    • 当たり前のことはいちいち書くな
    • 関数とグローバルデータにコメントを
    • 悪いコードにコメントをつけるな,書き直せ
    • コードと矛盾させるな
    • あくまでも明快に,混乱を招くな
Amazon CAPTCHA

「可読性」を検討する上では,これに加えて1画面で(スクロールせずに)読めるかどうか(行数,1行辺りの文字数)と言う指標も重要のように感じられるため,これを加えます.したがって,指標としては以下のようになるかと思います.

  1. 名前
  2. 式と文
  3. 一貫性と慣用句
  4. 関数マクロ
  5. マジックナンバー
  6. コメント
  7. 長さ(行数,1行の文字数)

各項目については,また追々何か書いていこうかと思っています.

蛇足: サンプル

「可読性」に関しては,以下のサンプルが面白いと感じました.

[問題] a ≠ b なら true, さもなくば false を引数として関数 int f(bool) を呼び、結果を c にセットしなさい。

// [1]
bool arg;
if ( a != b ) {
  arg = true;
} else {
  arg = false;
}
c = f(arg);

// [2]
if ( a != b ) {
  c = f(true);
} else {
  c = f(false);
}

// [3]
c = ( a != b ) ? f(true) : f(false);

// [4]
c = f( ( a != b ) ? true: false);

// [5]
c = f( a != b );
可読性ねぇ... - 東方算程譚

個人的には「読みやすさ」でも [5] なのですが,それとは別の観点から検討すると,このサンプルの [1] 〜 [3] に関しては,“c = f(true)/c = f(false)”(あるいは,“arg = true/arg = false”)と言う「対となる記述が存在する」と言う問題があります.

対となる記述には,(「必ずしも」とは言えませんが)「一方を修正した場合には,他方も修正しなければならない」と言う依存関係が生まれます.「[5] は初学者には分かりづらい」と言う批判がありましたが,[5] が読めない程度の初学者であれば「一方だけ修正して他方の修正を忘れた」と言うミスを犯す事は容易に想像できます(初学者でなくても忘れる).この時,コンパイラがエラーを吐いてくれれば良いですが,不幸にもコンパイルが通ってしまった場合には潜在的なバグを埋め込む事となります(これは,「コピー&ペースト」問題に近い性質となります).こう考えると,「可読性」とは別の理由で [1] 〜 [3] はあまり好ましいとは言えません.

例えば,3項演算子は「読みにくい」と言う理由で嫌われる傾向にありますが,以下の記述は if 文で代替する事はできません(右辺の式を関数として定義するしかない).

const bool c = (a != b) ? true : false;

「変数への(再)代入」と言う動作は,バグを埋め込みやすいものの一つです.そのため,変数への代入操作はできるだけ減らし,可能な箇所は上記のように再代入を禁止する(コンパイルエラーを発生させる)ように努めるのは初学者にとっても重要な事のように感じます.

「誤ってバグを埋め込んでしまう」問題に関しては,IDE の補助や先人達の効果的なテスト手法の提案によってかなり対策が強化されてきました.しかし,これらのものも使いこなすのにはそれなりの時間と労力が必要とされる為,初学者であればミスを犯してしまう事は容易に想像できます.そのため,プログラミング言語自体の各機能についても,「分かりにくい」からと言って隠すのではなく,きちんと伝えていく必要があるように感じます.