スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

デバッグ指向のススメ

予めおもんぱかれば、簡単であるが、後になっておもんぱかれば、複雑になる。
ゲーテ -『格言と反省
デバッグ指向プログラミング(debug-oriented programming)とは何か。一言で言うとすると、「デバッグしやすいプログラムを書きましょう」ということです。テスト指向(test-oriented)と近いところもありますが、よりデバッグの効率に重点を置いた考え方です。詳しい内容は今回だけでは書ききれませんが、とりあえず今回は、なぜデバッグ指向なのか、デバッグ指向とは具体的にどんなものか、ということについて書いてみたいと思います。

バグの発生は必然

バグの発生は予定外の出来事ではありません。よほど小規模のプログラムでない限り、ソースコードが一発で不具合なく動くことはほとんどありません。つまり、デバッグ作業というものは、ソフトウェア開発において重要なステップなのです。実際、大抵のソフトウェア開発では、コーディングそのものよりもデバッグに費やす時間の方が多いことが多いのではないでしょうか。つまり、このデバッグをいかに効率よく進められるかということが、ソフトウェア開発の効率を左右するといっても過言ではありません。

デバッグ効率をいかにあげるか

では、デバッグの効率はどのようにすれば改善できるのでしょうか?項目としてあげるとすると、
(1)バグのパターンを知り、解析・切り分け方法を習得する
(2)デバッガ・各種ツールを使いこなす
(3)デバッグ用のコードを埋め込んでおく
(4)デバッグしやすいコードを書く
といったところでしょうか。

(1)についてですが、設計手法と同様、デバッグ手法にもパターンや系統的手法が存在します。よくあるバグのパターンを知っていると、デバッグ効率もあがります。
(2)についてですが、最近のデバッガはかなり強力です。メモリリークやオーバーランの検出に有用なツールのあります。デバッガやツールを使いこなせるかどうかでデバッグ効率は大きく変わってきます。

(3)(4)が、デバッグ指向プログラミングの勘所です。デバッグ用のコードといっても単にprintfを埋め込めというわけではありません。勿論ログを残すというのは有効なデバッグ方法ですが、それだけではなく、assertの埋め込み、デバッガ向けコード、デバッグ関数の埋め込み等があります。開発対象がライブラリであれば、ライブラリ自身だけでなく呼び出し側でのデバッグも考慮します。

細かい点は追々追加していきますので、今回はデバッグ指向の一例として、契約プログラミングについて説明します。

契約プログラミング

契約プログラミング(DBC:Design By Contract)という言葉をご存知でしょうか。プログラムのコード上に、満たすべき条件を埋め込んでおき、違反があれば検出するというものです。最も基本的なものにassertがあります。ご存知のように、条件をチェックして、不一致であればログ出力後、abortするものです。
#include <stdio.h>
#include <assert>

#define ENTRY_MAX 5
int g_entry[ENTRY_MAX]

int
nth_entry(int n)
{
  assert(n < ENTRY_MAX && n >= 0)
  return g_entry[n];
}

上記のコードでは、nが5以上で呼び出されると、abortしてプログラムが停止してしまいます。違反が検出された時点でプログラムが停止するため、デバッガで動作させていればすぐにバックトレースをとることもできます。

では、assertがなかった場合、どうなるでしょうか?運がよければ、不正メモリアクセスでsegmentation faultか何かで同じく停止し、assert使用時と同様に発生地点を発見できるかもしれません。しかし、大抵の場合、不定値を返したあと、しばらく実行が続いたのちにバグが表面化するため、一体どこでバグが入ったのかを調べるのが大変になります。バグは発生した瞬間に捕まえないと非常にやっかいなので、assertで異常を見つけた瞬間に停止させるのは非常に有効な手段です。

まれにつぎのようなコードをみかけます。
#include <stdio.h>
#include <assert>

#define ENTRY_MAX 5
int g_entry[ENTRY_MAX]

int
nth_entry(int n)
{
  if (n >= ENTRY_MAX || n < 0)
    return -1; /* out of range */
  return g_entry[n];
}

配列の範囲外アクセスの場合、エラー(-1)を返すということになっています。外部提供関数であれば、これもありかもしれませんが、これが内部関数であれば、エラーを返す意味がありません。内部ロジックがおかしいのですから、エラーなぞ返さずに異常検出でabortした方が望ましいのです。誰もエラーチェックしないような関数でエラーを返す意味はありません。先のassertを入れたコードのようにするべきでしょう。

assertは非常に有用です。必ず満たしていなければならない条件がある場合は、こまめにassertをいれるべきです。関数の引数だけでなく、複雑なアルゴリズムの計算経過の確認などでも使えます。assertはコメントと違い、直接コードとリンクするのでコードとの不一致を起こすこともありません。

但し、assertを入れるとそのチェックが入る分、コードサイズや処理時間に影響を及ぼします。ですので、数が多い場合は、段階ごとにassertをOFFにできるようしておいた方が良いでしょう。
#define DEBUG_LEVEL 0

#if DEBUG_LEVEL > 0
#define ASSERT_1(x) assert(x)
#else
#define ASSERT_1(x)
#endif

