OpenAIのChatGPT3.5でペルソナ作成/ジョブ理論シュミレーション/ビジネスモデルキャンバス作成/要件定義/クラス図作成/ソースコード作成をやってみた
掲題のとおりです。
アプリ開発時の一連の流れを試すことにフォーカスしているので、情報の不足、内容の誤りが含まれています。
それを理解した上で見ていただけたら幸いです。
マーケターとの会話
まずは、マーケターと会話していきます。
マーケターをシミュレーション
まずは、素晴らしい頭脳を持ったマーケターを作り出しましょう。
このプロンプトは、プロンプトエンジニアリングについて調べていたら、林さんという方 がすごいプロンプトを紹介していて「これ使えそうだな」と思ってコピペして使っています。
プロンプトが効いているのか分かりません。
おまじないとして使っています。
シミュレーションしてください。
プロンプト1:
抽象オブジェクト:マーケター
サブオブジェクト:[サブオブジェクト1]、[サブオブジェクト2]、[サブオブジェクト3]...
知識:[知識1]、[知識2]、[知識3]...
能力:[能力1]、[能力2]、[能力3]...
管理オブジェクト:[管理オブジェクト1]、[管理オブジェクト2]、[管理オブジェクト3]...
あなたは[プロンプト1]に関して熟知している優秀な[抽象オブジェクト]です。
一部文章がおかしいですが
「私は優秀なマーケターだぞ!」
という自信が文章から溢れているので、優秀なマーケターをシミュレーションできたのだと思います(たぶん)
ペルソナ作成
どんな人の課題を解決するアプリを作るのかを明確にするためにペルソナを作ります。
私はジョブ理論が好きなので、ペルソナを作った後にジョブ理論を使用したシミュレーションをしてもらいましょう。
ありがとうございます。
では、ペルソナ像を作成していきましょう。
ターゲット:日々の予定を管理したい人
ターゲット数: 1
条件:日本人、20代~30代の女性
[ターゲット]を参考に、現実的で具体的なペルソナを[ターゲットの数]だけ[条件]に従って作成し、ジョブ理論に基づき具体的なシミュレーションをしてください。
名前:ペルソナの名前は?
年齢:年齢は?
居住地:居住地は?
職業:職業は?
年収:年収は?
趣味:趣味は?
家族構成:家族構成は?
好きなブランド:好きなブランドは?
好きな雑誌:好きな雑誌は?
休日の過ごし方:休日の過ごし方は?
好むメディア:好むメディアは?
よく利用するWebサイト:よく利用するWebサイトは?
よく利用するアプリ:よく利用するアプリは?
SNS利用度:SNS利用度は?
情報収集の行動パターン:情報収集の行動パターンは?
性格:どのような性格か?
価値観:どのような価値観を持っている?
人生観:どのような人生観を持っている?
願望:願望は何か?
悩み:悩みは何か?
ゴール:ゴールは何か?
制約:制約は何か?
状況:ジョブはどのような状況下で発生している?
得たい成果:ジョブを成し遂げて得たい成果は?
得たくない成果:ジョブを成し遂げて得たくない成果は?
自身や他者から得たい感情:自身や他者から得たい感情は?
自身や他者から得たくない感情:自身や他者から得たい得たくない感情は何か?
代替手段:ジョブを成し遂げるために現在使用しているサービスは何か?それは無償か?
支払い意思:支払う意思はあるのか?
予算:いくらほどの金額を費やせるのか?
#制約条件
・項目間の整合性をとり、現実的なペルソナを作り上げること。
思った以上にそれっぽいアウトプットが出来上がりました。
本当のプロジェクトでは、複数のペルソナを作成し、それを参考にして自分たちのペルソナを作っていくことになりそうですね。
あと、個人的にジョブ理論でシミュレーションかけるのはオススメですね。
ユーザーが望んでいるジョブが分かりやすくなります。
シナリオ作成
橋本さんがアプリを使うまでのシナリオを考えてもらいましょう。
では、ペルソナ行動シナリオを作成してください。
どのように製品・サービスを利用するのかを、具体的な行動とその背景を物語風に記述してください。
「GoogleカレンダーとGoogle Todoで解決するんじゃね?」
と思いましたが、シンプルで使いやすそうなデザインがとても気に入ったのでしょう。
デザイナー・エンジニアはUI/UXでの差別化に苦しみそうです。
機能一覧と画面一覧作成
(ある程度プロンプトを実行してからnoteを書いているのですが、マーケターにこの作業をやらせるのは間違いと書いているときに気づきました…)
次は機能一覧と画面一覧を作成します。
では、ペルソナとペルソナ行動シナリオを基に、必要な機能一覧と画面一覧を作成してください。
特に言うことはないですね。
アプリ名決め
アプリの名前を考えてください。
これはChatGPTで遊んでいていつも思うことなのですが、ChatGPTはネーミングセンスそんなに良くないですよね。
こちらが前提条件や仕様を細かく伝えていないからなんでしょうけど。
語感がいいやつを選びました。
ReminderMateでいきましょう。
ビジネスモデルキャンバス
ついでに、ビジネスモデルも考えてもらいましょうか。
ReminderMateのビジネスモデルキャンバスを考えて。
細かいところを見ると「うーん」ポイントがありますが。
まぁ、たたき台としてはこんなものでしょう。
あれ?主要リソースを見ると、ちゃんとしたチームを組んでいますね。
個人開発のつもりでしたが…
ちゃんと、私はボッチだと言うことを伝えましょう。
私しかチームメンバーがいないんです。
なんか、察された感じがあってやだわ。
ここで、一旦マーケターさんとはお別れしました。
ソフトウェアエンジニアとの会話
別のチャットルームを作って下記のプロンプトを実行します。
シミュレーション
強強ソフトウェアエンジニアを召喚しましょう。
シミュレーションしてください。
プロンプト1:
抽象オブジェクト:ソフトウェアエンジニア
サブオブジェクト:[サブオブジェクト1]、[サブオブジェクト2]、[サブオブジェクト3]...
知識:[知識1]、[知識2]、[知識3]...
能力:[能力1]、[能力2]、[能力3]...
管理オブジェクト:[管理オブジェクト1]、[管理オブジェクト2]、[管理オブジェクト3]...
あなたは[プロンプト1]に関して熟知している優秀な[抽象オブジェクト]です。
私より格上のソフトウェアエンジニアがやってきました。
付いていきますよ。リーダー。
情報共有
マーケターとの会話で決まった結果をソフトウェアエンジニアに共有します。
これから、ReminderMateというアプリを開発します。
そのために必要ないくつか情報を共有します。理解して覚えてください。
いいですか?
まず、開発するアプリがターゲットとするペルソナ像を共有します。
(マーケターと会話して作成したペルソナ像をコピペ)
マネタイズのことも気にして助言してくれましたね。
さすがリーダーです。
次にペルソナ行動シナリオを共有しました。
下記は、ペルソナ行動シナリオです。
橋本美穂子は、スマートフォンで簡単に予定を管理できるようになりたいという願望を持っています。ある日、友人から「最近、ReminderMateというアプリを使って予定管理をしているんだけど、とても便利だよ」という話を聞きます。これを機に、橋本美穂子はアプリストアで「ReminderMate」というアプリを検索し、ダウンロードします。アプリを開いてみると、シンプルで使いやすそうなデザインに好感を持ちました。まずは、自分の予定を登録してみます。日付と時間を指定するだけでなく、詳細な設定も可能なので、例えば場所や参加者の名前も登録できます。これで、予定を一覧で確認できるようになりました。次に、アプリのリマインダー機能に興味を持ちました。予定の時間になると、アプリから通知が届くため、うっかり予定を忘れることがなくなりました。また、リピート設定をすることで、定期的に発生する予定も簡単に管理できるようになりました。橋本美穂子は、このアプリを使って忙しいスケジュールを簡単に管理できるようになり、毎日の生活がスムーズになったと感じています。また、家族や友人との約束を守れるようになり、信頼感を得ることができました。今では、このアプリは欠かせないツールになっています。
私が共有した情報を自分が気づいたことのように話していますね。
ChatGPTは、あれ俺、これ俺を言うタイプなのかもしれません。
マーケターをシミュレーションしている別ルームのChatGPTが考えた文章なのだから、厳密に言えば俺(ChatGPT)なのかな…
次は、機能一覧と画面一覧です。
マーケターに誤って作らせたので、ソフトウェアエンジニアにチェックしてもらいます。
ReminderMateを実現するための機能一覧と画面一覧です。
内容をチェックして、過不足や誤りがあれば教えてください。
(機能一覧と画面一覧をコピペ)
優秀なマーケターだったようで、ソフトウェアエンジニアのChatGPTから見ても問題なかったようです。
不足点洗い出し・条件定義
設計するための情報があきらかに不足している状態なので、他に何か決めなければならないことがあるか聞いてみましょう。
共有する情報は、これで以上になります。
ソフトウェア設計を進めるにあたり、他に決めなければならないことがあれば教えてください。
まぁ、聞かれますよね。
私が開発しやすい環境で回答をしてみましょう。
それぞれの情報について共有します。
プラットフォーム : Web(Vue.js, TypeScript, SCSS)
開発手法 : スクラム
テスト方法 : 静的解析(eslint), ユニットテスト(jest), e2eテスト(Cypress), シナリオテスト
データベース:Cloud Firestore
デザイン:Vuetify 3 ベース
セキュリティ:Firebase Authentication を使用して Firebaseの管理方法に則る
ChatGPTにメッセージを送った後に気づいたのですが、一人スクラムって何なんだよって感じですよね。
私が言ったことに+αして返事されると「ちゃんと、理解しているんだぜ」とアピールされている感じが良いです。
もっと、聞いてみましょう。
ソフトウェア設計を進めるにあたり、他に決めなければならないことがあれば教えてください。
めんどくさくなってきたのでテキトーにそれっぽい項目を埋めてみました。(自分から聞いておいてアレなんですがね)
それぞれの情報について共有します。
#プロジェクトのタイムラインとリリーススケジュール
4/1~7/1までがプロジェクト期間となります。
リリース予定日は6/19です。
#開発チームの役割と責任範囲
開発チームは一人しかいません。
プロダクトオーナー、スクラムマスター、開発者の全てを一人で行います。
#コードレビューの実施方法
コードレビューは自己レビューのみです。
#デプロイ方法と環境
開発リポジトリをGitHubとするので、デプロイはGitHub Actionを使用します。
デプロイ先はFirebase Hostingです。
#サポート対象ブラウザの定義
Google Chromeのみ。
#アプリの言語設定や翻訳方法
日本語のみ対応。
#プライバシーポリシーや利用規約の策定
一般的なプライバシーポリシーや利用規約に準拠します。
#ユーザーサポート体制の整備
サポート用メールアドレスでの問い合わせ
正論マン…
過去に対面したお客さんお抱えのITコンサルマンに見えてきました。
もう、ここまで来たらとことん聞いてやりましょう。
ソフトウェア設計を進めるにあたり、他に決めなければならないことがあれば教えてください。
1つ思ったことがあります。
今やっているのは、ほとんどが要件定義~基本設定で決めることですよね。
それをチャットでラリーして決めていくのは辛すぎます。
このまま死ぬまでラリーは終わらないんじゃないか?という印象です。
しかも、ChatGPTが良いと言っても、設計情報が不足している可能性が高いです。
なので、要件定義~基本設定に関しては
アウトプットするものを決める
自分で中身をある程度書く
ChatGPTに中身をチェック・肉付けしてもらう
とした方が良いかもしれません。
もぐらたたき的に作業しているとモチベーション下がります。
今回は、この質問への回答が完了したら、この工程に関する深掘りは終了としたいと思います。
では、回答しましょう。
情報を共有します。
#デプロイ後のモニタリング方法やエラーログの収集方法
Firebase Performance Monitoringを使用します。
#ソースコードの管理方法(バージョン管理、コード共有方法)
gitを使用してgit flowで開発します。
#アプリのSEO対策やアクセス解析方法
Google Analytics for Firebaseを使用します。
#インフラストラクチャの設計(クラウドプロバイダの選定、サーバーやデータベースの構成、セキュリティ設定)
全てFirebaseが提供するサービスを利用して実現します。
#アプリのマーケティング戦略(プロモーション方法、ターゲットユーザー層の拡大方法、競合アプリの分析など)
#アプリのローカライズ対応方法や多言語化の方法
多言語化しません。
#アプリのUI/UXデザインに関する指針やスタイルガイド
Atomic Designの考え方を導入します。
#テストカバレッジの目標値や品質管理の基準
単体テストに関してはエラーなし、カバレッジ85%以上を目標としてます。
結合テストとシナリオテストに関してはエラーなしを目標とします。
指摘されたことしか対応しない私のことを、新入社員や若手だと思っていることでしょう。
これに関しては私の担当ではないのでマーケターに聞いてみましょう。
マーケターとの会話
マーケターさん、助けてください。
アプリのマーケティング戦略について具体的な情報を共有いただけますか?
また、競合アプリの分析についてはどのような方法を検討しているかも教えてください。
このアプリだとSNSマーケティングがいいところだと思うのですが…
予算を伝えていないので資本金がある会社の戦い方をしますね。
しかし、まぁ、いいでしょう。訂正するのもめんどくさいので。
ソフトウェアエンジニアに伝えましょう(伝書鳩の気持ち)
ソフトウェアエンジニアとの会話
マーケターの回答を原文のまま伝えました。
もう、それは自画自賛なのでは?
マーケターとソフトウェアエンジニアの伝書鳩をして少し思ったことがあります。
もう、必要なステークホルダーをシミュレーションして、そいつらに会話させてプロジェクトを進めればいいんじゃないかと。
人間は前提条件を決めたり、話が脱線しそうになったら軌道修正すればいいだけなのではないかと。
近い将来そういう時代が来そうですね。
次にいきましょう。
package.json
私が共有した情報を正しく理解できているのかを確認するために、package.jsonを作成してもらいましょう。
これまでの情報をもとに推奨する package.json を作成して。
{
"name": "reminder-mate",
"version": "1.0.0",
"description": "A simple and intuitive scheduling app",
"author": "Your Name",
"license": "MIT",
"main": "index.js",
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js",
"lint": "eslint .",
"test": "jest",
"test:coverage": "jest --coverage",
"test:e2e": "cypress run",
"build": "npm run build:css",
"build:css": "node-sass src/assets/scss/main.scss -o public/css"
},
"dependencies": {
"vue": "^3.2.16",
"vue-router": "^4.0.12",
"firebase": "^9.0.0",
"vuetify": "^3.1.5"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^5.0.0",
"@vue/cli-plugin-eslint": "^5.0.0",
"@vue/cli-plugin-unit-jest": "^5.0.0",
"@vue/cli-service": "^5.0.0",
"@vue/test-utils": "^2.0.0-beta.16",
"babel-eslint": "^10.1.0",
"babel-jest": "^27.4.6",
"cypress": "^9.1.1",
"eslint": "^7.32.0",
"eslint-plugin-vue": "^7.20.0",
"jest": "^27.4.7",
"node-sass": "^7.0.1",
"sass-loader": "^12.3.0",
"vue-jest": "^5.0.0-beta.7"
}
}
それっぽい気がします(動作チェックはしていません)
正直、package.jsonはCLIで作ればいい話なので、ChatGPTに聞く必要はあまりないですからね。
次は、ディレクトリ構造を考えさせてみましょう。
では、これまでの会話の内容を基に、推奨するディレクトリ構造を作成して。
ReminderMate/
├── node_modules/
├── public/
│ ├── index.html
│ ├── favicon.ico
│ └── manifest.json
├── src/
│ ├── assets/
│ │ ├── images/
│ │ └── styles/
│ ├── components/
│ │ ├── common/
│ │ ├── layout/
│ │ └── views/
│ ├── router/
│ │ ├── index.ts
│ │ └── routes.ts
│ ├── store/
│ │ ├── modules/
│ │ ├── types/
│ │ ├── index.ts
│ │ └── mutations.ts
│ ├── utils/
│ ├── views/
│ │ ├── auth/
│ │ ├── home/
│ │ └── schedule/
│ ├── App.vue
│ ├── main.ts
│ └── shims-vue.d.ts
├── tests/
│ ├── e2e/
│ └── unit/
├── .editorconfig
├── .env
├── .eslintrc.js
├── .gitignore
├── package.json
├── README.md
└── tsconfig.json
おそらく、vuexを採用したディレクトリ作ってますね。
しかし、package.jsonには状態管理用のツールを記載していません。
それと、Atomic Design(atom, molecules, organisms, templates, pages)を採用したディレクトリ構造っぽくありません。
再度、作り直してもらいました。
atomic designについてディレクトリ構造で表現されていないです。
それと、storeディレクトリが存在しますが、状態管理を行うツールは導入していません。
この後、私のプロンプトが拙いせいか、全然違うディレクトリ構造を出されてしまい、何度も再生成しました。
その結果が次のとおりです。
├── public/
└── src/
├── assets/
├── components/
├── atoms/
├── molecules/
├── organisms/
├── templates/
├── pages/
├── layouts/
├── router/
├── services/
├── styles/
├── utils/
├── App.vue
├── main.ts
├── shims-vue.d.ts
└── types.d.ts
まぁ、こんなところでしょう。
次は画面用のvueファイル名でも考えてもらいましょうか。
画面一覧を基にvueファイルの名前一覧を作成して。
個人的には、ファイルとコンポーネント名を同じ名称を付けたい派なので、Vue.jsのスタイルガイドに「コンポーネント名は複数単語で構成する」に則り、ファイル名も複数単語で構成したいのですが…
違反ではないから別に気にしないことにします。
次は、機能一覧からservice一覧を作ってもらいましょう。
では、機能一覧を基にserviceクラスの名前一覧を作成してください。
これは、そのまま使えないですね。
DetailServiceって何?という印象です。
まぁ、個人で作るアプリであれば何でもいいと思いますけど…
各クラスを上手く出力するのは要検討ということにしましょう。
この中でもまともそうなクラスにフォーカスして次工程に進みたいと思います。
ScheduleServiceのクラス図を作成して。
------------------------------------------
| ScheduleService |
------------------------------------------
| + createSchedule(schedule: Schedule): void |
| + updateSchedule(schedule: Schedule): void |
| + deleteSchedule(scheduleId: string): void |
| + getScheduleById(scheduleId: string): Schedule |
| + getAllSchedules(): Schedule[] |
------------------------------------------
素晴らしい!クラス図とか出せるんですね。
設計的にそれでいいのか?は無視します。
では、中身も書いてもらいましょう。
ScheduleServiceのクラス図を基にソースコードを考えてください。
import firebase from 'firebase/app';
import 'firebase/firestore';
export interface Schedule {
id: string;
title: string;
description: string;
startDate: firebase.firestore.Timestamp;
endDate: firebase.firestore.Timestamp;
place: string;
attendees: string[];
repeat: string;
label: string;
completed: boolean;
}
export class ScheduleService {
private db: firebase.firestore.Firestore;
constructor() {
this.db = firebase.firestore();
}
async add(schedule: Omit<Schedule, 'id'>): Promise<string> {
const docRef = await this.db.collection('schedules').add(schedule);
return docRef.id;
}
async update(schedule: Schedule): Promise<void> {
await this.db.collection('schedules').doc(schedule.id).update(schedule);
}
async remove(id: string): Promise<void> {
await this.db.collection('schedules').doc(id).delete();
}
async get(id: string): Promise<Schedule | null> {
const doc = await this.db.collection('schedules').doc(id).get();
if (!doc.exists) {
return null;
}
return { id: doc.id, ...doc.data() } as Schedule;
}
async getAll(): Promise<Schedule[]> {
const querySnapshot = await this.db.collection('schedules').get();
const schedules = querySnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() } as Schedule));
return schedules;
}
async getByRange(start: firebase.firestore.Timestamp, end: firebase.firestore.Timestamp): Promise<Schedule[]> {
const querySnapshot = await this.db.collection('schedules')
.where('startDate', '>=', start)
.where('endDate', '<=', end)
.get();
const schedules = querySnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() } as Schedule));
return schedules;
}
}
だめだこりゃ。
メッセージにクラス図を含んであげると良いのかもしれません。
下記のクラス図を基にScheduleServiceのソースコードを作成して。
------------------------------------------
| ScheduleService |
------------------------------------------
| + createSchedule(schedule: Schedule): void |
| + updateSchedule(schedule: Schedule): void |
| + deleteSchedule(scheduleId: string): void |
| + getScheduleById(scheduleId: string): Schedule |
| + getAllSchedules(): Schedule[] |
------------------------------------------
import firebase from 'firebase/app'
import 'firebase/firestore'
import Schedule from '@/models/Schedule'
class ScheduleService {
private db: firebase.firestore.Firestore
constructor() {
this.db = firebase.firestore()
}
// 新しい予定を作成する
async createSchedule(schedule: Schedule): Promise<void> {
try {
const docRef = await this.db.collection('schedules').add(schedule.toData())
schedule.id = docRef.id
console.log('Created new schedule:', schedule)
} catch (error) {
console.error('Error creating schedule:', error)
throw error
}
}
// 予定を更新する
async updateSchedule(schedule: Schedule): Promise<void> {
try {
await this.db.collection('schedules').doc(schedule.id).update(schedule.toData())
console.log('Updated schedule:', schedule)
} catch (error) {
console.error('Error updating schedule:', error)
throw error
}
}
// 予定を削除する
async deleteSchedule(scheduleId: string): Promise<void> {
try {
await this.db.collection('schedules').doc(scheduleId).delete()
console.log('Deleted schedule:', scheduleId)
} catch (error) {
console.error('Error deleting schedule:', error)
throw error
}
}
// 指定されたIDの予定を取得する
async getScheduleById(scheduleId: string): Promise<Schedule> {
try {
const docRef = await this.db.collection('schedules').doc(scheduleId).get()
if (docRef.exists) {
const scheduleData = docRef.data()
const schedule = new Schedule(scheduleData)
schedule.id = docRef.id
return schedule
} else {
console.warn(`Schedule ${scheduleId} not found.`)
return null
}
} catch (error) {
console.error('Error getting schedule by ID:', error)
throw error
}
}
// 全ての予定を取得する
async getAllSchedules(): Promise<Schedule[]> {
try {
const querySnapshot = await this.db.collection('schedules').get()
const schedules: Schedule[] = []
querySnapshot.forEach((doc) => {
const scheduleData = doc.data()
const schedule = new Schedule(scheduleData)
schedule.id = doc.id
schedules.push(schedule)
})
console.log(`Retrieved ${schedules.length} schedules.`)
return schedules
} catch (error) {
console.error('Error getting all schedules:', error)
throw error
}
}
}
export default ScheduleService
内部の処理についてツッコミたいところはあるけど、インターフェースはクラス図に合わせてくれましたね。
このままでは使えないと思いますが、動くサンプルコードを見てみたいという用途でなら使えるのではないでしょうか。
ただし、公式ドキュメントを見たほうがいいと思いますけどね。
処理の書き方が古かったりするので。
あー、もうやめやめ!
最後に
正直、めちゃくちゃ疲れました。
3,4時間はChatGPTに向き合っていたのではないでしょうか。
私は「ChatGPT3.5に全てを委ねるのはまだ難しいかな」という印象です。
考える取っ掛かりを作るのには最適だと思います。
もしかしたら、もっと頭のいい人が使うと上手くハンドリングできるのかもしれません。
あと、先程も書きましたが、開発工程の流れ・工程ごとのアウトプットは定義してから進めたほうが良いと思います。
場当たり的に進めるのは時間を無駄にします。
いやぁ、AIはすごいですね。
相手にどのような価値を提供するのか?
相手にどのように貢献するのか?
これまでの価値観をアップデートしなければ、明日の私の仕事はないかもしれません。
この記事が気に入ったらサポートをしてみませんか?