PSPプログラミングの第一歩
PSPプログラミングの第一歩として、自分が開発するプログラムのサイズとそれに掛かった時間を計測し、その平均値と標準偏差を計算するプログラムを設計、コーディングしてみましょう(可能な方は、ぜひフェーズごとの時間と欠陥も計ってください)。例えば、あなたのプログラム開発の実績が、PSP的計測方法によると以下の結果だったとします。
| プログラムID | 見積もりサイズ(KLOC) | 実際の開発時間(H) |
| A | 429 | 25.5 |
| B | 1586 | 140.3 |
| C | 227 | 20.8 |
| D | 98 | 5.2 |
| E | 3212 | 459.1 |
| F | 250 | 32.1 |
| G | 486 | 45.9 |
| H | 626 | 73.4 |
| I | 275 | 67.1 |
| J | 132 | 20.6 |
開発したプログラムのサイズが確定するたびに、このデータは増え続けます。そのため、データが何行になっても、その都度平均値と標準偏差を算出し続けるプログラムを開発してください。
欠陥とは
PSPでいう「欠陥」とは、『製品が完成するまでの間に修正されていなければならないあらゆること(要件定義、設計、実行時なども対象となりうる)』です。具体的には、各種設計ミス(ロジック設計ミス、変数設定ミスなど)、コーディングの誤植、バグ、異なる実行結果、などが挙げられます。
よく、「あ、欠陥ってバグのことでしょ?」と聞かれますが、単にコーディング時のバグだけを指すのではなく、要件定義や設計など、前述のPSPで定義されている開発の全6フェーズを対象とします。
標準偏差とは
標準偏差とは、平均だけでは表せない、データの散らばり具合を示す数値のことです。対象となるデータの平均値と各値の差を求めて二乗し(これを「分散」と呼ぶ)、それらの平均の平方根を取って求めます。標準偏差の詳細などについては、参考文献などを参照ください。
先ほどの表1の見積りサイズ(真ん中の列)において、分散を求めると次のようになります。
| プログラムID | 分散(KLOC) |
| A | 303.1 |
| B | 853.9 |
| C | 505.1 |
| D | 634.1 |
| E | 2479.9 |
| F | 482.1 |
| G | 246.1 |
| H | 106.1 |
| I | 457.1 |
| J | 600.1 |
では下記に、筆者がJavaで書いた解答例と実行結果を掲載します。
平均値と標準偏差の算出例
//---------------------------------------------- // Program Assignment: PSP1P1Pa // Name: Shinobu Minamikawa // Date: 03/12/2007 // Description: read two types of values and // calculating means and Standard Deviation: // To compile: javac PSP1P1Pa.java // To run: java PSP1P1Pa PSP1PIn.txt //---------------------------------------------- import java.io.*; class PSP1P1Pa { public static void main(String args[]) { try { //-------------------------------------------- // FileReader object FileReader fr = new FileReader(args[0]); // BufferedReader object BufferedReader br = new BufferedReader(fr); // StreamTokenizer object StreamTokenizer st = new StreamTokenizer(br); // "comma" as a blank character st.whitespaceChars(',', ','); //-------------------------------------------- // Variables double size_array[] = new double[100]; double size_SD_array[] = new double[100]; double size = 0.0; double total_size = 0.0; double mean_size = 0.0; double total_SD_size = 0.0; double SD_size = 0.0; double hours_array[] = new double[100]; double hours_SD_array[] = new double[100]; double hours = 0.0; double total_hours = 0.0; double mean_hours = 0.0; double total_SD_hours = 0.0; double SD_hours = 0.0; int n = 0; // the number of the items boolean is_size = true; //-------------------------------------------- // Main Process //-------------------------------------------- //-------------------------------------------- // reading the input table into arrays while(st.nextToken() != StreamTokenizer.TT_EOF) { switch(st.ttype) { case StreamTokenizer.TT_WORD: break; case StreamTokenizer.TT_NUMBER: if (is_size) { size_array[n] = st.nval; is_size = false; } else { hours_array[n] = st.nval; is_size = true; n += 1; }; break; default: ; } } //----------------------------------------------- //calculating_1: mean for(int num = 0; num < n; num = num +1) { total_size = total_size + size_array[num]; total_hours = total_hours + hours_array[num]; }; mean_size = total_size / n; mean_hours = total_hours / n; //----------------------------------------------- //calculating_2: Standard Deviation //----------------------------------------------- //-------------------------------------------- for(int num = 0; num < n; num = num +1){ size_SD_array[num] = size_array[num] - mean_size; hours_SD_array[num] = hours_array[num] -mean_hours; }; //-------------------------------------------- for(int num = 0; num < n; num = num +1){ size_SD_array[num] = size_SD_array[num] * size_SD_array[num]; hours_SD_array[num] = hours_SD_array[num] * hours_SD_array[num]; }; //-------------------------------------------- for(int num = 0; num < n; num = num +1) { total_SD_size = total_SD_size + size_SD_array[num]; total_SD_hours = total_SD_hours + hours_SD_array[num]; }; SD_size = total_SD_size / (n-1); SD_size = Math.sqrt(SD_size); SD_hours = total_SD_hours / (n-1); SD_hours = Math.sqrt(SD_hours); float fnum1 = (float)mean_size; float fnum2 = (float)mean_hours; float fnum3 = (float)SD_size; float fnum4 = (float)SD_hours; //-------------------------------------------- //printing the result //-------------------------------------------- System.out.println("Mean" + " " + "Std. Dev"); System.out.println(fnum1 + " " + fnum3); System.out.println(fnum2 + " " + fnum4); //----------------------------------------------- //close this process //----------------------------------------------- fr.close(); } catch(Exception e) { System.out.println("Exception:" + e); } } }
平均値 標準偏差 732.1 971.9071 89.0 135.73192
まとめ
今回の骨子をまとめます。
- PSPとはパーソナル・ソフトウェア・プロセスの略である
- PSPの目的は「ソフトウェア開発における改善」
- 最初に現状を知ることから始める
- 現状を知るには、PSPが定義する6つのフェーズにかかった時間を計ることから始める
- 計測対象には、「欠陥」(コーディング以外も対象)も含まれる
上記のような実感を持っていただけたら、alright! です。
いかがだったでしょうか。コーディングはいざ知らず、時間計測の作業などは、思いのほか面倒かもしれませんね。お疲れさまでした。
次回からは、コーディングそのものはもちろん、PSPプロセスにまつわる作業も少しずつお話ししていきます。「我こそは!」と心ひそかに意気込むあなたや、「へっ、ミナミカワのコーディング大したことないし」と思っている経験豊かなプログラマの方にとって、プロセス部分のエクササイズは少し辛抱が必要な部分もあるでしょう。
PSPが要求するプロセスの説明部分などの面倒な部分は適宜読み飛ばしていただいて、一緒に最後まで頑張っていきましょう!
参考文献
- 『PSP: A Self-improvement Process For Software Engineers』 Watts S. Humphrey 著、Addison-Wesley Pub、2005年3月
- 『図解雑学 統計解析』 丹慶勝市 著、ナツメ社、2003年3月