#if DEBUG_LEVEL > 1
#define ASSERT_2(x) assert(x)
#else
#define ASSERT_2(x)
#endif

こうすれば、DEBUG_LEVELマクロで、一部のassertだけを有効にできます。

今回は契約プログラミング,assertについて説明しました。その他のデバッグ指向プログラミングに関するTIPSも本サイトでおいおい紹介していきたいと思います。ちなみに、「デバッグ指向」という単語は私の造語ですので、Googleで調べていただいてもhitしません。あしからずご了承ください (^^;)

※ D言語ではより強化された契約プログラミングの機能が言語レベルで実装されているそうです

4873114063 【関連記事】
バグのパターン

【関連リンク】
Linuxのデバッグ手法をマスターする
プログラミング言語D - 契約プログラミング

【関連書籍】
.NET&Windowsプログラマのためのデバッグテクニック徹底解説
Javaデバッグ明快技法
D言語パーフェクトガイド―一歩先行くC/C++/C#/Java開発者に贈るD

趣味と職業の違い

「職業としてのプログラミング」となんだかすごいタイトルをつけてしまいましたが、私自信まだまだプログラマあるいはソフトウェア技術者としての経験はまだまだです。
なので、そんなにえらそうなことを言える立場でもないですが、今からプログラマを目指そう、あるいは、自分の技術をステップアップしていこうという方にとって、なにかしら役に立つことが書けたらなと思います。

最初に、私が考える、「趣味としてのプログラミング」と「職業としてのプログラミング」の違いについて書きたいと思います。

■趣味としてのプログラミング
私も昔は趣味でプログラミングをしていた時期があります。主に作っていたのは、簡単なゲームなんかです。別にゲームをしたいってわけではなくて、プログラムを書くということが楽しくてやっていました。インターネットもそれほど普及する前で、作ったものをオープンソースで公開するとかいうこともなかったんですが、自分なりに綺麗なコードを書くこと目指してせこせこがんばってました。

このような趣味のプログラミングの特徴を書くとすれば、次のような感じでしょうか。
  • 最も重要な目的は、自分自信が満足すること
  • 自分のやりたいようにできる
  • 作ったものに対する責任はなし
  • 締め切りはなし!
例外もあるでしょうが、だいたいこんな感じではないでしょうか。
趣味なんだから、とにかく自分が楽しいことが重要ですよね。

■職業としてのプログラミング
職業としてのプログラミングは、当たり前ですが就職してからがメインです。就職前も、WebページのCGI等はちょっとだけやってました。ちなみに現在の仕事はいわゆるSEではなく、組み込み機器のソフト屋さんです。

職業としてのプログラミングになると、趣味のころには無かったような、いろんな制約が発生します。具体的には次のようになります。
  • お客さんの満足が第一義
  • 複数人での開発になることが多い
  • 開発を行う上でのルールがある
    (コーディング規約、言語、プロセス管理)
  • 作ったものに対する責任があり、品質確保が必須
  • コスト(時間、お金)に制限がある
職業としてプログラミングをする場合は、このような制約が必ず発生します。
個々について、もう少し詳しく説明しておきます。

○お客さんの満足が第一義
なんといっても、この点が最も違う点でしょう。仕事でやっている以上、お客さんが最も重要なのは言うまでもありません。
そんなの当たり前と思っていても、本人が良かれと思っていることが、案外技術的な自己満足で終わってしまっているというのもよくある話。
与えられた要求仕様を確実にこなすことは勿論ですが、潜在的な要求を見出していくのも、職業プログラマには必要な技術が必要になってきます。

また、時には嫌な(面白くない)仕事だってやらないといけません。

○複数人での開発
大規模なプロジェクトになると、大抵複数人での開発になります。複数人での開発では、進捗管理、リソース配分等が必要になります。勿論的確な意思疎通を行うコミュニケーション能力も必要です。

○開発上のルール
開発のルールといってもいろいろありますが、使える言語が指定されているというところから、コーディングルール、ドキュメント作成など、趣味の時とは違って、自由にならないことがたくさんあります。

○仕事に対する責任
仕事で作成したソフトウェアの多くは、なんらかの対価と引き換えにお客さんの手にわたります。早い話、お金を頂くわけですから、その成果物に対しては、作成者としての責任が発生します。
重大なバグ等は、お客さんへのご迷惑をおかけするだけでなく、製品の回収、あるいはアップデート費用等で会社にも被害を与えます。高品質ソフトウェア開発は非常に重要なテーマです。

○コスト
企業は利益をあげないといけません。社会への貢献も何もかも、つぶれてしまっては何もできないのです。開発作業では、決められたお金、時間の中で開発を進めますが、それぞれの開発者がコスト意識をもって開発にあたらなければ、良いものはできません。プログラミングそのものの技術だけでなく、プロジェクト管理等の技術も必要とされています。

とりあえず、思いつくままだらだらと書いてしまいましたが、おいおい掘り下げた内容を書いていきたいと思います。
人気エントリ
最近の記事
本のおすすめ

4274065979

4844337858

482228493X

4904807057

4873114799


最近のコメント
Links
プロフィール
  • Author:proger
  • 組み込み関係で仕事してます
ブログ内検索
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。