ChatGPTとGithub Copilotを使ったウェブサービス開発しばりプレイ実験記
こんにちは。Team DELTA の豊福です。
フルスタックエンジニアとして入社しましたが、今ではいろんな事業に片足突っ込んだり、PM 的なことをやったりしてます。
イントロダクション
このブログでは、ChatGPT と GitHub Copilot を使って以下の制約のもとウェブサービスを作る実験を行い、その記録や学びを紹介します。
ソースコードは原則 ChatGPT もしくは Copilot が記述し、制作者は基本的に加筆修正しない(ただし、環境変数や IaC が不可能な箇所を除く)
デプロイなどの作業は制作者が加筆修正可
このようなルールにしたのは、なるべく人間がアシストしない状態を作ることで、今後より AI に任せられるようにするためにどういう点を考慮したらよいかということを知りたかったからです。
今回はウェブサービスを完成するところまでは行きませんでしたが、7 つのユースケースを満たすだけのバックエンド API を実装完了するところまでを実験しました。
ChatGPT と Copilot の役割分担
結果として、ChatGPT は雛形を出力、トラブルシューティングを担当し、Copilot が微修正を行う役割分担となりました。
それもそのはず、Copilot は VSCode 内で動くので、その外では対応が難しいです。トラブルシューティングは本来 VSCode に軍配が上がりそうですが、現状は受け口の広い ChatGPT の仕事となりました。
実際のソースコード
ソースコードの例: あらゆるアプリケーションで必要な共通実装
テンプレ的な実装は基本 AI に脳死で任せてもいいなと思いました。以下は API クライアント共通実装の例です。しかも 1 発で指定した技術を用いて実装されています。
今後の生産性はなるべく安定したバージョンのライブラリや標準機能を使って、いかに AI が短い時間で汎用的な実装を出力するかというのが大事になりそう。
// apiClient.ts
import { NextApiRequest, NextApiResponse } from "next";
export type Handler = (
req: NextApiRequest,
res: NextApiResponse
) => void | Promise<void>;
export function createApiClient(handler: Handler) {
return async (req: NextApiRequest, res: NextApiResponse) => {
try {
await handler(req, res);
} catch (error) {
console.error(error);
res.status(500).json({ message: "Internal Server Error" });
}
};
}
ソースコードの例: スキーマ出力
ユースケースを通してからのスキーマ出力もなかなかの精度でした。今回は DynamoDB 前提で実装しています。
何故かコメントで出力されましたが、それを Copilot で微修正してあげるとすぐできます。何なら TypeScript の Template Literal Types まで使ってくれました。
interface DynamoDBItem {
PK: string;
SK: string;
GSI1PK?: string;
GSI1SK?: string;
// 共通属性
[key: string]: any;
}
// User
// PK: `USER#${userId}`
// SK: `USER#${userId}`
// Tip
// PK: `TIP#${tipId}`
// SK: `TIMESTAMP#${timestamp}`
// GSI1PK: `TAG#${tagId}`
// GSI1SK: `TIMESTAMP#${timestamp}`
// userId: string
// content: string
// prompt: string
// points: string
// likeCount: number
// tags: string[]
// Like
// PK: `USER#${userId}`
// SK: `LIKE#${tipId}`
// Tag
// PK: `TAG#${tagId}`
// SK: `TAG#${tagId}`
// tagName: string
ソースコードの例: データベースアクセス
必要な部分は最初から環境変数にしてくれます。
スキーマとセットで出力してもらえるプロンプトを考えられたなら、もはや高度な Rails scaffold のようになるかなと思いました。
import AWS from "aws-sdk";
// Configure AWS SDK with credentials from environment variables
AWS.config.update({
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
region: process.env.AWS_REGION, // Use the AWS region from the environment variable
});
const dynamoDB = new AWS.DynamoDB.DocumentClient();
export async function getRecentTips(limit: number) {
const params: AWS.DynamoDB.DocumentClient.QueryInput = {
TableName: process.env.DYNAMODB_TABLE_NAME as string, // Use the DynamoDB table name from the environment variable
IndexName: "GSI1",
KeyConditionExpression: "#gsi1pk = :gsi1pk",
ExpressionAttributeNames: {
"#gsi1pk": "GSI1PK",
},
ExpressionAttributeValues: {
":gsi1pk": "TIP",
},
ScanIndexForward: false,
Limit: limit,
};
try {
const result = await dynamoDB.query(params).promise();
return result.Items;
} catch (error) {
console.error("Error fetching recent tips:", error);
throw error;
}
}
Copilot の苦手な点や改善の余地
バージョン互換性が重要
開始前にバージョンを具体的に指定したら回避できるかもしれないが、例えば AWS CDK の場合バージョンによって書き方が異なるので、延々にエラーになるコードを出力し直していました。今後は AI に通した時に迷いなくツールが選ばれて他が淘汰されていきそうです。
フォルダ構成把握が苦手
import 文の出力がうまく行かなかったことがありました。これは一度出力した import 文を覚えてしまうのでしょうか。tree コマンドの出力結果を渡してもだめでした。
解決策は import 文を消して GUI でインポートする(ズル)。
エラー時のトラブルシューティングがまだ人間任せ
ChatGPT の出力が早いとはいったものの、出力したコマンドは体感で 5 割くらいが動かないので、いちいち出力を待ってエラーを貼ってを繰り返すのには時間がかかりました。
今回は実験しませんでしたが、以下のようなことが可能になると AI が自走できそうな気がします。
- 実装クリアの条件としてテストを記述
- テストをクリアするまでコードを出力、エラーを入力、コード再出力を繰り返す
- テスト通過を Slack などで通知
AI に対してなるべく具体的(仕様やバージョン、達成条件)で情報を渡しつつエラーを減らし、速く動くものを作るためのスキルが必要になりそうです。
結論
ウェブサービスを作成するとなると、まだ人間が必要です。人間が AI と対話しながら、AI が自走できるような問いを入力できることが重要です。一方で、今スムーズに行かない点は Copilot やプラグインで確実に解消されていくので、どんどんスピードが上がっていくでしょう。
そうなると、コンセプトメイキングや設計力で差がつく世界観になりそうです。技術的な設計は AI が吸収できたとしても、「どのようなサービスが良いサービスか」という良いものを定義し見抜く力の重要性が増していくでしょう。
参考資料
お話しませんか?
我々 DELTA は多数の事業を展開、サポートしていますが、もっともっと助けたい、前に進めたいプロジェクトがたくさんあります。
少しでも興味を持っていただけたら、まずはカジュアルにオンラインで話しませんか?
DM していただいても OK です。
Discussion