プリント基板設計・シミュレーション

TOP > アポロレポート > コラム > 第19回 プログラミングについて 『いったい誰がやるんだ』
コラム
2022/10/14

第19回 プログラミングについて 『いったい誰がやるんだ』

アポロレポート

『いったい誰がやるんだ』

 

  馬鹿な上司が馬鹿な部下達に仕事をさせました。親切にも上司はそのときに部下が仕事をしてもいいものかどうかを調べてからこまごまと命令をしました。部下はなんの疑いもなく真面目に仕事をし、気をきかせた部下達は上司のするべき仕事までもこなしてくれました。けれども上司ばかりが忙しい上に部下が色々とやってくれるものですから、やがて上司はどの部下が一体どこまでやってくれているのかが分らなくなってしまい馬鹿な部署はてんてこまいになってしまいました。

 プログラムを作っていると、知らないうちに馬鹿な上司と馬鹿な部下達が居並んだ『製造部大馬鹿第一課』ができてしまうことがよくあります。中小企業ならば彼等は仲良く仕事をしてくれるのですが、大企業となると『製造部大馬鹿第一課』が『馬鹿一係』や『馬鹿二係』を誕生させ、あげくの果てには『大馬鹿製造部』にしてしまい、最後には『大馬鹿株式会社』にしてしまうのです。
 私も何気なく作ったプログラムがだんだんと変なものになって、最後に収拾のつかないものになった経験が数え切れないほどあります。こうなってはプログラムに小さな改修を加えると、とんでもないところで予想外の動作をすることがあり、またこれを押え込むために変な改修を加えるので、動作はするけれど中身はグチャグチャなプログラムになってしまうのです。

 何度も苦い経験をしているうちにだんだんと分ってきたことは、上司と部下達の作業分担をしっかりさせる事なのです。

 利口な上司が利口な部下達に仕事をさせました。上司は仕事を部下に命令するときあまりこまごまと言いません。部下達は与えられた命令を自分で判断して仕事をしますが、決して他人の仕事までも勝手にしませんでした。部下達も上司のすべきことは上司に頼み、同僚のすべきことは同僚に頼みましたので、その部署はいつまでも整然と円滑に仕事をすすめることができました。

 これが自分の理想なのですが、なかなか難しいものです。

さて、実際のプログラムを例に考えてみましょう。よくあることですが開いたファイルを誰が閉じるのかという問題があります。

 main()
 {
  :
  :

  fp=open("data.dat","r");

  :
  :

  sub1(fp);

  :
  :
 }

 sub1(fp)
 {
  :
  :

  sub2(fp);

  :
  :
 }

 sub2(fp)
 {
  :
  :

  fclose(fp);

  :
  :
 }

としてしまうことはよくあるものです。プログラムは確かにちゃんと動作しますが、保守の面では歓迎できるものではありません。こういうプログラムは改修のたびに必ず誰がファイルを閉じているのかを調べるはめになってしまうのです。
 FORTRANなどではファイルポインタなどといった概念などがなく、ユニット番号の指定のみでファイルとの入出力ができますから事情は深刻です。VAX/VMSでは、

   WRITE(1,100)
100 FORMAT(1H,'ABCDE')

   STOP
   END

と書くとFOR001.DATというファイルが簡単にできあがるのです。OPEN文を使ってユニット番号と実際のファイル名とを結合しますが、問題は1番のユニットを使っている事を知らずに他のルーチンが1番のユニットを使って他の別のファイルをオープンしてしまうことです。こうなってしまっては誰がどこでファイルを開いて、誰が閉じているのかが分らないと、修正が非常に困難になってしまいます。ユニット番号の衝突を避けるためには、ユニット番号を管理してくれるルーチンを別に作って各ルーチンがファイルをオープンしたり閉じたりするときに管理ルーチンと情報の交換をするようにすれば解決ができますが...。

 さて話を戻しましょう。ファイルのオープン/クローズについては、開いた人が閉じるというのが筋です。トイレのドアと同じです。自分がドアを開けてトイレに入ったのに、他人に閉めさせるなどということはありませんね。

 次にこれも頭を痛めることですが、誰がエラーメッセージを表示するのかという問題。この問題は場面によって違ってきますが、私の場合エラーを検出した人が表示することを基本としています。いま、エディタで作ったテキストファイルを検査するプログラムを作ったとします。

 main()
 {
  :
  :

  fp=fopen(...);          /* ファイルをオープンする */

  :
  :

  while(1){
   int kind;

   fgets(data, ... ,fp);     /* ファイルから1行読む */
   if(feof(fp))break;

   kind=get_data_kind(data);   /* データの種類を調べる */

   switch(kind){
    case KIND_TITLE :
        sts=check_title(data);
          if(sts==1)printf("--- タイトル名が長すぎます ---\n");
        else if(sts==2)printf("--- タイトル名が重複しています ---\n");
        else if(sts==3)printf("--- サブタイトル名が長すぎます ---\n");
        else if(sts==4)printf("--- サブタイトルがありません ---\n");

        break;
    case KIND_COMMENT :
        sts=check_comment(data);

          if(sts==1)printf("--- コメントがありません ---\n");
        else if(sts==2)printf("--- コメントの書式が誤りです ---\n");
        else if(sts==3)printf("--- コメントが長すぎます ---\n");

        break;
    case
     :
     :

    default :
        printf("--- 種類の不明なデータがあります ---\n");
        sts=1;
        break;
   }

   if(sts)break;
  }

  fclose(fp);            /* ファイルをクローズする */

  :
  :
 }

