堅牢なコーディングルールを策定する方法(1)

「ある処理をするコードを書く」というのは「ある出来事を文章に表現する」のと似ていると思っている。

まず表現に使う言語は様々であり、使用人口の大小はあれど、基本的に優劣はない。言語が同じだったとしても、十人十色の表現をし、全く同じ出来事を表現したものであっても、複数人が全く同じ文章を作る可能性は限りなく小さい。同じ人が表現するんであっても、今と昔で「全く同じ文章」を書くとは限らない。むしろ微妙に差異があるのが普通だ。

そんな「コーディング」に一貫性を持たせるのがコーディングルールだ。インデントはスペース4つだとか、braceの位置はどうだとか。複数人で小説を執筆する*1場合は、「ですます調に統一しよう」とか色々な取り決めをすると思う。このあたりの一貫性がないと、非常に読みにくい小説が出来上がるだろう。

とまぁ、ルールってのは、複数人間の意識合わせのために*2存在する。例えば法律もそうだ。そして、誰から見ても同じ判断ができることが望ましい*3。

例えば、コードレビューをするにしても「これを指摘すべきか否か」はルールに依存する。例えばルールが「各自が気持ち良いように書くべし」だったらば、指摘すべきか否かは判断がつかない。まぁ、その人は気持ちよかったんだろうなぁ、いや、もしかしたら気持ち悪いと思いつつも書き進めてしまったのか? ……エンジニアの時間は貴重である。こんなことに頭を悩ませるなんて勿体無い。

ざっと考えてみたのだが、ルールは以下のような性質を持つべきであると考えている。

  • ルールに合致するか、逸脱しているかが明確である
  • いつ、どこで、だれが判断しても、ルールが変わらない限り同じ答えが出る(環境に依存しない)
  • 結論を出すプロセスがライトウェイトである
    • 複数人が集まって議論しないと結論が出ない、とかはヘビーウェイトですね。
    • 大量の文書を読んだり、複雑な判断プロセスを経ないと結論を出せない、とかはヘビーですね。


以上のような性質を持つルールを作るには、どうしたらよいだろうか? Jiemamyでは、出来る限り上記の指針に従ったルールを策定し、採用しようと努めている。まずは以下の問いに答えられるようなロジックを作ってもらいたい。

「あるコードをバグであると判断する手順はどんなものか?」つまり「バグとは何か?」*4である。

public class Foo {
  private int bar;

  public String getBar() {
    return String.valueOf(bar);
  }

  public void setBar(String bar) {
    this.bar = Integer.parseInt(bar).intValue();
  }
}

public class Main {
  public static void main(String[] args) {
    Foo foo = new Foo();
    foo.setBar("hoge");
    System.out.println(foo.getBar());
  }
}

このコードは、実行するとNumberFormatExceptionでプロセスが終了する訳ですが。このコードにバグはあるだろうか? あるとしたら、どこがバグなのだろうか? 可能性を考えてみる。

  1. Fooのバグ説
    • Foo#setBar()ではあらゆるStringを引数で渡せるべきであり、hogeを受け付けないFooが悪である。
  2. Mainのバグ説
    • Foo#setBar()には、Integerの範囲の数値しか渡すことができず、"hoge"なんつー文字列を渡したMainが悪である。
  3. バグはない説
    • このプログラムを実行するとNumberFormatExceptionが発生する、というのが正常な動作である。
    • 仮にNFEが発生しなければ、どこかにバグがある。
  4. その他、まだあるかも?


上記諸説の中から「明確に」「環境に依存せず」「ライトウェイトに」唯一を選び出すロジック。それを各自作ってみて欲しい。私が採用しているロジックは後日ご紹介する。

*1:なんてケースがあるのか知らんけど

*2:一人プロジェクトだったとしても「昔の自分」と「今の自分」の間の整合性を取るのに有効だと思う。

*3:ただし、言葉で表現するのである程度曖昧になることは避けられず、ベストエフォートで対応すべき、という感じか。

*4:アプリケーションレベルでのバグではなく、コードの粒度におけるバグのこと