フロントエンドでAIと協働する
#AI #AIとの協働 #LLMs #ChatGPT
LLMs界隈を観測しながらフロントエンドのAI駆動開発の推移をウォッチする
---
2023/02/24
@fumi_sagawa: こないだやった仕様からのテストとコード出力がNotion AIでも良い感じ
要件定義をNotionでやっていればとてもスムーズに実装コードまで辿り着けそうな予感
(ただ、裏側がGPT-3だからかChatGPTより微妙な感じもある。ここは色々実験してみてかな)
仕様書とテストを用いた「AI駆動開発」
AI駆動開発と現状とのギャップを示す
「何を確認するか」「そのためにどんなテスト設計技法を用いれば良いか」といった部分は、まだまだAIに考えさせるのが難しい分野かなと思っています。
また、デシジョンテーブルの例や、境界値分析における振る舞いの表現のように、「物事を俯瞰的に見て表現する」「ハイレベルテストケースで表現する」といった部分はまだ苦手なのかなと感じました。
koushisa.iconもきになったので試してみた
---
2023/03/13
一度に説明するのは精度を下げる原因らしい
「有能なバカ」ChatGPTを使って1週間でiOSアプリを公開する方法
AIも人もフィードバックループが大事なんだなkoushisa.icon
---
プロンプト
code:md
エンタープライズ向けのタスク管理アプリケーションを開発している優秀なエンジニアのように振る舞ってください。
以下の仕様を元にjestとtesting libraryを利用したテストコードを作成してください。
また、以下の仕様を満たし、テストを通過するReactのFunctional ComponentをTypeScriptのコードで作成してください。
`markdown
## 仕様
### レイアウト
- タスク一覧
- タスク編集ボタン
- タスク削除ボタン
- タスク名インプットテキスト
- タスク追加ボタン
### 振る舞い
- タスク一覧
- 初期値はタスクが1件表示されている
- タスク編集ボタン
- 押下すると、"edit"とアラートで出力される
- タスク削除ボタン
- 押下すると、"destory"とアラートで出力される
- タスク名インプットテキスト
- 初期値は''
- タスク追加ボタン
- 押下すると、タスク名インプットテキストに入力されているタスクがタスク一覧へ表示される
`
出力形式は以下とします
`markdown
## 出力形式
- 概要
- テストコード
- 実装例
`
利用技術を以下に説明します。
ライブラリは最新バージョンを利用してください。
`markdown
## 利用ライブラリ
- React
- https://github.com/facebook/react
- TypeScript
- https://github.com/microsoft/TypeScript
- jest
- https://github.com/facebook/jest
- testing library
- https://github.com/testing-library/react-testing-library
- Fetch API
- https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
- Tanstack Query
- https://github.com/TanStack/query
- Mock Service Worker
- https://github.com/mswjs/msw
## 利用ライブラリに関する補足説明と制約
- React
- jest内のテストコードで利用する要素にはdata-testidを付与してください
- 目的はtesting libraryのByTestIdで該当要素を取得するためです
- Fetch API
- データフェッチで利用します
- エンドポイントはを利用します
- Tanstack Query
- React Hooksでデータフェッチするために利用します
- Mock Service Worker
- jestのtesting libraryのテストコードを通過させるために利用します
- jest
- タスク一覧のデータはMock Service Workerでモックします
- testing library
- jest内のテストコードで取得するHTML要素はtesting libraryのByTestIdで取得します
`
タスクの型を以下に説明します。Json Schemaで記述しますのでTypeScriptで型定義してください。
`tsx
## Json Schemaで記述したタスクの型
`
{
"$id": "task",
"title": "Task",
"type": "object",
"properties": {
"id": {
"type": "number",
"description": "The task's id."
},
"title": {
"type": "string",
"description": "The tasks's title."
}
}
}
`
## TypeScriptで記述したタスクの型
`
type Task = {
id: number
title: string
}
`
`
出力するコードの構造を以下に説明します。
ECMAScript Moduleに準拠したimport/exportで実装を分割してください。
`markdown
## ディレクトリ構造
- src
- api
- tasks.ts
- components
- Task.list.tsx
- Task.item.tsx
- Task.list.test.tsx
## ディレクトリ構造の説明
- .tsで終わるファイル名はデータフェッチのコードを記述します
- .tsxで終わるファイル名ReactのFunctional Componentのコードを記述します
- .test.tsxで終わるファイル名はtesting libraryのコードを記述します
`
シナリオテストの一例を以下に説明します。
`markdown
## シナリオテスト
- タスク一覧
- 初期値はタスクが1件表示されている
- タスク編集ボタンを押下すると、"edit"とアラートで出力される
- タスク削除ボタンを押下すると、"destory"とアラートで出力される
- タスク名インプットテキスト
- 初期値は''で表示されている
- タスク追加ボタン
- 押下すると、タスク名インプットテキストに入力されている文字列がタスク一覧へ表示される
`
5歳のエンジニアでも分かるようにハンズオン形式で作成してください。
結果
わりと納得のいく出力結果だった koushisa.icon
詳しい感想は後述
https://scrapbox.io/files/63f859602e62d9001c004223.png
https://scrapbox.io/files/63f859698ceeaf001b5fca33.png
https://scrapbox.io/files/63f85977b31ab5001ba795e3.png
https://scrapbox.io/files/63f8598f91ae5d001ba77d2c.png
code:ts
import { rest } from 'msw'
import { setupServer } from 'msw/node'
import React from 'react'
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import '@testing-library/jest-dom/extend-expect'
import { QueryClient, QueryClientProvider } from 'react-query'
import TaskList from './TaskList'
const server = setupServer(
rest.get('https://jsonplaceholder.typicode.com/todos', (req, res, ctx) => {
return res(
ctx.json([
{
userId: 1,
id: 1,
title: 'delectus aut autem',
completed: false,
},
])
)
})
)
beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())
describe('TaskList', () => {
it('renders task list with initial value', async () => {
render(
<QueryClientProvider client={new QueryClient()}>
<TaskList />
</QueryClientProvider>
)
await waitFor(() => screen.getByTestId('task-1'))
expect(screen.getByTestId('task-1')).toBeInTheDocument()
expect(screen.getByText('delectus aut autem')).toBeInTheDocument()
expect(screen.getByTestId('task-edit-button-1')).toBeInTheDocument()
expect(screen.getByTestId('task-delete-button-1')).toBeInTheDocument()
})
it('renders task list with added task', async () => {
render(
<QueryClientProvider client={new Query
https://scrapbox.io/files/63f859b67fe5ec001b684bc1.png
https://scrapbox.io/files/63f859bdec8532001c73857c.png
code:ts
import { useState } from 'react';
import { useQuery } from 'react-query';
import { Task } from '../types/task';
const fetchTasks = async (): Promise<Task[]> => {
const res = await fetch('https://jsonplaceholder.typicode.com/todos');
const data = await res.json();
return data;
};
const TaskList = () => {
const taskName, setTaskName = useState('');
const { data: tasks } = useQuery<Task[]>('tasks', fetchTasks);
const handleTaskNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setTaskName(event.target.value);
};
const handleAddTask = () => {
const newTask: Task = { id: tasks.length + 1, title: taskName };
setTaskName('');
// TODO: add newTask to the list of tasks
};
const handleEditTask = (id: number) => {
alert('edit');
};
const handleDeleteTask = (id: number) => {
alert('destroy');
};
return (
<div>
<ul data-testid="task-list">
{tasks?.map((task) => (
<li key={task.id} data-testid="task-item">
{task.title}
<button data-testid="edit-button" onClick={() => handleEditTask(task.id)}>
Edit
</button>
<button data-testid="delete-button" onClick={() => handleDeleteTask(task.id)}>
Delete
</button>
</li>
))}
</ul>
<input data-testid="task-name-input" type="text" value={taskName} onChange={handleTaskNameChange} />
<button data-testid="add-task-button" onClick={handleAddTask}>
Add Task
</button>
</div>
);
};
export default TaskList;
感想
PoCを作る叩きならよい
「おっ?」とおもったポイント
json schemaを解釈してくれてmsw作ってくれる
data-testidとかまでマッピングした状態でテストコード吐いてくれる
プロダクション品質にはまだまだ足りない
人間の手でメンテナンス可能な構造にもう1段落とし込む手間が必要
AIが出力したコードと人間が書いたコードが混ざったときのカオス具合が想像できない
AIフレンドリーな仕様定義能力が求められる
用語定義とその出処を文脈から取り除く
一つ一つをScrapboxでいうページにするみたいな
トピック指向
表記ゆれを防ぐためのユビキタス言語
今回の例でも、システム的に重要な単語はブラケットで注釈してみた
わかってないこと
これ効果あるのかな?koushisa.icon
wip: https://www.notion.so/763074395d0f49ababd9bcf3a9fe4e3c?pvs=4#caa77755bd8748c489f09dbedf1d1d1a
FlexGenみたいなLLMsにドメインやエンティティを教育させてみたい
TODO
このシステムにおけるタスクとは何か、みたいな
「〜とは何か」とは
コンパイル失敗するコードも入ってそう
動かさないとそれが正しいのかが分からないのは手間である
REPLやRefraction使ってその場でデバッグしたい
@umiyuki_ai: これまた仰天するような事件。LangChainでAIにPython…
TODO
上記はPythonの事例
Sandpackで実際にブラウザ上に描画しつつ、似たようなことが出来ないか?
テスト
要素のクエリと実装をあまり結びつけたくない
壊れやすいテストになるし読みづらい
現段階ではa11yに準拠したroleでテストコードを書いてもらうのは難しいみたい
ここは課題か
コアロジックさえ担保できればUIの実装はブラックボックスでもいいのでtestidはアリかも
時系列で変わる状態を機械的にテストするのは難しそう
XStateで実装出来れば...可能性はある...?koushisa.icon
理想的にはtesting-libraryとかmswとか手で書かかずに済ませたい
mablのようなSaaSで運用コストを減らせたらよさそう
検証する観点も分割できる
DEV Teamはシステム観点
BIZ Teamはユーザー観点
マシンリーダブルな仕様定義を心がける
仕様ファーストで対話しつつ実装とテストを同時に作成する
人間が振る舞いを検証する
実装を完全にブラックボックスにすると運用に難があるのではという気持ちになる
エッジケースの対応コスト > 自分で書くコスト
形式手法による仕様定義をAIが解釈して実装できるとうまく使えそう???
学習ハードル高そう
一度やり方を覚えれば再現性は高い
出力したコードの品質や妥当性を検証するためには人間がQA知識持ってないとダメ
@fumi_sagawa: @nihonbuson 非常に同感です。
AIに任せるフェーズに移ったとしたらQAの知識こそ重要になりそうだと思いました
いつかテストの選択も任せられるかもしれませんが、現時点で学ぶべきは設計とQA(テスト技能の正しい選択方法)だなーと…
QA Teamはどう介在するか
ファクトチェックの専門家的な役割になるのかな
AIへプログラム作成を依頼する時点で仕様定義が終わっていると開発と同時にテストはできる
テスト計画、テスト分析、テスト設計には高度な知識と経験が必要
システムそのものの理解がなければできない
テストケース作成
プロンプトからテストの手法は検討できる
開発組織として活用するときは個々の専門性や責任範囲をどうおくかにもよるか
実際は開発を並行したいというのはあるはず
プロンプト書く人とその結果を検証する人で分業するとか?
仕様変更にどう対応する?
手でコードを変更するのは簡単だが、AIにその経緯を理解させることや、リグレッション管理のコストはかかる
ここは諦めるのが現実的か
足るを知る
機能は追加よりも変更したり削除するほうが難しい
UI/UXはどうなのか
ChatGPTでフロントエンドのコードを出力する
たぶん、Figmaからも吐けるツールが今後でてくる
フロントエンドにおけるテスト駆動開発の実践と概説
こういうのみてると0→1フェーズでのAIとの協働は2~3年後には現実的だなと思った
まとめ
現時点ではQAと仕様定義がネック
QAのAIに関したmiddlewareが台頭してくる時期が来るはず
ここの穴を埋めるStatelyやmablに期待
期待していること
1. 対話による自然言語の仕様定義
2. 仕様定義からインタラクションや状態遷移表やデシジョンテーブルを作成
3. シームレスにFinite State Machine(FSM)でコアロジックを実装
4. Model-based testingとE2Eテストで振る舞いを担保する
---
2023/03/28
ChatGPTプラグインの登場で フロントエンドでAIと協働する#63fc223e8660300000a1e514 が現実的になった
StackBlitz と ChatGPT でチャット形式でUIを構築できるツールを作ってみた
@shanegJP: 「ChatGPT・プラグイン」ではコードを直に走らせることもできるので動画編集はもちろん、プログラミングも全てChatGPT内で完了できます。
UXの革命が起こるでしょう。マウスはもういらん。
React は人類が直接コーディングする最後の UI ライブラリになる#640a65248660300000927437
---
2023/05/28
CSSを持たない Headless な UI ライブラリと ChatGPT によるマークアップ生成を試してみる
---
2024/10/17
AIをソフトウェア開発へ取り込む際のテストにLLMsを活用する可能性に想いを馳せる