というように記述すると、馬鹿な上司と馬鹿な部下達になってしまうのです。呼び出した上司が部下の作業にこまごまと指示しすぎているのです。確かに呼び出すときには data しか渡してはいませんが上司は部下に対して、こういう問題があったらこういうふうに教えてくれとこまごまとしたことを暗黙に取り決めしているのです。こういう部署では部下が新たな問題を発見したときには上司との間で新たに取り決めを行なわなければならないのです。

 利口な上司ならばデータの種類(仕事の種類)によって部下を選び、部下に対しては問題があったことだけを教えてくれればいいと命令するのです。利口な部下は仕事を処理し、問題があったときには自分で処理をし、上司に対しては問題があったか否かを報告します。

 main()
 {
  :
  :

  fp=fopen(...);          /* ファイルをオープンする */

  :
  :

  while(1){
   int kind;

   fgets(data, ... ,fp);     /* ファイルから1行読む */
   if(feof(fp))break;

   kind=get_data_kind(data);   /* データの種類を調べる */

   switch(kind){
    case KIND_TITLE :
        sts=check_title(data);
        break;
    case KIND_COMMENT :
        sts=check_comment(data);
        break;
    case
     :
     :

    default :
        printf("--- 種類の不明なデータがあります ---\n");
        sts=1;
        break;
   }

   if(sts)break;
  }

  fclose(fp);            /* ファイルをクローズする */

  :
  :
 }

 check_title(data)
 char *data;
 {

  if(...){
   printf("--- タイトル名が長すぎます ---\n");
   return 1;
  }

  if(...){
   printf("--- タイトル名が重複しています ---\n");
   return 1;
  }

  if(...){
   printf("--- サブタイトル名が長すぎます ---\n");
   return 1;
  }

  if(...){
   printf("--- サブタイトルがありません ---\n");
   return 1;
  }

  return 0;
 }

 check_comment(data)
 char *data;
 {

  if(...){
   printf("--- コメントがありません ---\n");
   return 1;
  }

  if(...){
   printf("--- コメントの書式が誤りです ---\n");
   return 1;
  }

  if(...){
   printf("--- コメントが長すぎます ---\n");
   return 1;
  }

  return 0;
 }

 部下は忙しいかも知れませんが上司との取り決めが殆どないので、部下自身で自由に問題を処理することができます。上司もこの仕事はあいつがやるということを知っていればいいのですから楽です。問題があったという報告を受けたときにだけ対処するのですが、こまごまとしたことは部下がやっているので上司としての仕事をするだけでいいのです。

 おおきなプログラムになればなるほど作業の分担は大切になってきます。馬鹿な上司と部下達でプログラムを組み立てるのは非常な苦痛であり、最悪の場合プログラムが完成できなくなってしまうことすらあります。今回紹介した例は氷山のほんの一角であり、実際のプログラムではたった1行のことを誰にさせるのかで1日も頭を悩ますこともあります。本来ならば、こういうときにはこうすると明確にお話できれはいいのですが、以前からお話しているようにより多くのプログラムを作って体得していくしか方法がないように思います(無責任ですが....)。ただ大切なことは、『いったい誰がやるんだ』ということを忘れないことです。

 それではまた次回。


そのお悩み、
アポロ技研に話してみませんか?

アポロ技研でワンランク上の物創りへ!
そのお悩み、アポロ技研に話してみませんか?