ソフトウェア技術者のためのバグ百科事典(3)意外に厄介なデータ入力ミスのバグ山浦恒央の“くみこみ”な話(124)(1/4 ページ)

ソフトウェア技術者に向けて、バグに関する基礎知識をまとめていく新シリーズ「バグ百科事典」。第3回は、ある意味プログラマーにとって理不尽で、意外に厄介でもある「データ入力ミスのバグ」について解説します。

» 2019年12月10日 10時00分 公開
※本ページはアフィリエイトプログラムによる収益を得ています

⇒連載「山浦恒央の“くみこみ”な話」バックナンバー

1.はじめに

 ソフトウェア開発エンジニアのみなさんは、「バグを未然に防ぎたい」と思いつつ、デバッグでは、「バグの原因がなかなか見つからない……」と悩んでいると思います。本シリーズでは、バグの原因をテーマ別に分類し、百科事典のように紹介します。将棋なら「棒銀」「四間飛車」「ゴキゲン中飛車」「三間飛車」「相掛かり」「矢倉」「藤井システム」のように、戦術別にまとめた解説書とお考えいただければ分かりやすいと思います。

 今回は、筆者の体験を中心に「データ入力のミス」に起因するバグを取り上げます。これは、「プログラミングのロジックは正しいのに、初期設定として内部や外部から入力したデータ値が正しくないため、結果が不正になったバグ」です。「プログラマーには理不尽なバグ」もあります。

2.制御構造とデータ

 プログラムを意図した通りに動作させるには、「制御構造」と「データ」をコンピュータに正しく指示する必要があります。どちらが欠けても、不可解な動作不良を起こします。

2.1 制御構造

 制御構造とは、プログラムの流れのことで、C言語では「if, then, else」「for」「while」と「モジュールの呼び出し」が相当します。ソフトウェア開発エンジニアが言う、「ロジック」です。プログラマーには、「ロジックが正しい」が全てですが、後述のように「データが正しい」との視点で見る必要もあります。

スパゲティ ※写真はイメージです

 今から50年前の「石器時代のプログラミング」では、C言語などの高級言語は一般的ではなく、アセンブラの全盛期でした。メモリが「貴重品」だったため、プログラムがメモリを占有する量を最小限にするため、1ステップでも短いプログラムを作りました。その結果、いわゆる「GO文」を使い、「スパゲティ構造」と呼ぶめちゃくちゃな制御構造を駆使し、「最小体積のプログラム」を作ったのです。

 例えば、あるモジュールの途中から、別のモジュールの真ん中へジャンプし、また元のモジュールへ戻る「段違い平行棒」的なロジックは当たり前。これは、例えば、他人の家を訪問する場合、トイレの窓から入って、ベランダから出ていくような制御構造で、そんなプログラムを日常的に作っていました。

 こんな「スパゲティ構造」をしたソースコードは、他人どころか、作った本人が読んでも理解できませんでしたし、保守も不可能でした(これは、日本史に例えると、「大化の改新」以前でしょうか)。そこで提唱されたのが「構造化プログラミング(structured programming)」で、図1の4つの制御構造だけを使い、かつ、入口と出口が1つだけのモジュール構造をいいます(これが、プログラミング文化の「大化の改新」です)。

 今では、高級言語を使ってコーディングする限り、必ず、構造化プログラミングになりますが、これは、プログラミング言語の文法として、4つの制御構造しか許さないように制限を課した結果であり、「強制的な構造化プログラミング」です。

 これら4つの制御構造だけを使い、「GO文」を使わないプログラミングは、現在では当たり前ですが、1970年代のソフトウェア開発では、「GO文」を使い、好きな場所に制御をジャンプさせる構造が普通でした。また、上記の4つの構造を備えた高級プログラミング言語も存在しなかったことから、「GO文を使わないでプログラミングするのは非現実的だ」と、大多数のプログラマーが大反発した「戦国時代」がありました。

 筆者は、「制御構造をきれいに構造化したのが『構造化プログラミング(=大化の改新)』であり、データを構造化したのが『オブジェクト指向(=明治維新)』である」と思っています。このテーマを掘り下げるには、多くのページ数が必要ですので、プログラミングの「鎌倉幕府」とか、「江戸幕府」のような「ディープな歴史のお話」は、また別の機会で集中的に触れます。

図1 図1 構造化プログラミングの4つの制御構造(クリックで拡大)

2.2 データ

 プログラミングで「制御構造」と対になるのが「データ」です。今回のコラムで取り上げるのは、データ入力のバグですので、上記の「4つの制御構造」は「寄り道」として軽くお考えください。

 今回のテーマである「データ入力のバグ」は、制御構造やデータ構造のバグではなく、変数の値(例えば、int size = 30)そのものです。プログラムを正しく動作させる場合、制御構造が正しくても(ロジックが正しくても)、データを間違えると、正しい結果になりません。

 簡単な例として、「映画の入場料金の計算プログラムで、年齢が成人(20歳以上)は2000円、未成年(20歳未満)は1000円と表示」するプログラムを考えます(リスト1)。

	int seijin = 20;
	printf("年齢を入力してください\n");
	scanf("%d",&age);
	if (age >= seijin) {
printf("入場料金は2000円です");
} else {
printf("入場料金は1000円です");
}
リスト1 映画館入場料計算プログラムの例題(一部抜粋)

 上記は、映画館の入場料計算の実装例です。20歳以上の成人ならば2000円、未成年ならば1000円という制御構造は、if文で制御しています。また、成人年齢を表すデータは、「int seijin = 20;」で定義しています。成人年齢を初期設定した後、コンソールから、「入場者の年齢データ」を入力し(それを「変数age」としてプログラム内で処理する)、成人か未成年を決定し、入場料を表示しています。

       1|2|3|4 次のページへ

Copyright © ITmedia, Inc. All Rights Reserved.