【ServiceNow】ChatGPT 4o に爆速でビンゴアプリを作らせた話

:::note
この記事は ServiceNow アドベントカレンダー 2024 の12月21日分（シリーズ２）の記事として執筆しています。
:::

https://qiita.com/advent-calendar/2024/servicenow

## はじめに

11月某日、弊プロジェクトの５周年記念会が都内某所で開催されました。

企画段階で、せっかくだから何か催し物が欲しいよねという話になり……。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632778/632ebf3d-76cc-1418-50ef-03f7ebee08f8.png)

世の中には[言い出しっぺの法則](https://ja.wikipedia.org/wiki/%E8%A8%80%E3%81%84%E5%87%BA%E3%81%97%E3%81%A3%E3%81%BA%E3%81%AE%E6%B3%95%E5%89%87#:~:text=%E8%A8%80%E3%81%84%E5%87%BA%E3%81%97%E3%81%A3%E3%81%BA%E3%81%AE%E6%B3%95%E5%89%87%EF%BC%88%E3%81%84%E3%81%84%E3%81%A0,%E3%81%82%E3%82%8B%E3%81%A8%E3%81%84%E3%81%86%E7%90%86%E5%BF%B5%E3%82%92%E6%8C%87%E3%81%99%E3%80%82)というものがあるようで……。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632778/a2b5332a-ab53-94ed-8279-226ea38d6de1.png)


業務時間外に作り上げました。
「やっつけで」とか書いて謙遜ぶってますが、**設計・実装を考えたのはほぼ ChatGPT** です。

## ChatGPT 4o に爆速でビンゴアプリを作らせてみる

開発環境はServiceNowのPDI（バージョンXanadu）です。
まずは以下のプロンプトから開始しました。

```
ServiceNowでビンゴアプリケーションが使いたいです。

[ビンゴシート]
- 中央はFreeとなっています。
- 左の列から1～15, 16～30, 31～45, 46～60, 61～75の中からランダムに5つの数字が割り当てられます。
- ビンゴシートの内容は参加者ごとに別々になっている必要があります。

[参加者]
- ポータル上でビンゴシートを表示します。
- 出た数字の部分をクリックして穴をあけることができます。
- これまでに出た数字の履歴を確認することができます。

[運営]
- Core UIで既に出た数字を管理します。
```

ChatGPTからの回答は以下のとおり。

![スクリーンショット 2024-12-19 14.06.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632778/248cdd6a-d431-0e57-8207-f57770986d0f.png)

おお、テーブル定義まで提案してくれるんですね。
ビンゴシートの情報はString形のフィールドにJSON形式で格納すればよい、と。なるほど。
`drawn_timestamp` は `sys_created_on` 等で代用可能では？　と思ったので無視しました。
その他にも、サーバサイド／クライアントのスクリプトとHTMLが提案され、**実装は Portal Widget で行うことに決定**しました。

先ほどのチャットに続けて、
- [Bingo!] ボタンを表示して、クリックしたらSheetテーブルの `is_bingo` を更新したい
- 画面の初回表示時にビンゴシートを自動生成したい
- 自動生成の処理はサーバサイドで行いたい

等の要望を一つひとつ追加していき、提案されたスクリプトが以下のとおりです。

### Body HTML Template
![html_template.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632778/574080b6-a5bd-a210-8b07-0e5c02e3b314.png)

### Client Controller
![client_controller.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632778/1bc08cc1-07de-b6cf-8f01-5f12d43b1468.png)

Client controllerは `api.controller=...` の表記に書き換えました。
また、`x_bingo_sheet` の部分は環境に合わせて適切なテーブル名に置換する必要がありました。

### Server Script
![server_script.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632778/13a7c52b-8f8e-f3de-1d8e-8740f526cda6.png)

こちらも `x_bingo_sheet` の部分は書き換える必要があります。

### Widgetのプレビュー結果

プレビュー画面は以下のとおりです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632778/b0198ec5-7561-467d-8130-cf731cd2ca02.png)

何となくそれっぽい形になったので、これをベースにして

- ビンゴシートの行と列を転置したい
- ビンゴシートとビンゴ達成者のあいだに、抽選で出た数字の履歴を表示したい
- 既に出た数字のみクリックできるようにしたい
- 既にビンゴシートを作成済みの場合はテーブルから取得したい
- ビンゴシートをもっとビンゴシートっぽい（？）デザインにしたい

等々……時には思いどおりの挙動にならない原因を ChatGPT と一緒に考えつつ、トータル１時間半ぐらいで「とりあえず遊べるレベル」のビンゴアプリが完成しました。

## sorekara doshitano

結論から言うと、**幹事がドンキでビンゴセットを買ってきた**のでこのアプリが登板する機会は無かったのですが、直前まで ChatGPT との問答を繰り返した結果、

* ログイン不要で遊べるよう全面的に改修
* 進行状況を準リアルタイム配信（モバイルブラウザにも対応）
* ビンゴシートの状態をCookieに保存
* インタラクティブなCSS
* 幹事用の抽選画面

等の趣向を凝らし、最終的にはこちらのような出来栄えとなりました。

### 画面（モバイルブラウザ）

リーチした箇所は CSS でチカチカと blink するようにしました。
抽選で選ばれた数字は、「出た数字の履歴」に自動で反映されます。
ビンゴしたユーザは参加者全員に対して `addInfoMessage()` で通知するようにしています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632778/0cb740d6-8aa9-8972-80fa-8a26ffb9df84.png" width=50%>

### Sheet テーブル

