ウィリアムのいたずらの、まちあるき、たべあるき

ウィリアムのいたずらが、街歩き、食べ物、音楽等の個人的見解を主に書くブログです(たま~にコンピューター関係も)

デスマーチになるのは、プログラムが書けないからでなく、”おじさんの運動会”だからだ

2007-05-11 18:27:37 | Weblog

さいきん、これ
どうしてプログラマに・・・プログラムが書けないのか?
http://www.aoky.net/articles/jeff_atwood/why_cant_programmers_program.htm

がはやっているようだ。

この文を読んで。。
あー、この書いた人がプロジェクトマネージャーになったら、開発はデスマーチ、プログラマは地獄だろうなと思った。

どうしてか。。を書く前に、まず、ここで話題になっている話を1つ
(以下斜体は上記サイトより引用)

ここでは、「Fizz-Buzz問題」というのを取り上げている。
それは、


1から100までの数をプリントするプログラムを書け。ただし3の倍数のときは数の代わりに「Fizz」と、5の倍数のときは「Buzz」とプリントし、3と5両方の倍数の場合には「FizzBuzz」とプリントすること。


というものです。

で、それについて、

 ちゃんとしたプログラマであれば、これを実行するプログラムを2分とかからずに紙に書き出せるはずだ。怖い事実を聞きたい? コンピュータサイエンス学科卒業生の過半数にはそれができないのだ。自称上級プログラマが答えを書くのに10-15分もかかっているのを見たこともある。


うん、この人は、プログラマでよかった。。
この人がSEかマネージャーになったら、このプロジェクトはデスマーチになるだろう。
もし、上級プログラマが10分かかっていて、
コンピュータサイエンス学科卒業生の過半数ができないのに、
自分が2分でできると思っていたら、
それは、世間が間違ってるんじゃなくって、自分の考えが間違っている。




そう考えないと、”おじさんの運動会”になってしまう。

おじさんが、子供の運動会に参加することがある。
そうすると、おじさんはなぜかこける・・・
なぜ、こけるのか。。
自分は走れるとおもっているけど、体はそう動かない。
なので、こけるのだ。

それと同じ。自分は2分でできると思って、計画を立てておいて、
2分でできない人が続出した場合、プロジェクトはこけてしまう。
でも、2分でできると思い続けている限り、
なぜ10分かかるのかの理由がわからないから、
永遠と転び続ける。。。

デスマーチの多くの原因は、この、勘違いによることがおおい。
プログラム能力の差異は、実は教育方法があるから、埋められるのだ。。
(その教育方法を、大学やプログラマが知らないということがあるのだが。。)




さて、このケースでは、なぜ、2分でできると考え、自称上級プログラマが10分かかるのか、考えて見ましょう。

まず、2分でできると考えた人は、こういうプログラムを書くと思う。

public class testpro2 {

	public static void main(String[] args) {
		for(int i = 1 ; i <=100 ; i ++ )
		{
			if ( (i % 3 == 0 ) && ( i % 5 == 0 ) )
			{
				System.out.println("FizzBuzz");
			}
			else if ( i % 5 == 0 )
			{
				System.out.println("Buzz");
			}
			else if ( i % 3 == 0 )
			{
				System.out.println("Fizz");
			}
			else
			{
				System.out.println(i);
			}
		}
	}
}

(上記< > ¥は、本当は半角です)




ここで、悩んだり、できなくなったりする理由は、この書き方が、仕様書とはちがっていることだ。

仕様書は、あくまでも

1.3の倍数かどうか調べよ!
2.5の倍数かどうか調べよ!
3.3と5の倍数だったら。。

ときている(たぶん、意図的にこの順番にしている)。

ここで、testpro2のif文を、この仕様書の順番で、

if ( i % 3 == 0 )

からはじめてしまうと、3と5の倍数のときも、これにひっかかって
Fizzと印刷してしまう。

かといって、elseifをつかわないで、ifでかいて
if ( i % 3 == 0 )
{
	System.out.print("Fizz");
}

