【ChatGPT縛りプレイ】システム開発をさせてみた

# はじめに
RAGだとかReActだとかon your dataだとかfunction callingだとかが流行っていますが、ChatGPTの基本スキルだけでシステム開発（**要件分析や設計～実装やテストまで**）をどこまでできるか試してみました。こういう使い方できるんだとか、じゃあこういうのができるのでは？とかの提起にもなれば幸いです。

利用したモデルは、chagtp-35-turboです。

ちなみに最終的にこういうWebアプリがUIテスト、単体テストとともにできました。（私はコードを1ミリも書いてません）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/977156/2c051433-cbbe-771f-61de-6a8427e40bf8.png)

ちなみに、先日書いた[横スクロールChatGPT](https://qiita.com/shyamagu/items/f53e63b8ec4801cb10d4)で実施しました。練り上げ系は、横、いいですよ。

# 縛りプレイのルール
- 顧客要望と、ChatGPTへの指示のみが入力できる
- ChatGPTの回答は再利用可能。抜粋して利用も可能とする。
- 自前の知識を使った場合は赤で明記する

# 0. 顧客の要望

**"ウェイターがさ、お客さんの注文を耳で聞いて紙で書いてるのをやめたいのよね。たまに間違うし。あとさコックもさ、ウェイターから口頭で注文を聞いて作るのもやめたい。たまに間違うし。この辺システムでチャチャっとできないかな？
あとさお金のやりとりにレジを使うのは、まぁいいとしてさ、合計金額をいちいちレジで計算するのも無駄くない？システムで注文受けてるんだから、合計金額分かるよね？すぐに。
あとさあとさー、料理ができたらコックがウェイターを呼ぶのもやめたい。声出すのって感染リスクあるじゃん。システムでさ、調理中とか調理済みとかあと配膳済みとかそういうステータス管理できるよね？
こういうのシステム化したいんだけどさ、何からやるといいのかな？"**

# 1.要件の分析とシステム設計

## ユースケース分析
まずは顧客要望を分析していきます。ユースケース分析や業務フローを整理するために以下のプロンプトでChatGPTを呼び出します。

|プロンプト|内容|
|:--|:--|
|システム|あなたは熟練のITコンサルタントです。ユーザからの相談をもとに、注文管理Webシステムの要件定義を始めます。まずは入力された情報をもとにユースケース分析を実施します。確認事項があればユースケース分析の末尾にまとめて書き出してください。|
|ユーザー|<※上述の顧客要望>|

ChatGPTからは以下のようなユースケース分析が回答されてきます。

|ChatGPTの回答|
|:--|
|1. 注文の受け付け<br/>- ウェイターがタブレット端末を用いて、お客様からの注文を受け付ける<br/>- 注文内容は、メニューから料理名を選択できるようにする<br/>- 注文内容は、料理名、数量、価格、備考<br/><br/>2. 注文の確認<br/>- キッチンスタッフがタブレット端末を用いて、全ての注文内容を確認する<br/><br/>3. 料理の調理<br/>- キッチンスタッフがタブレット端末を用いて、注文内容に基づいて料理を調理する<br/>- 料理の調理状況は、タブレット端末で管理する<br/>- 料理状態は、注文受付、調理中、調理済み、配膳済み、会計済みの5ステータスとする<br/><br/>・・・略

また、足りないユースケースや必要な追加業務フローがないかを複数回ChatGPTにレビューさせましたが、同じような内容が続くため、ここでは割愛します。

<font color="red">**※配膳済みのステータスがうまく出てこなかったので、それだけ人間側で足しました。**</font>


## 業務フロー分析・システム設計
次にシステム設計ぽいことをやらせます。

|プロンプト|内容|
|:--|:--|
|システム|あなたは熟練のITコンサルタントです。\<usecase>タグで囲まれたユースケースについて、システム設計を実施してください。|
|ユーザー|\<usecase>※上述のユースケース\</usecase>|

|ChatGPTの回答|
|:--|
|上記のユースケースに基づいて、以下のようなシステム設計を提案します。<br/><br/>1. 注文の受け付け</br>- ウェイターがタブレット端末を用いて、注文情報を入力する画面を提供する<br/>- 注文情報は、料理名、数量、価格、備考を入力できるようにする<br/>- 注文情報は、注文テーブルに保存する<br/><br/>2. 注文の確認<br/>- キッチンスタッフがタブレット端末を用いて、注文テーブルから注文情報を取得する<br/>- 注文情報は、注文受付、調理中、調理済み、配膳済み、会計済みのステータスを持つ<br/>- 注文情報のステータスが変更された場合は、注文テーブルを更新する<br/><br/>…略|

いい感じですね。雑に作った顧客の要望から、とりあえず業務フローが整理できました。

## ユースケース図作成

次にUMLで図を作ります。まずはユースケース図を作成します。

|プロンプト|内容|
|:--|:--|
|システム|入力されたユースケースを分析し、PlantUMLのユースケース図を作成してください。|
|ユーザー|※上述のユースケース|

|ChatGPTの回答|
|:--|
```
@startuml
left to right direction
skinparam packageStyle rectangle

actor Waiter
actor KitchenStaff
actor Customer

rectangle "レストランシステム" {
    rectangle "注文管理" {
        usecase "注文の受け付け" as UC1
        usecase "注文の確認" as UC2
        usecase "キャンセル" as UC3
    }
（略）
```
ちょっと微妙な感じのユースケース図ですが、細かい指示を出していないので、まぁこんなものかなと。もっとブラッシュしたければこういう記載方法にしてとか指示を追加すればよくなります。（が、割愛）

```plantuml
@startuml
left to right direction
skinparam packageStyle rectangle

actor Waiter
actor KitchenStaff
actor Customer

rectangle "レストランシステム" {
    rectangle "注文管理" {
        usecase "注文の受け付け" as UC1
        usecase "注文の確認" as UC2
        usecase "キャンセル" as UC3
    }
    rectangle "調理管理" {
        usecase "料理の調理" as UC4
        usecase "注文の配膳" as UC5
    }
    rectangle "会計管理" {
        usecase "会計" as UC6
    }

    Waiter --> UC1
    UC1 --> UC2
    UC2 --> UC3
    UC3 --> UC2
    UC2 --> UC4
    UC4 --> UC5
    UC5 --> UC2
    UC2 --> UC6
    UC6 --> Customer
}
@enduml
```

## シーケンス図作成
次に同じくUMLでシーケンス図を作成します。

|プロンプト|内容|
|:--|:--|
|システム|入力されたユースケースを分析し、PlantUMLのシーケンス図を作成してください。|
|ユーザー|※上述のユースケース|

|ChatGPTの回答|
|:--|
```
@startuml
title レストラン注文システム

actor ウェイター
actor キッチンスタッフ

database 注文テーブル

== 注文の受け付け ==
activate ウェイター
ウェイター -> 注文テーブル: 注文情報を保存
deactivate ウェイター
（略）
```

パット見良さそうなのですが、if then 記載方法になっていたので、このままではPlantUMLのシーケンス図としては表示できません。ので、シーケンス図を修正させます。
|プロンプト|内容|
|:--|:--|
|システム|入力されたシーケンス図のif then else endif 表記から、alt else end表記に変えてください。<br/><br/># 修正例<br/>## 修正前<br/>if (調理済み) then<br/>  ウェイター -> 注文テーブル: 配膳する<br/>  note right: 注文情報のステータスを配膳済みに変更<br/>else<br/>  ウェイター ->x 注文テーブル: 配膳不可<br/>endif<br/><br/>## 修正後<br/>alt 調理済み<br/>  ウェイター -> 注文テーブル: 配膳する<br/>  note right: 注文情報のステータスを配膳済みに変更<br/>else<br/>  ウェイター ->x 注文テーブル: 配膳不可<br/>end|
|ユーザー|※上述のシーケンス図|

こうするとことで正しい(ちゃんと表示できる)シーケンス図（下図）が作成されました。
|ChatGPTの回答|
|:--|
```plantuml
@startuml
title レストラン注文システム

actor ウェイター
actor キッチンスタッフ

database 注文テーブル

== 注文の受け付け ==
activate ウェイター
ウェイター -> 注文テーブル: 注文情報を保存
deactivate ウェイター

== 注文の確認 ==
activate キッチンスタッフ
キッチンスタッフ -> 注文テーブル: 注文情報を取得
note right: 注文情報のステータスを確認
キッチンスタッフ -> 注文テーブル: 注文情報のステータスを更新
deactivate キッチンスタッフ

== キャンセル ==
activate ウェイター
ウェイター -> 注文テーブル: キャンセルすべき注文情報を取得
note right: 注文情報のステータスを確認
alt 注文受付または調理中
  ウェイター -> 注文テーブル: 注文をキャンセル
  note right: 注文情報のステータスをキャンセル済みに変更
else
  ウェイター ->x 注文テーブル: キャンセル不可
end
deactivate ウェイター

== 料理の調理 ==
activate キッチンスタッフ
キッチンスタッフ -> 注文テーブル: 調理すべき注文情報を取得
note right: 注文情報のステータスを調理中に変更
キッチンスタッフ -> 注文テーブル: 注文情報のステータスを更新
deactivate キッチンスタッフ

== 注文の配膳 ==
activate ウェイター
ウェイター -> 注文テーブル: 配膳すべき注文情報を取得
note right: 注文情報のステータスを確認
alt 調理済み
  ウェイター -> 注文テーブル: 配膳する
  note right: 注文情報のステータスを配膳済みに変更
else
  ウェイター ->x 注文テーブル: 配膳不可
end
deactivate ウェイター

== 会計 ==
activate ウェイター
ウェイター -> 注文テーブル: 会計すべき注文情報を取得
note right: 合計金額を計算
note right: お客様が支払いを行った場合は、注文情報のステータスを会計済みに変更
deactivate ウェイター
@enduml
```
シーケンス図いい感じです。実際使えるレベルのが出てきました。（もちろん修正は必要ですが）

## データベース設計
次にユースケース情報からデータベース情報を抽出させます。

|プロンプト|内容|
|:--|:--|
|システム|\<usecase>タグで区切られたユースケース情報をもとにデータベース設計を実施してください。<br/>注文テーブルと、メニューテーブルの論理設計をお願いします。|
|ユーザー|\<usecase>※上述のユースケース\</usecase>|

|ChatGPTの回答|
|:--|

注文テーブルの論理設計:

| 列名 | データ型 | 制約 | 説明 |
| --- | --- | --- | --- |
| order_id | INT | PRIMARY KEY | 注文ID |
| menu_id | INT | NOT NULL | メニューID |
| quantity | INT | NOT NULL | 注文数 |
| price | INT | NOT NULL | 単価 |
| note | VARCHAR(255) | | 備考 |
| status | VARCHAR(20) | NOT NULL | ステータス（注文受付、調理中、調理済み、配膳済み、会計済み、キャンセル） |

メニューテーブルの論理設計:

| 列名 | データ型 | 制約 | 説明 |
| --- | --- | --- | --- |
| menu_id | INT | PRIMARY KEY | メニューID |
| menu_name | VARCHAR(50) | NOT NULL | メニュー名 |
| price | INT | NOT NULL | 単価 |
| category | VARCHAR(20) | NOT NULL | カテゴリ（飲み物、前菜、メインディッシュ、デザートなど） |
| description | VARCHAR(255) | | 説明文 |

細かく見てないですが、悪くない感じです。もし不満なところがあれば修正指示をいれればよさげです。

# 2.実装

## サーバサイドプログラムの実装

設計情報がある程度できたので、ここらで一気にプログラムを作成させていきます。

|プロンプト|内容|
|:--|:--|
|システム|\<usecase>タグで区切られたユースケースと、\<database>タグで区切られたデータベース設計をもとに、Nodejs expressで起動するサーバサイドプログラムを作成してください。なお、データベースは無いため、javascriptの連想配列をもちいて情報を格納・更新してください。|
|ユーザー|\<usecase>※上述のユースケース\<usecase>　　<br/>\<database>※上述のデータベース設計\</database>|

データベースの指定をしないと適当なDBをつかったプログラムになるので、今回はメモリ上で完結させるための文言(~連想配列)をいれています。

|ChatGPTの回答|
|:--|
|以下は、上記のユースケースとデータベース設計をもとに作成した、Nodejs expressで起動するサーバサイドプログラムの例です。データベースの代わりに、javascriptの連想配列を使用しています。<br/>\```javascript<br/>const express = require('express');<br/>const app = express();</br>const port = 3000;<br/><br/>// 注文テーブルの初期化<br/>let orders = [];<br/><br/>// メニューテーブルの初期化<br/>（略）|

それっぽいコードができてきました。が、<font color="red">**お気づきの方もいると思いますが、body-parserが入っていません。このままだとPOSTが空になってしまうので、修正させます。**</font>

|プロンプト|内容|
|:--|:--|
|システム|\<server>タグで区切られたNodejs expreeプログラムについて、POSTメソッドが正常に処理できるようbody-parserの処理を追加してください。|
|ユーザー|\<server>※上記で出力されたNodejsのプログラム\</server>|

これでbody-parserをつかったプログラムに変わります。

また、このままだとAPIサーバだけになっちゃうので、画面HTMLを返すように変更します。

|プロンプト|内容|
|:--|:--|
|システム|\<server>タグで区切られたサーバサイドのNodejs プログラムに対して、ルートアクセス時に、index.htmlを返すようにプログラムを修正してください。|
|ユーザー|\<server>※上記で出力されたNodejsのプログラム\</server>|

|ChatGPTの回答|
|:--|
```javascript
// ルートアクセス時にindex.htmlを返す
app.get('/', (req, res) => {
  res.sendFile(__dirname + '/index.html');
});
```
だんだんとできてきました。

## クライアントHTMLの実装

次に画面HTMLを生成させます。さっくり確認したいだけなので、CDN版のVueを指定して作成させます。また指示がないと適当すぎる画面になるため、一覧表示と新規登録が入っていることを伝えます。

|プロンプト|内容|
|:--|:--|
|システム|\<server>タグで区切られたサーバサイドのNodejsプログラムを呼び出すindex.htmlを作成してください。CDN版のVueを使うこととします。<br/>なお、index.htmlは初期表示として注文一覧を表示します。表示された一覧からボタンでステータスを変えることができるようにしてください。また下部より新規注文を登録できるようにしてください。|
|ユーザー|\<server>※上記で出力されたNodejsのプログラム\</server>|

|ChatGPTの回答|
|:--|
|以下が、注文一覧を表示し、ステータスを変更できるようにしたindex.htmlです。また、下部に新規注文を登録できるフォームを追加しました。<br/><br/>\```html<br/>\<!DOCTYPE html><br/>\<html lang="ja"><br/>（略）|

ここで一度動作を確認しようとしたところ、HTML側にエラーが発生していましたので、それを修正させます。

|プロンプト|内容|
|:--|:--|
|システム|入力されたHTMLにおいて、以下の警告が出ます。どのように修正すべきですか？<br/><br/>Select element must have an accessible name: Element has no title attributeMicrosoft Edge Toolsaxe/forms<br/>The select element represents a control for selecting amongst a set of options.|
|ユーザー|※エラーが出ている箇所のHTML|

これで、title属性がない部分を修正してくれます。

## 動作確認

（サーバサイドに必要なライブラリだとか起動コマンドも全部ChatGPTに出力させましたが、割愛。）
こんな画面ができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/977156/6600662d-030b-24e9-7dde-b2e7dd100db4.png)

おお、と思いつつ、あれ？メニュー一覧が取得できていないようです。どうやらクライアントからは/menusでメニュー一覧を取得しにいってるのですが、サーバサイドにAPIが無いようです。ので、追加させます。

## サーバサイドプログラムの修正


|プロンプト|内容|
|:--|:--|
|システム|\<server>タグで区切られたサーバサイドのNodejsプログラムに、/menusにアクセスした際に全メニューを返却するGETメソッドを追加してください。|
|ユーザー|\<server>※上述のNodeJsプログラム\</server>|

|ChatGPTの回答|
|:--|
以下のように、/menusにアクセスした際に全メニューを返却するGETメソッドを追加してください。

```javascript
// メニューの取得
app.get('/menus', (req, res) => {
  res.send(menus);
});
```

とのことなので、このプログラムをサーバサイドに追加します。

## プログラムのレビュー

他にも不備があると嫌なので、レビューさせます。クライアントとサーバの全コードをぶちこんでレビュー。

|プロンプト|内容|
|:--|:--|
|システム|\<client>タグで区切られたクライアントHTMLと、\<server>タグで区切られたNodejsプログラムがあります。呼び出しているAPIに不備が無いかレビューしてください。|
|ユーザー|\<server>※上述のNodeJsプログラム\</server><br/>\<client>※上述の画面HTML\</client>|

|ChatGPTの回答|
|:--|
APIに不備は見当たりません。ただし、以下の点については改善の余地があるかもしれません。<br/><br/>- エラーハンドリングが不十分である。例えば、注文の受け付け時にmenu_idが不正な場合には400エラーを返しているが、それ以外のエラーについては適切なエラーハンドリングがされていない。<br/>- 料理の調理を行うAPIが存在しない。現在の実装では、料理の調理を行うAPIが存在しないため、配膳前に調理済みのステータスに変更することができない。

いや、2点目がクリティカルすぎますｗ
というわけで再度サーバサイドのプログラムを修正させます。

|プロンプト|内容|
|:--|:--|
|システム|\<client>タグで区切られたクライアントからの呼び出しメソッドに対して、\<server>タグ内のNodeJsプログラムを対応できるように修正してください。|
|ユーザー|\<server>※上述のNodeJsプログラム\</server><br/>\<client>※上述の画面HTML\</client>|

これで画面とサーバとの間のAPIに不足はなくなりました。
他にもフロント側で注文の遷移条件を間違っている部分などもあったので、そのあたりも修正させます。（割愛）

## スタイルシートの適用
このままだと味気の無い画面すぎるので、スタイルシートを追加していきます。
まずはクライアント側で style.css を読み込めるようにします。またHTMLの各要素にクラス名を付与させます。
|プロンプト|内容|
|:--|:--|
|システム|入力されるHTMLをcssをつかってお洒落なデザインに変更したいです。<br/>そのためにまずは要素単位で、クラス名を付与してください。また空のstyle.cssを読み込むようにHTMLを変更してください。|
|ユーザー|※上述の画面HTML|

あわせて、サーバサイド側でもsylte.cssを返却できるようにします。

|プロンプト|内容|
|:--|:--|
|システム|クライアントでは、以下のheaderをつかって、sylte.cssを指定しています。\<server>で区切られたサーバサイドプログラムをどう変更するとsylte.cssが適用されますか？<br/>(header略)|
|ユーザー|\<server>※上述のNodeJsプログラム\</server>|

最後にスタイルシートを作成させます。
|プロンプト|内容|
|:--|:--|
|システム|入力されるHTMLに対して、クラス名に対応してレストランサイトにふさわしいお洒落なスタイルシートを作成してください。<br/>なお、スタイルシートはsylte.cssに保存されるものとして作成してください。<br/>テーマカラーはオレンジとします。|
|ユーザー|※上述の画面HTML|

|ChatGPTの回答|
|:--|
以下が、クラス名に対応したスタイルシートの例です。sylte.cssに保存してください。<br/><br/>\```css<br/>/* 全体のスタイル */<br/>body {<br/>  font-family: 'Helvetica Neue', sans-serif;<br/>  background-color: #f5f5f5;<br/><br/>（略）

いい感じのスタイルシートができました。
ここまでの成果物で動作確認をすると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/977156/2c051433-cbbe-771f-61de-6a8427e40bf8.png)

うん、いい感じです。
さて、次はテストですね。

# 3. テスト

## テストシナリオの作成

まずはユースケースからテストシナリオを作成させます。
|プロンプト|内容|
|:--|:--|
|システム|あなたはシステムテスト戦略エキスパートです。<usecase>タグで区切られたユースケースについてテストシナリオを作成してください。|
|ユーザー|\<usecase>※上述のユースケース\</usecase>|

|ChatGPTの回答|
|:--|
|1. 注文の受け付け<br/>- 料理名、数量、価格、備考を入力し、注文情報が正しく保存されることを確認する<br/>- 注文情報が保存された後、注文テーブルに正しく反映されていることを確認する<br/><br/> （略）|

とりあえず、いいですね。今回はとってもシンプルなシナリオしかないので、問題なさげです。ここもテストシナリオ例をいれることでお好みの粒度、フォーマットのテストシナリオが作成できそうです。

## UIテスト

今回UIテストにはplaywrightを使ったのですが、playwrightの準備についてChatGPTの回答がハルシネーションしてしまいました。ので、<font color="red">**playwrightの準備は[公式サイト](https://playwright.dev/docs/intro)をもとに実施しました。**</font>

準備ができたらplaywrightのUIテストコードを生成させます。playwrightの記載方法についてChatGPTに不安があったので、記載例ということでplaywrightのテストコードの書き方を入れました。

|プロンプト|内容|
|:--|:--|
|システム|あなたはplaywrightを使ったUIテストのプロフェッショナルです。http://localhost:3000/にアクセスすると表示される \<html\>で区切られたWebシステムのUIテストを作成します。<br/><br/>まずは初期アクセス時に画面が正しく表示されるUIテストケースを作成してください。<br/><br/>## playwirghtの記述例<br/>import { test, expect } from '@playwright/test';<br/><br/>test('has title', async ({ page }) => {<br/>  await page.goto('https://playwright.dev/');<br/><br/>  // Expect a title "to contain" a substring.<br/>  await expect(page).toHaveTitle(/Playwright/);<br/>});<br/><br/>test('get started link', async ({ page }) => {<br/>  await page.goto('https://playwright.dev/');<br/><br/>  // Click the get started link.<br/>  await page.getByRole('link', { name: 'Get started' }).click();<br/><br/>  // Expects the URL to contain intro.<br/>  await expect(page).toHaveURL(/.*intro/);<br/>});|
|ユーザー|※上述のHTML|

これで初期アクセス時に画面が正しく表示されることを確認するテストコードができました。

|ChatGPTの回答|
|:--|

```javascript
import { test, expect } from '@playwright/test';

test('initial page load', async ({ page }) => {
  await page.goto('http://localhost:3000/');

  // Expect the title to be "注文一覧"
  await expect(page).toHaveTitle('注文一覧');

  // Expect the table to have the correct headers
  const headers = await page.$$eval('.order-table__header', (elements) =>
    elements.map((el) => el.textContent)
  );
  expect(headers).toEqual([
    '注文番号',
    'メニュー名',
    '数量',
    '備考',
    'ステータス',
    '操作',
  ]);

  // Expect the form to have the correct labels
  const labels = await page.$$eval('.order-form__label', (elements) =>
    elements.map((el) => el.textContent)
  );
  expect(labels).toEqual(['メニュー', '数量', '備考']);

  // Expect the submit button to have the correct text
  const buttonText = await page.$eval('.order-form__button', (el) => el.textContent);
  expect(buttonText).toBe('注文する');
});
```

注文受付のテストコードも同じように生成させます。

|プロンプト|内容|
|:--|:--|
|システム|あなたはplaywrightを使ったUIテストのプロフェッショナルです。http://localhost:3000/にアクセスすると表示される \<html\>で区切られたWebシステムのUIテストを作成します。<br/><br/>注文の受け付けシナリオのテストコードを作成してください。<br/>- 料理名、数量、価格、備考を入力し、注文情報が正しく保存されることを確認する<br/><br/>## playwirghtの記述例<br/>(上記と同じ記載例）|
|ユーザー|※上述のHTML|

注文受付のテストコードも作成されますが、そのままだとエラーが出てうまく動きません。4回ほど修正をした結果とりあえずは動くようにはなるのですが、出たエラーを解決させるループになるので、割愛します。
が、UIテストコード、それなりなのは出ますが、ちょっと複雑だとChatGPTにやらせるのはあんまり向いていないですね。ざっくり作ってもらったのを人間が修正する、くらいが妥当なレベルでした。
というか、**playwrightのレコーディング機能を使った方がここは圧倒的に楽ですね。。**

## UIテストの動作確認
`npx playwright test --ui`で動作を確認します。とりあえずの2ケースしか作っていませんが、いい感じですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/977156/cca3c76d-94ed-25e5-859f-d6eacd39b983.png)


## 単体テスト

あと単体テストも実施したいので、作成させます。

|プロンプト|内容|
|:--|:--|
|システム|あなたは熟練のITテストエキスパートです。\<server>で区切られたNodejs expressのプログラムに対して単体テストコードを作成してください。<br/>必要なライブラリを含めて実行可能なテストケースの作成をお願いします。|
|ユーザー|\<server>※上述のNodeJsプログラム\</server>|

|ChatGPTの回答|
|:--|
以下は、MochaとChaiを使用して、上記のNode.js expressプログラムの単体テストコードの例です。テストケースは、注文の受け付け、注文の確認、注文のキャンセル、料理の調理、注文の配膳、会計、メニューの取得、注文のステータス更新の8つの機能についてテストします。

```javascript
const chai = require('chai');
const chaiHttp = require('chai-http');
const app = require('./app'); // テスト対象のアプリケーション
const expect = chai.expect;

chai.use(chaiHttp);

describe('Express App', () => {
  // 注文の受け付け
  describe('POST /orders', () => {
    it('should create a new order', (done) => {
      chai.request(app)
        .post('/orders')
        .send({
          menu_id: 1,
          quantity: 2,
          note: 'no onion'
        })
        .end((err, res) => {
          expect(res).to.have.status(200);
          expect(res.body).to.be.an('object');
          expect(res.body).to.have.property('order_id');
          expect(res.body).to.have.property('menu_id');
          expect(res.body).to.have.property('quantity');
          expect(res.body).to.have.property('price');
          expect(res.body).to.have.property('note');
          expect(res.body).to.have.property('status');
          done();
        });
    });
  });

  // 注文の確認
  //（以降は省略）
```

<font color="red">**テスト対象のプログラムを正しく指定するだとか、`module.exports = server;` をいれるだとか、machaやchaiのインストールはちょっと面倒になってきたので、さくっと人間側でやってしまいました**</font>

今回作ったNodeJSのプログラムは、ビジネスロジックはほぼなくてAPIをうけてデータを更新するくらいのため、作成された単体テストはAPIをたたくテストになっちゃっています。なお、実行した結果 4/8 Passed なテストができましたが、これは各テストケースでデータの初期化をしていないため、編集操作系のテストがエラーになっているだけなので、とりあえずこの状態でよしとしちゃいます。
修正させるなら、各テストケース実行前にデータの初期化をいれさせればよさそうですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/977156/18f9bfc1-c006-eb4f-ed28-df85de5c0273.png)

# 4. API設計書の作成（コードから）

最後におまけ的に、できたプログラムをもとに設計書を作成させます。

|プロンプト|内容|
|:--|:--|
|システム|\<server>で区切られたサーバサイドプログラムについて、設計書を作成してください。以下の要素を含めるようにお願いします。<br/><br/> - API の概要<br/>  - API の受け口<br/>  - 処理の内容|
|ユーザー|\<server>※上述のNodeJsプログラム\</server>|

生成されたAPI設計書は以下の通りです。（全文）
====

APIの概要：

このサーバサイドプログラムは、レストランの注文システムを実現するためのAPIを提供します。以下のAPIがあります。

- 注文の受け付け
- 注文の確認
- キャンセル
- 料理の調理
- 注文の配膳
- 会計
- メニューの取得
- 注文のステータス更新

APIの受け口：

- POST /orders：注文の受け付け
- GET /orders：注文の確認
- PUT /orders/:order_id/cancel：キャンセル
- PUT /orders/:order_id/cook：料理の調理
- PUT /orders/:order_id/serve：注文の配膳
- PUT /orders/:order_id/pay：会計
- GET /menus：メニューの取得
- PUT /orders/:order_id：注文のステータス更新

処理の内容：

- 注文の受け付け：POST /orders

  リクエストボディに注文内容を含めて送信することで、注文を受け付けます。注文内容は、menu_id（メニューID）、quantity（数量）、note（備考）です。注文が正常に受け付けられた場合、注文ID、メニューID、数量、価格、備考、ステータスを含むJSONをレスポンスとして返します。

- 注文の確認：GET /orders

  注文一覧を取得します。注文一覧は、注文ID、メニューID、数量、価格、備考、ステータスを含むJSONの配列としてレスポンスとして返します。

- キャンセル：PUT /orders/:order_id/cancel

  注文IDを指定して、注文をキャンセルします。注文が正常にキャンセルされた場合、注文ID、メニューID、数量、価格、備考、ステータスを含むJSONをレスポンスとして返します。

- 料理の調理：PUT /orders/:order_id/cook

  注文IDを指定して、料理の調理を開始します。注文が正常に調理された場合、注文ID、メニューID、数量、価格、備考、ステータスを含むJSONをレスポンスとして返します。

- 注文の配膳：PUT /orders/:order_id/serve

  注文IDを指定して、注文の配膳を行います。注文が正常に配膳された場合、注文ID、メニューID、数量、価格、備考、ステータスを含むJSONをレスポンスとして返します。

- 会計：PUT /orders/:order_id/pay

  注文IDを指定して、会計を行います。注文が正常に会計された場合、注文ID、メニューID、数量、価格、備考、ステータス、合計金額を含むJSONをレスポンスとして返します。

- メニューの取得：GET /menus

  メニュー一覧を取得します。メニュー一覧は、メニューID、メニュー名、価格、カテゴリ、説明を含むJSONの配列としてレスポンスとして返します。

- 注文のステータス更新：PUT /orders/:order_id

  注文IDを指定して、注文のステータスを更新します。ステータスは、注文受付、調理中、調理済み、配膳済み、会計済み、キャンセル済みのいずれかです。注文が正常に更新された場合、注文ID、メニューID、数量、価格、備考、ステータスを含むJSONをレスポンスとして返します。

# まとめ

ChatGPTを使って、システム開発の一連の流れをとりあえずえいやえいやでやらせてみました。
本当は、Bing Chatの方が良いポイント、GitHub Copilot の方がふさわしいポイントなど多々あったのですが、とりあえず全部をChatGPT(35-turbo)に任せてみました。が、結果的にそれなりのものができたんじゃないかと思います。いや、思ったよりも色々作ってくれました。最終的に作成できたのは以下の成果物になります。

## 最終成果物
 - ユースケース分析結果
 - 業務フロー設計書
 - UML(ユースケース図)
 - UML(シーケンス図)
 - プログラム（サーバサイドNodejs)
 - プログラム（フロントHTML w/Vue)
 - テストシナリオ
 - UI テストコード（2ケース, 100% Passed)
 - Unit テストコード (8ケース, 50% Passed)
 - API設計書


ていうか、よく考えたらテーブルIDとかは必須ですよね。最初の分析のときに気づかず最後までいってしまったので、やりなおすならユースケース分析とか業務フローのところに「テーブルID単位で注文を管理できるようにする」が必要ですね。他にもまぁ色々ありそうですが、今回は正直細かい内容は全然確認していません。とりあえず動けばいいやので精神でやりました。けどこれ、もう少し現実的に考えるなら、お手持ちのフォーマットだとか、資料内容だとか、プロセスだとかに併せて使うことで人間側は相当楽できるのでは…、と思う結果にはなったかなと思います。

というわけで、ビールを大至急

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/977156/c15530bc-1ccf-4d2c-c763-20cc27fcb33a.png)

ちなみに今回試した範囲ではトークン4kでもぎりぎりなんとかなりましたけど、ちょうど6/13 に chatgpt-35-turbo-16k とかも出てきていますし、gpt4-32kとかもありますので、入れれる文章量やコード量なんかは将来的にはかなり気にしなくてよくなりそうでもありますね。あと沢山のトークンを入れるので、都度結構待たされたりしましたが、そういうのもだんだんと速くなって気にならなくなりそうです。

ある程度の知識やスキルがあればChatGPTを使い倒すことで、システム開発に新しいやり方が生まれそうという感触とともに、ChatGPT縛りプレイ～システム開発編を終わります。最後まで読んでいただき、ありがとうございました。