自戒プログラミング

Last-modified: 2007-03-29 (木) 12:37:38

自分用こうあるべきだ・・・

以下に、自分がプログラミングをするときに気をつけるべき項目をメモしておく。
必ずしも自分のソースがこれらを満たしているとは限らない←精進。

ちょう基本

  • コメントをつける
  • インデントをつける
  • 警告レベルを下げず、コードを直す
  • マクロを使わない

変数名/関数名/型名などの名前

  • 名前は「What」でつける。「How」でつけない。←つまり「何をするものなのか」という名前をつける。「どうやってやるのか」という名前をつけない。たとえば「Calc~()」という関数名は微妙、「Get~()」が正しくないか?

コメント

  • 変数、関数などには、それを用意した意図を書いておこう。
  • たとえば「XがaのときはAを実行、bのときはBを実行」というコメントはわかりにくいかも。重要なのは、「Xによって実行される処理が変わる」ということで、その後で付記として「aならA」というふうに箇条書きにする方がわかりやすいかも。
  • switch-caseで、何もしないcaseラベルがある場合は、「/* nothing to do */」とか書く。
  • switch-caseで、意図があってbreakのないcaseラベルを書く場合は、「/*FALLTHROUGH*/」と書く。
  • とりあえず作った空の関数には、/*todo*/とか書いておく。

変数

  • 意味のある変数名
  • 変数を別の用途に使わない
  • 目的が抽象的な変数を作らない
  • 変数名を省略しすぎない
  • 変数名を大文字小文字などで区別しない
  • 変数名にnew/oldをつけて区別しない
  • 変数名に1,2,3などをつけて区別しない
  • グローバルな変数ほど長い名前をつける
  • 初期化する(未初期化や無用なコンストラクタを呼ばせないため)

関数

  • 意味のある関数名
  • 関数を別の用途に使わない
  • 機能が抽象的な関数を作らない(引数型の抽象化は良い)
  • 関数名を省略しない
  • 関数名を大文字小文字などで区別しない
  • 関数名にnew/old/exなどをつけて区別しない(exは、その後の拡張性を失くす)
  • グローバルな関数ほど長い名前をつける
  • グローバル関数は作らない(せめて無名名前空間に入れる)
  • 関数マクロを使わない(ソースコードデバッグができない)
  • できるだけ最小の機能ごとに関数を切り分ける(見通しがきく)
  • とりあえず作った空の関数のうち、空であることで問題を誘発する恐れがあるなら、その関数内で実行を止めるか、関数内でエラーメッセージを表示する。

C++

  • constにする
  • 継承されない親クラスをvirtualにしない
  • 継承される親クラスをvirtualにする

設計

  • 値自体には意味のない定数には、enumを使う
  • 実行時エラーは出さない。コンパイル時エラーになる工夫をする
  • 実行時エラーは出さない。実行時に回避できるように設計する
  • switch~caseやif~elseは条件追加忘れの温床になる。なるべくならデザインパターンのState/Strategyパターンを使う。
  • 内部でのエラー処理は、Fatal - Error - Warn - Info - Debug と段階をつける。

アクセス権

  • 公開するものは、とことんテストする。「公開してもいいかな?」で公開しない。
  • 非公開のものは、その中で起こるエラーが公開するものに絶対波及しないようにする。

デバッグ

  • 自動テストを行う
  • デバッガを使う

マルチスレッド・マルチコア

  • 複数のスレッドから同じ変数にアクセスするような仕様はやめよう。
  • どうしても同じ変数にアクセスするなら、事前にロックしよう。
  • あるいは、Atomic的な構造を仕組もう。
  • ハイパースレッドでは定期的にSleepしないと、他のスレッドが動けない(?)。
  • Sleepして他のスレッドを待つような場合でも、タイムアウトは必要。

その他

ブロック内の式文を少なく、階層は浅く。

たとえば以下のようなものを考える。

void func1(void) {
   if (...) {
     .........
     .........
     if (...) {
        .........
        .........
        .........
     } else {
        .........
        .........
     }
     .........
     .........
   }
}

これは中括弧の整合性などが取りにくいので、以下のようにする。

void func1(void) {
   if (...) {
     .........
     .........
     func2();
     .........
     .........
   }
}
void func2(void) {
  if (...) {
     .........
     .........
     .........
  } else {
     .........
     .........
  }
}

関数は、なるべく単機能になるように切り分ける。
そしてその関数が本来やりたかった事項のみを処理できるようにする。
細かい処理は、他の関数に切り分ける。