if ( i % 5 == 0 )
{
	System.out.print("Buzz");
}



と書くと、今度は15の倍数のときの条件を、
仕様書には書かれているのに、プログラム上は書かない上に、
なにも出力しない場合、数字を書き出すためのフラグを持たないといけない。




もちろん、仕様書を無視し、同じ結果が出ればいいと考えるかもしれないが、
これをやり始めると、デスマーチになるのだ。。
修正で想定外のことが起こる危険がある。

たとえば、3と4の倍数の場合。。というのを仕様書に追加したとしたら、
それは(上記testpro2中でしめした)3と5の倍数の上に書くのか、
下に書くのか、このとき、どちらにかくかで、60で違いが出てくるのだが、
そーいう複合条件における、仕様のもれが、まさにデスマーチにつながってくる。

だからこそ、仕様書と、プログラムの条件判断は、あわせたいのだ。




で、この問題は、こうやって考えると(このケースでは)解決する。
(たぶん、この方法で解決するように条件が並べてあるように見える)

王道は、崩すべきではないのだ。
条件判断は、まず、
1.判断する値を全部集める=>今回はない

ここで、状態によって処理を換える場合は
2.わたしはだーれ?と聞き、状態を決定する
3.状態=>処理に変換が必要なら変換する
4.処理をディスパッチする

という方法をとる。さっき書いた決定表のketteiCntl.javaにおいても
そのようになっていて、「条件判定」が2にあたり、「実行」が4にあたる。
この間に、3に相当する「実行条件の選択」というのが入っている。

今回の処理の場合、3が必要ない(起動する処理は1つ、「印刷する」なので)

したがって、それを考えると、こういうプログラムになる。
/**
 * 
 * Fizz-Buzz問題
 * 
 */
public class testpro1 {