User IDには `gs.generateGUID()` で生成した一意の識別子を保存するようにしました。
同じ情報を Cookie に保存することで、画面の初回表示時にはビンゴシートを新規作成、リロード時には作成済みのビンゴシートを再描画するようにしています。

![スクリーンショット 2024-12-19 21.07.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632778/efe5e937-bace-fb26-0484-53e0ff5a456a.png)

### Drawn Number テーブル

あらかじめ1〜75の数字を登録し、選ばれたか否かをフラグで管理するように変更しました。

![スクリーンショット 2024-12-19 21.08.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632778/5a00510a-7d9a-16a3-be4d-020906b2b8ca.png) 

拡張性を考慮すると、Sheet と Drawn Number を関連リストで管理する「Game テーブル」のようなものがあるとよさそうです。

### 抽選画面

必要最小限の機能のみに絞り、UIページで実現しています。
ビンゴシートに労力を使い果たしたので、こちらはほぼ ChatGPT に丸投げしています。

![スクリーンショット 2024-12-19 21.03.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632778/5dade9d5-de4f-4b66-a1e8-9f00098a50d6.png)

## プロンプトの工夫ポイント

### 現在の状態を提示する

今回の Portal Widget のように、サーバ／クライアントの両方にスクリプトを記述する必要がある場合、提案されたスクリプトをどこに書くべきか？　が分かりづらい場合があります。
以下のように現在の各フォームの内容を提示してあげることにより、記述すべき箇所を明確にしてくれるとともに、出力されるスクリプトの精度も向上する気がしました。

```
ServiceNowで以下の機能を実現するPortalWidgetを開発したいです。

*（ここに要件１を記述）
*（ここに要件２を記述）
*（ここに要件３を記述）
　　　　　：
　　　　　：

初期状態は以下のとおりです。
[Body HTML Template]
<div>
<!-- your widget template -->
</div>

[Client controller]
api.controller=function() {
  /* widget controller */
  var c = this;
};

[Server script]
(function() {
  /* populate the 'data' object */
  /* e.g., data.table = $sp.getValue('table'); */

})();
```

### diff形式で出力

毎回スクリプト全体を生成し直す方法だと、貼り付けが楽な反面、どこがどのように変更されたのかが分からず、人間がスクリプトの仕組みを理解できない状態に陥りがちです。
「修正箇所をdiff形式で出力してください」と追加してあげると、変更内容の見通しがよくなりました。

```
ビンゴ達成時にはブリンクを解除したいです。
Body HTML template, CSS, Client controllerにどのように修正を加えればいいですか？
修正箇所をdiff形式で出力してください。
```

### CSS は HTML 丸投げで

CSS についてはほとんど知見が無かったので、先に HTML を作り上げ、完成した HTML を ChatGPT に丸投げして考えてもらいました。
混乱を避けるため、スクリプトとは別のチャットで生成させています。
```
ServiceNowでビンゴアプリを作ろうとしています。
以下のHTMLをよりおしゃれにしたいので、CSSデザイナーとして提案をしてくれませんか？

[HTML Template]
<div class="container">
  <h2>ビンゴシート</h2>
  :
  :
</div>
```
我ながら雑なリクエストだなと思うのですが、これだけでもいい感じの CSS を提案してくれるので驚きです。


## 雑感（生成AIは開発に使えるのか？）

### PoC との相性は良い

PoC での開発には抜群の効果を発揮すると思います。これ以降、「動くものをさくっと作って見せたいな」と思ったときには積極的に生成AIを活用するようにしています。

ただし、出力されたスクリプトが実用に耐えられる品質か？　と問われるとう〜ん……という印象です。
まず、**要件が複雑化すればするほどスパゲティコード化しやすい**という傾向があります。要約が得意な ChatGPT ですが、スクリプトのリファクタリングには期待したほどの効果は得られませんでした。
また人間側の問題として、自分の期待どおりに生成されたアウトプットを無意識に「正しい」と信じ込む**確証バイアスが働き、スクリプトに潜む問題点や欠陥を見落としやすくなる**という懸念があります。
実際の開発では参考程度に留めておくのがよいでしょう。

### 「顧客が本当に必要だったもの」に注力できる

上の内容とも少し被るのですが、「要件を出す→実装する→さらに要件を出す→実装する→……」のサイクルを超高速で回せるので、**実現方法について考える時間を短縮し、要件の精度を高めることに注力することができる**というのは大きな気づきでした。

一方で、生成AIが相手と言えど「実はモバイルにも対応させたいんだけど……」のような**前提がひっくり返るレベルの方針変更は困難を極めるので、最初期の段階で提示してあげる**必要があると感じました。

### エラーメッセージの分析能力が高い

今までエラーが発生した場合にルーティーン的に行っていた、
①エラーメッセージを翻訳する
②エラーの内容を理解する
③原因の当たりをつける
④修正
という作業のうち①～③までを代行してくれる点には非常に魅力を感じました。

しかしながら、頓珍漢な回答をされて泥沼にハマる[^1]場面もあったり、エラーは出ないけど何かおかしいという場合もあったりするので、**人間側の技術力およびデバッグ力は引き続き要求される**ことになりそうです。

[^1]: テーブルの更新を Push 通知する方法については最後まで期待した回答が得られず……有スキル者の「それ [recordWatch](https://www.servicenow.com/docs/ja-JP/bundle/utah-api-reference/page/app-store/dev_portal/API_reference/spUtil/concept/spUtilAPI.html#SPU-recordWatch_O_S_S_F) で出来ますよ」の一言で解決しました（最終的にはモバイルブラウザへの対応のため、Polling方式に変更しました）。