AIを活用した開発の基本

# はじめに

最近、AIの進化がすごいですね。
私もスマホアプリの個人開発でAIを活用してみたところ、1/16の時間で完成しました。
（見積り 80h -> 実績 5h）

この記事では、AI（ChatGPT）を開発に活用した例をご紹介します。

ただし、毎週のように様々なAIプロダクトが発表されており、これが正解ではありません。
基本的な考え方は変わらないと思うので、状況に応じて柔軟に工夫し、最適なツールおよび活用方法を見つけてください。

# 前提知識

・AIは幅広い知識を持っているが、正解を教えてくれるわけではない。
・AIからの回答は提案であり、最終判断は人間が行う。
・前提条件とやりたいことを明確に伝えると、より正確な提案を得られやすい。
・イメージと違う方向に行ったら、それはプロンプト（質問や指示の仕方）が原因。プロンプトを繰り返し見直すべき。
・何度か再生成したり、プロンプトを微修正したりすると、より希望に沿った回答（提案）を得られることがある。

# 事前準備

ChatGPTに依頼する前に、前提条件と要件を明確にしましょう。
相手はこちらのことを知らないので、できるだけイメージしやすいようにリストアップします。

この例では、簡易的な旧Twitter風のSNSを作成します。

やりたいこと：Twitter風の簡易的なSNSを作りたい
OS：MacOS
フロントエンド：TypeScript / React
バックエンド：Node
データベース：JSONファイル（データベースの代用で、/tmp配下に設置）
要件：異なるアカウントが同じJSONファイルを参照し、5秒ごとに最新情報を読み込む。また、ポストに👍でリアクションできる機能を実装する。

# 実践
## プロンプト
ChatGPTに以下のプロンプトを送りました。
```
Twitter風の簡易的なSNSを作りたいです。
以下の要件で、環境構築手順、コード、実行方法を教えてください。

OS：MacOS
フロントエンド：TypeScript / React
バックエンド：Node
データベース：JSONファイル（データベースの代用で、/tmp配下に設置）
要件：異なるアカウントが同じJSONファイルを参照し、5秒ごとに最新情報を読み込む。また、ポストしたり、ポストに👍でリアクションできる機能を実装する。

フロントエンド、バックエンドともに詳細なコードを書いてください。
```

## ChatGPTからのレスポンス（原文まま）
MacOS環境で、TypeScript/Reactを使用したフロントエンドと、Node.jsを使用したバックエンドで構築される簡易的なSNSシステムを作成するためのステップをご案内します。データベースはJSONファイルとして/tmpディレクトリに配置し、異なるアカウントが同じファイルを参照し、5秒ごとに最新情報を読み込む設計です。また、ポストしたり、ポストに👍でリアクションできる機能を実装します。

