struct Employee { int SerialNumber; // 従業員番号 char* OfficeRoomNumber; // 会社での部屋番号 char* Name; // 氏名 char* Address; // 住所 int Age; // 年齢 }会社では一人にひとつの部屋を割り当てるとした場合、SerialNumberとOfficeRoomNumberの両方が従業員に対して一意の情報となれます。ここで従業員を登録するために
void SetEmployee(Employee* anEmployee);を定義。関数を呼ばれたときには引数の内容をデータベースに記録するというもの。ここまでは良かった。次にデータベースから削除するために、この関数に引数を追加、
void SetEmployee(Employee* anEmployee, int add);「add==0ならanEmployee->OfficeRoomNumberと合致するものを削除」と仕様書に明記されました。私なら新関数RemoveEmployeeとか定義しそうですが、まぁ決めた人の都合です。
まだここまではOK。ところが後になって、引数anEmployee->SerialNumberだけ正しい情報を入れてadd=0で関数を呼ぶ例が出てきました。どっちも一意な情報なのでデータの削除にはこれだけあれば十分と思ったのでしょうが、呼ばれる方はそういう意図は知りません。当然誤動作します。
余計な情報まで含む構造体を引数として使うと定義が曖昧になり、本来必要な情報を入れずに関数が呼ばれる可能性があります。一人でプログラムを組む場合は事情が理解できているので問題とすら思わないかもしれませんが、チームでプログラムを作るときは面倒でも引数は必要十分にしたほうが良さそうです。
結局関数にさらに引数を追加、void SetEmployee(int SerialNumber, Employee* anEmployee, int add);SerialNumberが必要な情報だよと関数の定義レベルで明示するように私のほうで変更。案の定「構造体に入ってる情報をなぜ引数にも入れているのか」と質問が来ました。
ちなみに「関数を定義した人」=「仕様書を書いた人」=「SerialNumberだけ正しい情報を入れた人」=「質問してきた人」だったりします。まったく…
以上、今日のお仕事でした。
[2010/6/15 追記] 結局SetEmployee(Employee* newEmployee), RemoveEmployee(int SerialNumber)の2関数体制に変更
Comments