COBOLでアカデミー賞受賞映画一覧を出力するプログラムを作ってみた

## 動機
COBOLの仕事に就きたく、理解を深めるために今回のプログラムを作成しました。
自分にとって興味がある分野として「映画」を採用しています。

ここでは学びや苦労したことをまとめています。
~~単純なプログラムなので「開発」という単語を使うのに抵抗があります。~~

## 自己紹介
元Webディレクター。開発未経験です。
Java Silverだけ持っています。

## プログラム概要
アカデミー賞受賞映画一覧を出力するプログラム。
取得したい年代をコンソールに入力し、合致するレコードをtxtファイルに出力します。
最後に入力件数と出力件数をコンソールに出力します。

出力ファイルはこんな感じです。
![スクリーンショット 2024-05-16 054757.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3514795/74ef5961-191b-59ff-1fcd-6a7374a97d8a.png)

完成したプログラムや設計書は以下からダウンロードできます。
https://23.gigafile.nu/0824-b99341fa2b50b8fea0c6a26dc07125bf9
※ダウンロード期間が過ぎていたらお声がけください。

### 開発環境
OS:Windows11
コンパイラ:OpenCOBOL 1.0.0
エディター:Visual Studio Code

Webアプリ開発を勉強するために導入していたCopilotも使用しました。主に予約語やコードの動きを説明してもらっていました。エラーへの対処にはあまり役立たなかった印象です。

### 開発期間
体感で３～４人日です(設計や資料作成を含む)。

ESQLに挑戦したり、開発環境を整えたりを加えると５人日程度でしょうか。

## 苦労したこと

### 苦労① 入力ファイルの設計
ある年代の受賞項目ごとにレコードを用意することも考えたのですが、それでは一つの作品が複数受賞していた場合、同じ作品名が並んで冗長になってしまいます。

それを避けるために作品を主キーとすることに決めました。

よって、一つの作品が複数受賞している場合の処理を考慮しなければなりませんでした。

COBOLには、TRUE or FALSEのような概念がないので、代替策として各レコードに各賞の領域を確保し、それが正か負かで受賞しているかを判定することに。

結果、似たような処理が23個も並ぶ冗長なコードになってしまいました

<details open><summary>※これです。</summary>

```rb
      *年代判定
           IF WK-INPUT-YEAR = WK-YEAR

      *受賞項目判定～印刷
               IF IN-AW-ALR = 1
                   MOVE "主演男優賞"  TO WR-AWARD
                   PERFORM WRITE-SYORI
               END-IF

               IF IN-AW-ASM = 1
                    MOVE "助演男優賞"  TO WR-AWARD
                    PERFORM WRITE-SYORI
               END-IF

               IF IN-AW-ALW = 1
                    MOVE "主演女優賞"  TO WR-AWARD
                    PERFORM WRITE-SYORI
               END-IF

               IF IN-AW-ASW = 1
                    MOVE "助演女優賞"  TO WR-AWARD
                    PERFORM WRITE-SYORI
               END-IF

               IF IN-AW-ANIME = 1
                    MOVE "長編アニメ賞"  TO WR-AWARD
                    PERFORM WRITE-SYORI
               END-IF

               IF IN-AW-CG = 1
                    MOVE "撮影賞"  TO WR-AWARD
                    PERFORM WRITE-SYORI
               END-IF

               IF IN-AW-COS = 1
                    MOVE "衣装デザイン賞"  TO WR-AWARD
                    PERFORM WRITE-SYORI
               END-IF

               IF IN-AW-DIR = 1
                    MOVE "監督賞"  TO WR-AWARD
                    PERFORM WRITE-SYORI
               END-IF

               IF IN-AW-DOC = 1
                    MOVE "長編ドキュメンタリー賞"  TO WR-AWARD
                    PERFORM WRITE-SYORI
               END-IF

               IF IN-AW-DOCS = 1
                    MOVE "短編ドキュメンタリー賞"  TO WR-AWARD
                    PERFORM WRITE-SYORI
               END-IF

               IF IN-AW-EDIT = 1
                    MOVE "編集賞"  TO WR-AWARD
                    PERFORM WRITE-SYORI
               END-IF

               IF IN-AW-ITNR = 1
                    MOVE "国際長編映画賞"  TO WR-AWARD
                    PERFORM WRITE-SYORI
               END-IF

               IF IN-AW-MAH = 1
                    MOVE "メイクアップ＆ヘアスタイリング賞"  TO WR-AWARD
                    PERFORM WRITE-SYORI
               END-IF

               IF IN-AW-SCORE = 1
                    MOVE "作曲賞"  TO WR-AWARD
                    PERFORM WRITE-SYORI
               END-IF

               IF IN-AW-SONG = 1
                    MOVE "歌曲賞"  TO WR-AWARD
                    PERFORM WRITE-SYORI
               END-IF

               IF IN-AW-BEST = 1
                    MOVE "作品賞"  TO WR-AWARD
                    PERFORM WRITE-SYORI
               END-IF

               IF IN-AW-DESIGN = 1
                    MOVE "美術賞"  TO WR-AWARD
                    PERFORM WRITE-SYORI
               END-IF

               IF IN-AW-ANIMES = 1
                    MOVE "短編アニメ賞"  TO WR-AWARD
                    PERFORM WRITE-SYORI
               END-IF

               IF IN-AW-SHORT = 1
                    MOVE "短編映画賞"  TO WR-AWARD
                    PERFORM WRITE-SYORI
               END-IF

               IF IN-AW-SOUND = 1
                    MOVE "音響賞"  TO WR-AWARD
                    PERFORM WRITE-SYORI
               END-IF

               IF IN-AW-VFX = 1
                    MOVE "視覚効果賞"  TO WR-AWARD
                    PERFORM WRITE-SYORI
               END-IF

               IF IN-AW-WA = 1
                    MOVE "脚色賞"  TO WR-AWARD
                    PERFORM WRITE-SYORI
               END-IF

               IF IN-AW-WO = 1
                    MOVE "脚本賞"  TO WR-AWARD
                    PERFORM WRITE-SYORI
               END-IF
               
           END-IF.
```
</details>