**環境構築**
**Node.jsのインストール:**
MacOSにNode.jsがインストールされていない場合は、[Node.js公式サイト](https://nodejs.org/en)からインストールしてください。

**プロジェクトディレクトリの作成:**
任意のディレクトリで以下のコマンドを実行してプロジェクトフォルダを作成します。

```bash
mkdir my-sns-app
cd my-sns-app
```
**フロントエンドのセットアップ:**
Reactアプリケーションを作成します。

```bash
npx create-react-app frontend --template typescript
cd frontend
npm install axios uuid @types/uuid
```
**バックエンドのセットアップ:**
新しいターミナルウィンドウを開き、プロジェクトディレクトリに戻ってバックエンドのセットアップを行います。

```bash
cd my-sns-app
mkdir backend
cd backend
npm init -y
npm install express cors body-parser
```

**バックエンドのコード**
backendフォルダ内にindex.jsファイルを作成し、以下のコードを記述します。
```javascript:backend/index.js
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const fs = require('fs');
const path = require('path');

const app = express();
app.use(cors());
app.use(bodyParser.json());

const filePath = path.join('/tmp', 'posts.json');

app.get('/posts', (req, res) => {
  if (!fs.existsSync(filePath)) {
    fs.writeFileSync(filePath, JSON.stringify([]));
  }
  const posts = JSON.parse(fs.readFileSync(filePath));
  res.json(posts);
});

app.post('/post', (req, res) => {
  const post = req.body;
  if (!fs.existsSync(filePath)) {
    fs.writeFileSync(filePath, JSON.stringify([]));
  }
  const posts = JSON.parse(fs.readFileSync(filePath));
  posts.push(post);
  fs.writeFileSync(filePath, JSON.stringify(posts));
  res.json({ status: 'success' });
});

app.post('/react', (req, res) => {
  const { id } = req.body;
  const posts = JSON.parse(fs.readFileSync(filePath));
  const postIndex = posts.findIndex(p => p.id === id);
  if (postIndex !== -1) {
    posts[postIndex].reactions++;
  }
  fs.writeFileSync(filePath, JSON.stringify(posts));
  res.json({ status: 'success' });
});

const PORT = 5000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});
```

**フロントエンドのコード**
frontend/src内のApp.tsxファイルを以下のように編集します。
```javascript:frontend/src/App.tsx
import React, { useState, useEffect } from 'react';
import axios from 'axios';

interface Post {
  id: string;
  content: string;
  reactions: number;
}

const App: React.FC = () => {
  const [posts, setPosts] = useState<Post[]>([]);
  
  useEffect(() => {
    const interval = setInterval(() => {
      axios.get('http://localhost:5000/posts').then(response => {
        setPosts(response.data);
      });
    }, 5000);
    return () => clearInterval(interval);
  }, []);

  const handleReact = (id: string) => {
    axios.post('http://localhost:5000/react', { id }).then(() => {
      // 再読み込み処理
      axios.get('http://localhost:5000/posts').then(response => {
        setPosts(response.data);
      });
    });
  };

  return (
    <div>
      {posts.map(post => (
        <div key={post.id}>
          <p>{post.content}</p>
          <button onClick={() => handleReact(post.id)}>👍 {post.reactions}</button>
        </div>
      ))}
    </div>
  );
}

export default App;
```

**実行方法**
**バックエンドの実行:**
backendディレクトリで以下のコマンドを実行します。

```bash
node index.js
```

**フロントエンドの実行:**
frontendディレクトリで以下のコマンドを実行します。
```bash
npm start
```

これで基本的なTwitter風のSNSアプリケーションが実行されます。フロントエンドとバックエンドが正しく設定され、5秒ごとに最新の投稿が表示されるようになります。また、投稿に対して👍でリアクションをつけることができます。

## 実行結果

ChatGPTからの提案通りに、環境構築して、ファイルを編集して、起動コマンドを実行しました。

それでは、画面を見てみます。
![fig01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407770/4e8a27b1-ebd5-0e73-862d-46cb532e5ddb.png)

デザインは置いといて、表示されてますね！

次に、ポストしてみましょう。
![fig02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407770/4c50d3b3-155e-d1f4-adca-dea751e4bfc5.png)

ちゃんとポストされました。

今回はデータをJSONファイルに出力しているので、そちらも確認してみます。
```bash
$ cat /tmp/posts.json 
[{"id":"8b155db3-41a5-4c99-b2d2-671796a5aa44","content":"テスト","reactions":0}]
```
データも入っているようです。

別ブラウザで見ると、どうなるでしょうか。

左がChrome、右がEdgeです。
Edgeからポストして、Chrome側に反映されるか試してみました。
![fig03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407770/b43a4c4f-9fab-2e86-26d6-863ba7f0bd92.png)

5秒おきにJSONファイルを読み込んでいるのでタイムラグはありますが、Edge側でポストした数秒後に、Chrome側に反映されました！

さらに、お互いにポストやいいねをしてみます。

![fig04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407770/4722f047-4ec6-590e-2cfc-602dc0d4f0f3.png)

いいですね:thumbsup:

今回はエラーも無く、スムーズに動くものが作れました。

最初にChatGPTにプロンプトを送ってからここまで、約30分。

デザインやDB利用を含めてお願いしても、2時間あれば、それなりのものが出来てしまいます。

# 備考
通常、ChatGPTからの最初のレスポンス通りに実施すると、一部のライブラリが足りなかったり、何らかのエラーが出ることの方が多いです。

そういった場合も、画面のキャプチャやエラーメッセージ、該当箇所のコードなどを送れば、解決策を提案してくれます。

ほとんどコピペなので、通勤電車内でも作れてしまいますね。

学習で使うと、自分が作りたいもので効率的に学習できます。
学習効率が飛躍的にアップするので、おすすめです:thumbsup:

※業務で利用する場合は秘匿情報を送らないように注意してください。
※また、コードが学習に利用されないかどうかも確認が必要です。

# 最後に

AIを開発に活用するためには、明確な目的と適切なプロンプト設定が重要です。
また、AIの回答はあくまで提案であり、最終的な判断は、開発者自身が行う必要があります。

柔軟な発想と適切なプロンプトで、AIの力を最大限に活用しましょう！