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

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

仕様決めがしやすく、テストファーストにしやすいメソッド、関数の引数の決め方

2005-11-27 09:20:24 | 開発ネタ

 伝票指向アプリケーション・アーキテクチャというのがあるそうですね。
 日経システム構築2005年12月号P129によると。。
 そこでは、各コンポーネント間でのデータ流通を、伝票という概念に統一させているそうです。

 この考えが、はやるかどうかはさておき、たしかに、(JAVAなどでは)メソッド間(Cだと関数間)で、受け渡す変数と、返り値を統一すると、仕様決めがしやすく、すぐにテストでき(スタブも、テストドライバもすぐに作れる)、構成管理における、リンクできない問題(引数が違ってリンクできない問題)も解決されます。




 具体的にいうと、
 Javaの場合、メソッドの引数をハッシュマップ、返り値もハッシュマップにします。
 perlやPHPの場合、連想配列にします
 C++やCでは、
 typedef struct
 {
    char **key;
    void **val;
 } VO;
 というかんじの構造体(C++の場合は、クラス)をつくり、そのVOとします。

 そうすると、結局、メソッドはすべて
HashMap VOret = methodXX(HashMap VO);
 (methodXXは、どんなもんでもOK(任意のメソッド))
 のカタチになってしまいます。

 で、実際に受け渡したい引数の内容は、そのハッシュマップVOにセットします。
 そして、処理内容は、受け取ったVOにセットし、返します。
 (受け取ったVOに、そのままセットし、返します。そのため、このメソッドに関係ない値がVOに入っていて、受け取った場合、その値を削除することが、仕様になければ、そのまま返します)。




 例を示します。
 今、本来だと、月日をセットし、今年の曜日を数値で返すメソッド、dateToYobiというメソッドがあったとします。そうすると、こんな感じになります。

int yobi = dateToYobi(int tuki,int hi);

 でも、この形式だと、こんな感じになります
 HashMap VO;
// 月(tuki)日(hi)の設定
VO.put("tuki",new Integer(tuki));
 VO.put("hi",new Integer("hi"));

// メソッドは、こんなかんじ
 VO = dateToYobi(VO);

// 結果はVOに入ってる
Integer result = (Integer)VO.get("result");
Integer yobi = (Integger)VO.get("yobi");

 これだけなら、呼び出しが、めんどくさくなっただけです。

 ところが、dateToYobiの仕様が変更になり、年の指定も必要になった場合(そして求める結果は、その指定した年月日の曜日を求める)
 上記の方法だと、
 int yobi = dateToYobi(int nen,int tuki,int yobi);
 に変えないといけません。これを変えるには、引数が変わっているため、すべて、このメソッドを使っているところを変えなければいけません。

 さらに、構成管理の立場から見れば、この関数を、今すぐ変えてしまうと、連絡がまだ行っていない担当者のところは、昔の関数のままなので、新旧の違った引数をもったメソッドが混在し、おかしな動きになったりします。

 ところが、上記のHashMapにいれる方法であれば、
 HashMap VO;
// 月(tuki)日(hi)の設定
 VO.put("version","1.1");
 VO.put("nen",new Integer("nen"));
VO.put("tuki",new Integer(tuki));
 VO.put("hi",new Integer("hi"));

// メソッドは、こんなかんじ
 VO = dateToYobi(VO);

とすればいいだけなので、引数、返り値ともに、VOでかわらず、構成管理上も、新旧のメソッドが混在しても問題ありません。とくにversionがはいっているので、1.1なら、最新のものとして処理し、入ってない場合(本来は1.0とか入れておいたほうがいいけど)だったら、前のバージョンのものとして処理すれば(そのときちゃんと処理するか、エラー表示するかは、実装者がどうしたいかによる))OKです。問題ありません。




 この場合、引数が変更になっても対応できるので、とりあえず、メソッド名だけをきめておいて、コーディングしておいてもらい、後から、詳細に引数と返り値を決めることもできます。変更も容易です。

 さらに、引数の形式が決まっているので、すぐに、テストドライバが作れます。
 モジュール名がabcなら、そのテストドライバの呼び方は
HashMap VO = new HashMap();
// ここに、引数がはいるが、あとからきめればよい。
VO = abc(VO);
 なのに、きまっています。

 スタブもとりあえず作る場合は
 public HashMap abc(HashMap VO)
 {
    return VO;
 }
 と、すぐ作れます。引数については、あとから決まったときに追加すればいいです。

 そして、テスト結果表示も、呼び出し前のVOの値と、呼出し後のVOの値を表示するだけでOKです。




 上記の説明では、引数の個数が変わったケースですが、型が変わったケースでもOKです。
 たとえば、上記の場合、年月日を String YYYYMMDD;のカタチであらわすことになった場合、
int yobi = dateToYobi(String YYYYMMDD);
 だと、新旧の物が混じると、リンクできなくなるかもしれませんが、HashMap VOを使うケースだと

HashMap VO = new HashMap();
VO.put("version","1.2");
VO.put("ymd",YYYYMMDD);
VO = dateToYobi(VO);

 となるだけなので、まったく問題ありません。




 上記の説明は、Javaでしたけど、perlやPHPなら、HashMapの代わりに連想配列を使っていただければ、同じことができます。Cの場合は、上記にあげた構造体で、keyの文字列の配列と、値(val)のvoid*の配列に、値をセットしていれることになります(put,get,freeの関数は作っておくべきでしょうけど)

 で、これらのことは、特別な技術を導入する必要もなく、ただ、コーディング規約を、このように決めてしまえばいいだけです。

 現状では、アーキによっては、こういう仕様がくるのですが、
 (ただし、本人が、このようなことを理解してやっているかどうかは疑問)

 普通は、こういう仕様にならず、
 int yobi = dateToYobi(int nen,int tuki,int hi);
 のような仕様になるので、とーぜんのことながら、構成管理に失敗し(新旧のモジュールが混じってしまったり、前のに戻せ!(新しいのが間に合わないため)とかで、現場混乱、テストモジュールもすぐに作れず。。。とかで、えらい開発が大変になったりします。

 大きなシステムになればなるほど、仕様は決まらないので、この差は大きいですね。

 つまり、アーキの読み、ないしは、ウィリアムのいたずらのブログを見ているかどうかで、多くの人が残業になるかどうかがきまるということです(うん、前者はそのとおりだが、後者はそうなのか??)



 なお、HashMapでなく、これをXMLのDomでやってもOKではあるのですが、Domの場合話が複雑になる(入れ子が容易にできるため、複雑な引数にされてしまう)ことがあるので、HashMapのほうが、仕様を切りやすかったりします。

 とはいえ、どっちでもいいんですけどね。。。



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