もっとスマートなやり方があったのではと思います。
受賞項目を配列にして、for文で回していく～みたいな…。

（というかそもそも、受賞項目が追加されたり減ったりしたときには入力レイアウトごと編集しなきゃならないのが欠点のような気もします）


### 苦労② IF文で謎エラー
上記にあるIF文でエラーが発生しました。

構文エラーのようですが、"END-IF"もちゃんと記入してるし、IF文の中でピリオドを使っていることもありません。

調べながら検証し、ここで１～２時間ほどのロス。

結果、「IF文に必ずしも記入する必要はない」という"THEN"を「最初のIF文にだけ」使うことで解決したのですが、原因は不明です。

追記：THENを外しても正常に動きました。謎です。

### 苦労③ 入力ファイルを読み込めない
入力ファイルの読み込み時、プログラムがinfile.txtを認識できませんでした。

これはフォルダ名に日本語が含まれていたことが原因でした。単純ですが、そこそこ時間を奪われました。

### 挫折

設計前の段階では、ESQLを用いてDB接続し、そこから情報を出力する形を想定していました。

しかし、思うように連携できませんでした。目的はプログラムを作ることでありDB接続ではない…と自分に言い聞かせ、泣く泣く断念。

入力ファイル(txt)を読み込む方針に決めました。

## 学んだこと

### 学び① データ項目の管理が大事すぎる
データ項目の管理を厳格化しないと開発に混乱が生じ、工数が大幅に増えることが容易に想像できました…。

これは別にCOBOLにかぎらないと思うのですが、COBOLは他の言語と違って変数を随時追加できないことがややこしさにつながっているのだと思います。

考えられる対策としては、最初に必要なデータ項目を洗い出すこと。用途に応じているわかりやすい命名規則を設けること。~~それができれば苦労しないような…。~~

開発途中で項目を追加した場合は、リストへ随時追加すること。項目一覧そのものをバージョン管理したり、あとから追加された項目が一目でわかるように色付けするなど、工夫の必要性を感じました。

### 学び② フローチャートこそ絶対
「COBOLはフローチャートさえしっかりしていれば書ける」と教わりまして、実際にプログラムを作成して、この言葉が腑に落ちました。

まずは大枠でフローチャートを書き、それを詳細化していくこと。何度も反芻して、必要な処理が抜けていないか確認すること(こういうところに経験が大きく貢献しそうです)。

また、他の誰にでも理解しやすい設計を心掛けること。未来の自分さえ理解できないなんて事態は避けたいところです。

### 学び③ COBOLの書き方
MOVEやIF文など、決して難しいことではありませんでしたが、実際に手を動かしたことで"身についた"という実感があります。

ただ、実務ではコンパイラごとに制約もあるでしょうし、学んだことを過信しない必要がありそうです。



## まとめ
最後までお読みいただき、ありがとうございます。

しかし、自分で考えたものを形にするというのは楽しいものですね。
作業時間を捻出するために睡眠時間を２時間削りましたが、まったく苦にはなりませんでした。

単純なプログラムではありますが、完成させられたことが自信になりました。あわよくば転職のフックになることを願うばかりです。

## 謝辞
田中準志先生によるSchooの講義(https://schoo.jp/course/4943) には大変お世話になりました。

「COBOLとはなんぞや？」という部分から、処理の流れを考えていて頭がごちゃついたときに講義を見て捗ることが多々ありました。ありがとうございます。