	/*
	 * 実行部分
	 */
	public static void main(String[] args) {
		
		//	メイン処理(100までループ)
		for(int i = 1 ; i <= 100 ; i++)
{ int sts = 0; //==========================// // 条件判断部分 // //==========================// // 3の倍数 if ( i % 3 == 0 ) { sts = 3; } // 5の倍数 if ( i % 5 == 0 ) { sts = 5; } // 3と5の倍数 if ( ( i % 3 == 0 ) && (i % 5 == 0 ) ) { sts = 15; } //==========================// // 処理部分 // //==========================// switch(sts) { case 3: System.out.println("Fizz"); break; case 5: System.out.println("Buzz"); break; case 15: System.out.println("FizzBuzz"); break; default: System.out.println(i); break; } } } }

(上記< > ¥は、本当は半角です)

 こうすれば、条件変更があっても、「条件判断部分」が仕様書と一致しているので、仕様変更があったときでも、「仕様書と同じ順番でやってます。」といいきれる。
 同じ順番でやっている以上、仕様書どおりの順番で書いて、おかしくなっても、(さっきの例だと、3と4の倍数を、3の倍数の前に入れようが、3と5の倍数の後に入れようが、仕様書と同じ順番でコーディングできる。その結果、おかしくなったとしても)「いやー、あんたが書いたとおりやっておかしくなったんだから、そりゃーあんたが悪い」とは、口が裂けてもいえないけど、仕様の書き手に対して、どうしておかしくなったかは伝わる。

 そうすれば、仕様書の書き手とプログラムが一致するので、書き手があらかじめ順番を考えることができる。さらに、仕様書とプログラムが一致すると、自動生成の可能性も出てくる。ワーカーにも説明がつく。

 ワーカーに説明できる=プログラムが書ける必要性はないのだ。
 こちらの説明どおりに書いてくれれば、いいわけだし、自動生成にもちこめば、まさにかける必要はない。

 実際にプログラムを書くのはウィリアムのいたずら、後の人は、Excelシートをがんばって保守っていう作業もある。これで、1000個のソースとかを自動生成して管理する(保守要員1名で)という話もある。たぶん、保守してる人は、プログラムかけないと思う。でもシステムは回っているのだ。これでOK!




ところが、プログラマ側で勝手に仕様書と書き方を変えてしまうと、ちとこまる。
仕様書の書き手は疑心暗鬼になってくるし、実際、論理が破綻してしまうこともある。

保守も???ってなってくる

プログラマの技量によるところ大になり、自動生成もできない
(だから、1000個のプログラムを1人で直す。。。は無理なので、何人かに分けてとなり、人も増える)。。。

あちゃー、デスマーチなのですよ。。。

でも、こーいう事態が結構あるんだけどね。。




ちなみに、じゃあ、条件がすべて、上記のような体系でかけるかというとそうではない。

 まず、条件には、単純なIF文と、状態判定をするような複雑なケースがあり、複雑なケースにおいては、オプション型の、どんどんやることを追加していくものと、状態型のある1つの状態のとき、やることはこれ!という方法がある(今回は状態型を採用した)。
 そして状態型は、決定表に持ち込む方法と命題に持ち込む方法などがある(今回は命題に持ち込む方法を採用した)、詳しい話は、「開発の初めから順番に書いていってみる」で、決定表の話が終わった次に、条件判定の体系化というようなかんじの話で行う予定ですけど(そこで、どうして今回の条件の並べ方が、意図的に感じられたかは書きます)。。。

 今回は、そのなかの1つをつかって、ばちんとうまく言ったって言う話。

 だけど、これ、多分話をよんでしまえば、

 なーんだ!

 でおわってしまう話なんで。。あんまり、重要なことではない。
 (大学とかで、教えてあげればいいのに。。昔は、会社で教わったのね)




 で、実際、eclipseを立ち上げてから、testpro1をコーディングしてテストし、コメントを入れるまでで、だいたい10分かかった。

 つまり、上級の人は、
1.はじめに2分でおもいついている
2.でも、「いやまてよ、仕様変更があったら?」と考え直し
3.こっちの方法のほうが、きれいだよね!と考えを変えて
4.それをコメント入りできれいにコーディングしている

だから、10分かかってるってことだとおもう。

15分の理由、つまりあと5分でなにをしているかというと、いろんな言語をやっている人の場合、倍数のあまり0は、%なのか、mod関数なのかが気に係り、ネットでチェックしてるんだと思う。上級者になるほど、そーいうところは確認するような気がする。
(英語、できるやつほど辞書で確認をとるっていうやつ)

なので、この5分は別に。。指摘するほどのことでもない。

むしろ、重要なのは、思いついたプログラムをすぐに書くんじゃなくって、
一回、考えをためてから、書いていることだ。
 この「考えをためて、冷静になって考える」ことをしないと、ぐちゃぐちゃな場当たり的なプログラムになってくる。
 この差のほうが、むしろ重要だと思う。




あ、このほかにも、さっきの「どうしてプログラマに・・・プログラムが書けないのか?」「連結リストを実装」あー、そーねそーね、CのポインタにおけるJavaでの実装の問題、デザインパターンのおはなしとか、あのへんねえ。。。とか「実際的な問題を解くのに再帰が使える」あーそーねそーねー、再帰の実装の問題ねえ。。

と話したいことがみつかっちゃったんだけど、いい加減長くなりすぎたので、今回はここまで(シリーズ化しちゃう?)

  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

プログラムやテストデータを自動生成する方法 その5 作業一覧

2007-05-11 16:16:20 | 開発ネタ

雛形ソースを作成し、Excelの仕様書を用意すると、プログラムのソースやテストデータを生成する方法について説明するシリーズ、「プログラムやテストデータを自動生成する方法」です。

 第二回目で、インストールしました。
 それ以降、このシステムで利用する、
  ・雛形
  ・仕様書
  ・ソースファイルを作るExcelマクロ
 について順に説明し、今回は「ソースファイルを作るExcelマクロ」のところです。

 といっても、このマクロの中身については、もっと先にやるつもりです。
 今回は、書き出しのときに指定する、「作業一覧」シートについて指定します。




■「作業一覧シート」とは

 実際に、どの雛形とどの仕様書のシートを使って、どのファイル名で書き出すか?というのを指定するシートが、「ソースファイルを作るExcelマクロ」の中にある、「作業一覧」シートです(なので、このシートは削除してはいけません)。

 前処理でこのシートに書き出す場合もあるし、手入力で書く場合もあります
 (実際の読み込みは、前処理の後に行いますので、そのとき、できていればOKです。
  また、後処理に入る前にいらなくなりますので、後処理で削除するのはOKです)

作業一覧シートは、このようになっています。


 この図にあるように5行目から書き始め、
  A桁に雛形ファイル、
  B桁に、作業用シート名
  C桁に出力先のファイル名
をかきます。
この、桁と開始行(5行目)は固定です。変えられません。
なお、「作業一覧」というシート名も変えられません。固定です。
(VBAを修正すると変えられますが、それを知りたい人は、マクロを見てください。
 マクロ中に分かりやすく書いてあります。ある値を換えるだけです)

5行目から作成したいものを順次記入していきます。
このとき、空白行を作らないでください。
そこで作成はとまります(A桁が空白の行まで処理を行います)

書き終わったら、「ドキュメント作成」ボタンをクリックします。




■A,B,C桁を計算式にすると。。

 ただし、A,B,C桁の値は、文字列でなければならないわけではありません。
 計算式でもOKです。

 たとえば、出力先名に指定するファイル、この一覧がどこかにあるようなケースでは、
以下のように

そのファイル名一覧を、E桁など、A,B,C桁以外のところにおいておいて、
フォルダをどこかあまったところに指定すれば
(例:上の図では、ファイル一覧をE桁、出力先フォルダをセルD4に指定

出力先名を、計算式で指定してもOKです
(図の場合、セルC5を
   =$D$3 & "¥" & E5 (全角¥は本当は半角)
と指定している)

こうすることによって、出力先をフォルダごと変えたい場合、便利です。




 ということで、一通りの説明が終わったので、次回から例を挙げて、
サンプルを作ってみたいと思います。


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

開発の初めから順番に書いていってみる その41:プログラミング(3)決定表 2-ソース

2007-05-11 12:00:54 | 開発ネタ

 シリーズ「開発の初めから順番に書いていってみる」の続きです。
 設計手順には、要求分析、外部設計、内部詳細設計・プログラミング、単体テスト、結合テスト、総合テスト、運用テスト及び運用とあります。
 現在プログラミングで、決定表と自動生成の話題を書こうと思っています。

 今日は決定表の2回目で、自動生成しやすくするための、決定表のプログラムです。




■仕様

 まずは、きのうから取り上げている、決定表を確認しておきましょう。
 これです。
30歳未満  Y Y N N
男性     Y N Y N
既婚者    N Y Y N
──────────────
帳票1を出力 - X - -
帳票2を出力 - - - X
帳票3を出力 X - - -
帳票4を出力 - - X -


ここ http://homepage2.nifty.com/mitsugumorita/98as/98asm03.htm
より引用(情報処理試験の問題らしい)


問題の難易度を上げるためと思われますが、この決定表はすべての場合について書かれているものではありません(それについては、昨日書いた




■基本方針

 で、基本的な考え方なのですが、決定表は、MVC(もでる・びゅー・こんとろーる)で考えると、コントロールの役割を示します。

 で、実際のモデル部分と分離するためには、
帳票1を出力 ==> 処理1を実行(処理1で帳票1出力)
帳票2を出力 ==> 処理2を実行(処理2で帳票2出力)
   :
   :
 のように、コントロール側ではモデルの処理部分を呼び出し、処理部分のところで、帳票出力などの記述をするようにします。

 また、上記の決定表では、年齢などなどが必要なのですが、これは、ビュー部分(といっても、今回はバッチ起動なので、起動されるところがビューになりますが)で設定して・・というようにしています。

そこで、クラスは、本当は一本で、もっと簡単にかけるのですが、

 ・呼び出しクラス(ビューに相当)
 ・決定表の部分(コントロールに相当)
 ・実行部分(モデルに相当)

として、3つに分けています。将来、自動生成するのは、「決定表の部分」であり、決定表変更ごとに自動生成できますが、実行内容に関しては、クラスを分離しているので、処理内容記述に影響はでないようにしています。




■ソース
では、実際のソースです。
今回、
 ・呼び出しクラス:Kettei.java
 ・決定表の部分 :KetteiCtrl.java
 ・実行部分   :KetteiModel.java
のようになります。

●呼び出しクラス:Kettei.java
import java.util.*;

/**
 * 
 * 決定表の例
 * 
 */
public class Kettei {

	/*
	 * 	メイン処理
	 */	
	public static void main(String[] args) {

		//	引数チェック
		if ( args.length < 3 )
		{
		System.out.println("引数は3つのはず");
			return;
		}
		
		//	データセット
		HashMap	map	=	new	HashMap();
		map.put("age",args[0]);
		map.put("seibetsu",args[1]);
		map.put("kikon",args[2]);

		//	処理実行	
		KetteiCntl ketteiCntl = new KetteiCntl();
		ketteiCntl.execute(map);
	}
}

(上記 ¥ < > は、本当は半角です)


●決定表の部分 :KetteiCtrl.java
import java.util.*;

/**
 * 
 * 決定表のコントロール部分
 */
public class KetteiCntl {

	/*
	 * 右側の上のYN
	 */
	public static final String[] zyoken_list={
			"YYN",		//	0
			"YNY",		//	1
			"NYY",		//	2
			"NNN"};		//	3
	/*
	 * 右側の下の実行内容
	 */
	public static final String[] todo_list={
			"--X-",		//	YYN
			"X---",		//	YNY
			"---X",		//	NYY
			"-X--"};	         //	NNN

	/*
	 * 	決定表の実行処理
	 */	
	public int execute(HashMap map) 
	{
		//======================//
		//	データ取得     //
		//======================//

		//	年齢
		int	age	=	0;
		try
		{
			String buf =	(String)map.get("age");
			age	=	Integer.parseInt(buf);
		}
		catch(Exception e)
		{
			e.printStackTrace();
			return	-1;
		}		

		//	性別
		String	seibetsu	=	(String)map.get("seibetsu");
		if ( seibetsu	==	null )
		{
			return	-1;
		}

		//	既婚者・未婚者
		String	kikon	=	(String)map.get("kikon");
		if ( kikon	==	null )
		{
			return	-1;
		}
		
		//======================//
		//	条件判定	      //
		//======================//
		//	条件文をここに設定
		String	zyoken = "";

		//	30歳未満
		if ( age	<	30 )
		{
			zyoken = zyoken+"Y";
		}
		else
		{
			zyoken = zyoken+"N";
		}
		
		//	男性
		if(seibetsu.equals("男性") == true )	
		{
			zyoken = zyoken+"Y";
		}
		else
		{
			zyoken = zyoken+"N";
		}

		//	既婚者
		if(kikon.equals("既婚者") == true )
		{
			zyoken = zyoken+"Y";
		}
		else
		{
			zyoken = zyoken+"N";
		}
		logout(zyoken);

		//======================//
		//	実行条件の選択 //
		//======================//
		String todo = "----";
		for(int i = 0 ; i < zyoken_list.length ; i ++ )
		{
			if ( zyoken_list[i].equals(zyoken)==	true )
			{
				todo	=	todo_list[i];
			}	
		}
		logout(todo);
		
		//======================//
		//	実行 	      //
		//======================//
		KetteiModel ketteiModel = new KetteiModel();

		//	1段目の実行条件
		if ( todo.charAt(0)	==	'X' )
		{
			ketteiModel.zikko_1();
		}

		//	2段目の実行条件
		if ( todo.charAt(1)	==	'X' )
		{
			ketteiModel.zikko_2();
		}

		//	3段目の実行条件
		if ( todo.charAt(2)	==	'X' )
		{
			ketteiModel.zikko_3();
		}

		//	4段目の実行条件
		if ( todo.charAt(3)	==	'X' )
		{
			ketteiModel.zikko_4();
		}

		return	0;
	}

	/*
	 * 	ログ出力
	 */	
	 public void logout(String msg)
	 {
//		System.out.println(msg);
	 }

}

(上記 ¥ < > は、本当は半角です)


●実行部分   :KetteiModel.java
/**
 * 
 * 決定表の実行部分
 * 
 */
public class KetteiModel {

	/*
	 * 	1番目の実行処理
	 */	
	 public void zikko_1()
	 {
		System.out.println("帳票1");
	 }

	/*
	 * 	2番目の実行処理
	 */	
	 public void zikko_2()
	 {
		System.out.println("帳票2");
	 }
	 
	/*
	 * 	3番目の実行処理
	 */	
	 public void zikko_3()
	 {
		System.out.println("帳票3");
	 }

	/*
	 * 	4番目の実行処理
	 */	
	 public void zikko_4()
	 {
		System.out.println("帳票4");
	 }
}

(上記 ¥ < > は、本当は半角です)

この書き方、この程度のプログラムに対しては、いささか、大げさすぎますが、
実際の決定表はもっと複雑なので、そんなに大げさでなくなり、
条件が複雑になればなるほど、むしろこの書き方のほうが、シンプルになってきます。




で、この書き方のポイントは、決定表の変数、

 zyoken_listに決定表の右上の部分を「そのまま」
    (ただし、90度回転してみてね)
 todo_listに決定表の右下の部分を「そのまま」
    (ただし、90度回転してみてね)

です。

このように、仕様書をそのまま書くことにより、机上デバックしやすくなることはもちろん、Excelの決定表からの自動生成をやりやすくします。

っていうことで、ここからさきの詳しい説明は、次回ということになります。


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

「ITかかし」を「踏み切りのない線路」に置いたら、人命が助かるのでは。。

2007-05-11 01:59:59 | Weblog

前田(みんみん)アナのトレンドたまごで、
ITかかし
http://www.tv-tokyo.co.jp/wbs/toretama/070509.html

というのをやっていました。
それは(以下斜体は上記サイトより引用)

無人駅では列車がいつ来るかの情報が不足しているが、大がかりなシステム構築を行う余裕もない。このシステムでは列車に汎用のGPS対応携帯電話を搭載することで位置情報を集約している。5月24日まで実証実験。


つまり、
1.電車にGPSつきケータイを乗せる
2.サーバーで、その位置を集約し
3.ネットで、無人駅にある、このITかかしに、位置を知らせて、
  あと何分で来るよ!とか、しゃべらせる
というものらしい。。

おお、これ、無人駅じゃなくって、「踏み切りのない線路」(第4種っていうの、遮断機も警報機もない線路)に取り付けたら。。。というか、もっと簡単に、

1.電車にGPSつきケータイを乗せる
2.サーバーで、その位置を集約し
3.「踏み切りのない線路」には、あらかじめ、拡声器とケータイ電話をおいておいて、
  そこにあと1分くらいで電車がくる!とわかったら、サーバーから、そのケータイに
  電話をかける。

4.「踏み切りのない線路」では、ケータイの着信音を警報機の音にして
  拡声器でいってもいいし、
  電話に自動的に出るようにして、電話口から警報音をならしてもいい
  (まあ、すなおに「ITかかし」をおいておいたほうがいいかも
   間違いとか、変な電話がかかってくる危険もあるから。。 ^^;)

おお、そーやって、音がなれば、
電車にはねられ男性死亡 米原の近江鉄道
http://headlines.yahoo.co.jp/hl?a=20070507-00000005-kyt-l25

のような、「踏み切りのない線路」での事故が減り、人命が助かるのではないかなあ。。

そしたら、すごいすごい!!みんみんアナ、松丸アナのつぎにすごいです (^^;)

もし、「踏み切りのない線路」で、上記みたいなケータイとか、ITかかしが使えたら、これは再度、トレンドたまごに連絡して、トレたまチェイスで取り上げてもらわないと(^^;)

。。。そのときも、みんみんアナ?




  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする