先週、あるプロジェクトで「なぜか API が 5 秒もかかってするり続けているんですけど、どこがおかしいのでしょうか?」と、Slack に投げたところ、数分で解決してくれた相手からこんな一言をいただきました。
「自分のコードを見てるだけではなく、クライアント側のネットワークタブでリクエストを確認してみてください。キャッシュされたレスポンスが返っているかもしれません」
そういえば、それまでは AI に質問するとき、「〜してみたらうまくいかないんですけど」と相談するようにしていました。するとよく聞くのは「詳細を教えてください」や「コードを見せてください」という答え。がっかりするばかりではなく、「自分の書き方が悪いのかな」と考えることもしばしきありました。
はじめて AI に質問した時の戸惑い
最初に AI に質問をすることになったの、実は去年の 4 月でした。ある日、React の state が更新されないという問題に直面して、「React の state 更新しない」と素直に質問してみたのです。すると返ってきたのは「state を正しく更新してください」という、まるで「はい」という返答のようなものでした。
それは確かに正しい答えではあったのですが、「正しく」とはどういうことか、具体的にどうやってすればいいのか、全然教えてくれませんでした。その後、いくつか似たような質問をしてみて、だいたい同じパターンでした。「うまくいかない」「なぜか動かない」といった相談には、「詳細を教えてください」「コードを見せてください」という答えが返ってくるだけ。
最初、自分は「自分の書き方がまずいのかな」と考えましたし、「もっと賢い書き方をするべきだな」と落ち込みました。確かに質問文が荒っうっている気がしましたし、コードも gist にアップしてリンクを送るほどの熟練には足りませんでした。
しかし、ある日その問題を解決するまでに至ったのです。単紘に「なぜうまくいかないか」だけでなく、「こういうコードを書いている」「こんなエラーメッセージが出ている」「自分で試したこと」「期待している結果」を全部書いてみたのです。
✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨
スイカゲームとにゃんこ大戦争のようなタワーディフェンス系ゲームを組み合わせたゲームを作成しました!
遊んでみていただけると嬉しいです🙇♂️
ハジメル.dev: https://hajimeru-dev.vercel.app/
「ひとりで続けるのは難しい」「何から学べばいいか分からない」という方向けに、
プログラミングのマンツーマンレッスンサービス「ハジメル.dev」も運営しています。
未経験OK・オンライン完結・月額制/違約金なしなので、気軽に無料相談してみてください🙇♂️
海外テックニュースを追いたいけど、英語や情報量の多さで大変…という方向けに、
Hacker News の話題を日本語でサクッと追える「HackerNews 日本語まとめ & AI要約」
を個人開発しました!
技術トレンド収集に使ってもらえると嬉しいです🔥🙇♂️
→ HackerNews 日本語まとめ & AI要約: https://hn-matome-2ht.pages.dev/
「ニャンパイアサバイバー」というヴァンパイアサバイバーリスペクトのゲームを作成しました!
もしよろしければ遊んで頂けると嬉しいです😭
習い事教室の先生向けに、SNS 投稿・生徒募集・保護者通知の文章を AI で生成する Web サービス「おしらせAI」を個人開発しました。Next.js + Supabase + LLM で構成しており、無料で月 10 回まで試用できます。よければ触ってみてください。
→ おしらせAI: https://oshirase-ai.vercel.app/
✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨
質問を充実させ始めて得られた驚き
その質問を送った後、驚くべきことが起きました。AI からは単なる「直してください」という答えではなく、「ここの書き方が問題です」「こうするとうまくいきます」という、具体的な手直しの手順まで教えていただけたのです。
例えば、ある日「useContext で値が伝わらない」という問題に直面しました。そんな時、今までなら「 useContext がうまくいかない」と質問していたでしょう。しかし、今は次のように書きました。
import React, { createContext, useContext } from 'react';
const MyContext = createContext();
export function MyComponent() {
const value = useContext(MyContext);
console.log('context value:', value);
return <div>{value}</div>;
}
// 親コンポーネント
export function App() {
return (
<MyContext.Provider value="テスト">
<MyComponent />
</MyContext.Provider>
);
}
書いているうちに、「Provider の value が文字列「テスト」になっているから、伝わらないのでは?」と気づきました。しかし、質問をしたところ、「Provider の value として文字列を渡すのは正しいですね。ただ、コンソールログを見ると、value が undefined になっているようです。おそらく、コンポーネントの再レンダリングが原因です」という指摘をいただきました。
その後、コンソールログを詳しく見てみると、再レンダリングが原因で value が undefined になることがわかりました。「なぜ再レンダリングが原因なのか」まで教えていただいたので、その仕組みを理解するまでになりました。
コードを添えることの重要性
質問をするときにコードを添えること、後になって考えるととても重要だったなあと感じます。なぜなら、コードがあることで AI は自分の考察のベースを持つからです。
ある事例をご紹介します。あるプロジェクトで API からデータを取得して表示するコンポーネントを作っていた時、「データが表示されない」という問題がありました。最初は「なぜか表示されない」と簡潔に質問してみたのですが、「詳細を教えてください」というしかしょうがない回答しか得られませんでした。
でも、コードを添えて「こう書いているんですが、data が空の配列になっているんですよね」と質問するようにしました。そうすると、「fetch が非同期だから、データが取得される前に render が実行されている」という指摘をいただきました。
function UserList() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch('/api/users')
.then(res => res.json())
.then(data => {
console.log('取得したデータ:', data);
setUsers(data);
});
}, []);
console.log('現在の users:', users);
return (
<div>
{users.map(user => (
<div key={user.id}>{user.name}</div>
))}
</div>
);
}
このコードを見ると、問題は明らかですよね。fetch が非同期なので、console.log で表示される users は空配列のままの場合もあるからです。でも、その気づきが自分ではなかったので、AI に聞いたら「state の初期値を配列以外にしてみては?」という回答が返ってきたかもしれません。
エラーメッセージも全部書く癖
次に覚えたのは、エラーメッセージを全部書くことでした。ある日、Next.js のサーバーサイドレンダリングで「Cannot read property 'map' of undefined」というエラーがでていまして、最初は「map エラー」と書いていました。
すると、「map は配列でしか使えません」という、まるで obvious な答えが返ってきました。でも、そのエラーの背景には、サーバーサイドでデータが取得できず、undefined が返ってきているという問題がありました。
今なら、次のように書きます。
エラーメッセージ:
TypeError: Cannot read property 'map' of undefined
発生しているコード:
export async function getServerSideProps() {
const res = await fetch('https://api.example.com/users');
const users = await res.json();
console.log('サーバーで取得した users:', users);
return {
props: { users },
};
}
function UserList({ users }) {
return (
<div>
{users.map(user => (
<div key={user.id}>{user.name}</div>
))}
</div>
);
}
すると、「res.json() の前に res.ok をチェックしてみてください」「API のレスポンス構造が異なっているかもしれません」という、具体的なアドバイスをいただけます。
エラーメッセージだけでなく、発生しているコードのコンテキストも書くようにしました。すると、AI は単なる構文のエラーだけでなく、「API からのレスポンスが期待通りでない」「サーバーサイドでのデータ取得に失敗している」など、深層的な問題にも気づいてくれるようになったのです。
期待する結果を明示すること
最後に覚えたのは、期待する結果を明示することでした。「うまくいきたい」「なぜか動かない」と書いていても、AI は「動くように」するための手がかりを探し始めます。しかし、「こういう結果が欲しい」「こういう挙動が理想」と書けば、AI はそのゴールに向かっての提案をしてくれるようになります。
例えば、ある日「フォームのバリデーションをしたい」と考えていました。最初は「バリデーション」と書くだけでしたが、返ってきたのは「ライブラリを使ってください」という回答。ライブラリは確かにいいのですが、「自分で実装したい」という希望が伝わりませんでした。
なので、次は「自作のバリデーションを実装したい」「エラーメッセージを表示したい」「送信ボタンはバリデーションが通 Through の時だけ有効化したい」と書きました。
function MyForm() {
const [values, setValues] = useState({ email: '', password: '' });
const [errors, setErrors] = useState({});
const [isSubmitted, setIsSubmitted] = useState(false);
const validate = () => {
const newErrors = {};
if (!values.email.includes('@')) {
newErrors.email = '有効なメールアドレスを入力してください';
}
if (values.password.length < 8) {
newErrors.password = '8文字以上で入力してください';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleSubmit = (e) => {
e.preventDefault();
if (validate()) {
setIsSubmitted(true);
console.log('送信成功:', values);
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={values.email}
onChange={(e) => setValues({...values, email: e.target.value})}
/>
{errors.email && <span>{errors.email}</span>}
<input
type="password"
value={values.password}
onChange={(e) => setValues({...values, password: e.target.value})}
/>
{errors.password && <span>{errors.password}</span>}
<button type="submit" disabled={isSubmitted}>
送信
</button>
</form>
);
}
すると、「state の管理方法は良いですが、validate 関数の中で errors を直接更新しているので、無限ループに注意してください」「isSubmitted の使い方が少し気になります」といった、細かな指摘をいただけました。
それでどう開発が楽になったか
質問の仕方を少しでも整えるようになってから、開発が本当に楽になりました。まず、答えをもらうまでの時間が短縮されました。「詳細を教えてください」という往復がなくなったからです。
次に、自分の理解が深まりました。単なる「直してください」ではなく、「こうするとうまくいきます」という手順を教えてもらえるので、その手順にしたがっているうちに、なぜその方法が正しいのかを自分で学べるようになったのです。
それまでは「なぜか動かない」という問題にぶつかるたび、いろんなサイトを飛んで「どうやらこれが原因っぽい」と当たりあたりを繰り返していました。しかし、AI に正しく質問するようになると、その問題の本質を教えてもらえるようになりました。
最後に、周りからの信頼も増まりました。「自分で問題を整理して質問する姿勢が素晴らしい」と、同僚からそんなコメントをいただきました。確かに、質問するまえに自分でコードを見直したり、エラーを調べたりする習慣がついているからです。
まとめ
AI に質問するのも、一つの技術だと最近気づきました。質問の仕方を少しでも整えるようにしたことで、開発が格段に楽になりました。コードを添える、エラーメッセージを全部書く、期待する結果を明示する、そして自分で試したことを書く。これらの習慣が、単なる相談以上の価値を返してくれるようになったのです。
これからも、質問する前に一度自分のコードやエラーを見直す習慣をつけていこうと思います。そうすると、たぶん、AI からもっかい回答をもらえるかもしれませんし、自分でも問題の解決が速くなるでしょう。質問のコツを身につけた今、新しいチャレンジも怖くありません。
タイトル: AI に聞き方のコツがわかってから、開発が楽になった話
本文:
先週、あるプロジェクトで「なぜか API が 5 秒もかかってするり続けているんですけど、どこがおかしいのでしょうか?」と、Slack に投げたところ、数分で解決してくれた相手からこんな一言をいただきました。
「自分のコードを見てるだけではなく、クライアント側のネットワークタブでリクエストを確認してみてください。キャッシュされたレスポンスが返っているかもしれません」
そういえば、それまでは AI に質問するとき、「〜してみたらうまくいかないんですけど」と相談するようにしていました。するとよく聞くのは「詳細を教えてください」や「コードを見せてください」という答え。がっかりするばかりではなく、「自分の書き方が悪いのかな」と考えることもしばしきありました。
はじめて AI に質問した時の戸惑い
最初に AI に質問をすることになったの、実は去年の 4 月でした。ある日、React の state が更新されないという問題に直面して、「React の state 更新しない」と素直に質問してみたのです。すると返ってきたのは「state を正しく更新してください」という、まるで「はい」という返答のようなものでした。
それは確かに正しい答えではあったのですが、「正しく」とはどういうことか、具体的にどうやってすればいいのか、全然教えてくれませんでした。その後、いくつか似たような質問をしてみて、だいたい同じパターンでした。「うまくいかない」「なぜか動かない」といった相談には、「詳細を教えてください」「コードを見せてください」という答えが返ってくるだけ。
最初、自分は「自分の書き方がまずいのかな」と考えましたし、「もっと賢い書き方をするべきだな」と落ち込みました。確かに質問文が荒っうっている気がしましたし、コードも gist にアップしてリンクを送るほどの熟練には足りませんでした。
しかし、ある日その問題を解決するまでに至ったのです。単純に「なぜうまくいかないか」だけでなく、「こういうコードを書いている」「こんなエラーメッセージが出ている」「自分で試したこと」「期待している結果」を全部書いてみたのです。
質問を充実させ始めて得られた驚き
その質問を送った後、驚くべきことが起きました。AI からは単なる「直してください」という答えではなく、「ここの書き方が問題です」「こうするとうまくいきます」という、具体的な手直しの手順まで教えていただけたのです。
例えば、ある日「useContext で値が伝わらない」という問題に直面しました。そんな時、今までなら「 useContext がうまくいかない」と質問していたでしょう。しかし、今は次のように書きました。
import React, { createContext, useContext } from 'react';
const MyContext = createContext();
export function MyComponent() {
const value = useContext(MyContext);
console.log('context value:', value);
return <div>{value}</div>;
}
// 親コンポーネント
export function App() {
return (
<MyContext.Provider value="テスト">
<MyComponent />
</MyContext.Provider>
);
}
書いているうちに、「Provider の value が文字列「テスト」になっているから、伝わらないのでは?」と気づきました。しかし、質問をしたところ、「Provider の value として文字列を渡すのは正しいですね。ただ、コンソールログを見ると、value が undefined になっているようです。おそらく、コンポーネントの再レンダリングが原因です」という指摘をいただきました。
その後、コンソールログを詳しく見てみると、再レンダリングが原因で value が undefined になることがわかりました。「なぜ再レンダリングが原因なのか」まで教えていただいたので、その仕組みを理解するまでになりました。
コードを添えることの重要性
質問をするときにコードを添えること、後になって考えるととても重要だったなあと感じます。なぜなら、コードがあることで AI は自分の考察のベースを持つからです。
ある事例をご紹介します。あるプロジェクトで API からデータを取得して表示するコンポーネントを作っていた時、「データが表示されない」という問題がありました。最初は「なぜか表示されない」と簡潔に質問してみたのですが、「詳細を教えてください」というしかしょうがない回答しか得られませんでした。
でも、コードを添えて「こう書いているんですが、data が空の配列になっているんですよね」と質問するようにしました。すると、「fetch が非同期だから、データが取得される前に render が実行されている」という指摘をいただきました。
function UserList() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch('/api/users')
.then(res => res.json())
.then(data => {
console.log('取得したデータ:', data);
setUsers(data);
});
}, []);
console.log('現在の users:', users);
return (
<div>
{users.map(user => (
<div key={user.id}>{user.name}</div>
))}
</div>
);
}
このコードを見ると、問題は明らかですよね。fetch が非同期なので、console.log で表示される users は空配列のままの場合もあるからです。でも、その気づきが自分ではなかったので、AI に聞いたら「state の初期値を配列以外にしてみては?」という回答が返ってきたかもしれません。
エラーメッセージも全部書く癖
次に覚えたのは、エラーメッセージを全部書くことでした。ある日、Next.js のサーバーサイドレンダリングで「Cannot read property 'map' of undefined」というエラーがでていまして、最初は「map エラー」と書いていました。
すると、「map は配列でしか使えません」という、まるで obvious な答えが返ってきました。でも、そのエラーの背景には、サーバーサイドでデータが取得できず、undefined が返ってきているという問題がありました。
今なら、次のように書きます。
エラーメッセージ:
TypeError: Cannot read property 'map' of undefined
発生しているコード:
export async function getServerSideProps() {
const res = await fetch('https://api.example.com/users');
const users = await res.json();
console.log('サーバーで取得した users:', users);
return {
props: { users },
};
}
function UserList({ users }) {
return (
<div>
{users.map(user => (
<div key={user.id}>{user.name}</div>
))}
</div>
);
}
すると、「res.json() の前に res.ok をチェックしてみてください」「API のレスポンス構造が異なっているかもしれません」という、具体的なアドバイスをいただけます。
エラーメッセージだけでなく、発生しているコードのコンテキストも書くようにしました。すると、AI は単なる構文のエラーだけでなく、「API からのレスポンスが期待通りでない」「サーバーサイドでのデータ取得に失敗している」など、深層的な問題にも気づいてくれるようになりました。
期待する結果を明示すること
最後に覚えたのは、期待する結果を明示することでした。「うまくいきたい」「なぜか動かない」と書いていても、AI は「動くように」するための手がかりを探し始めます。しかし、「こういう結果が欲しい」「こういう挙動が理想」と書けば、AI はそのゴールに向かっての提案をしてくれるようになります。
例えば、ある日「フォームのバリデーションをしたい」と考えていました。最初は「バリデーション」と書だけでしたが、返ってきたのは「ライブラリを使ってください」という回答。ライブラリは確かにいいのですが、「自分で実装したい」という希望が伝わりませんでした。
なので、次は「自作のバリデーションを実装したい」「エラーメッセージを表示したい」「送信ボタンはバリデーションが通 Through の時だけ有効化したい」と書きました。
function MyForm() {
const [values, setValues] = useState({ email: '', password: '' });
const [errors, setErrors] = useState({});
const [isSubmitted, setIsSubmitted] = useState(false);
const validate = () => {
const newErrors = {};
if (!values.email.includes('@')) {
newErrors.email = '有効なメールアドレスを入力してください';
}
if (values.password.length < 8) {
newErrors.password = '8文字以上で入力してください';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleSubmit = (e) => {
e.preventDefault();
if (validate()) {
setIsSubmitted(true);
console.log('送信成功:', values);
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={values.email}
onChange={(e) => setValues({...values, email: e.target.value})}
/>
{errors.email && <span>{errors.email}</span>}
<input
type="password"
value={values.password}
onChange={(e) => setValues({...values, password: e.target.value})}
/>
{errors.password && <span>{errors.password}</span>}
<button type="submit" disabled={isSubmitted}>
送信
</button>
</form>
);
}
すると、「state の管理方法は良いですが、validate 関数の中で errors を直接更新しているので、無限ループに注意してください」「isSubmitted の使い方が少し気になります」といった、細かな指摘をいただけました。
それでどう開発が楽になったか
質問の仕方を少しでも整えるようにしたことで、開発が本当に楽になりました。まず、答えをもらうまでの時間が短縮されました。「詳細を教えてください」という往復がなくなったからです。
次に、自分の理解が深まりました。単なる「直してください」ではなく、「こうするとうまくいきます」という手順を教えてもらえるので、その手順にしたがっているうちに、なぜその方法が正しいのかを自分で学べるようになったのです。
それまでは「なぜか動かない」という問題にぶつかるたび、いろんなサイトを飛んで「どうやらこれが原因っぽい」と当たりあたりを繰り返していました。しかし、AI に正しく質問するようになると、その問題の本質を教えてもらえるようになりました。
最後に、周りからの信頼も増まりました。「自分で問題を整理して質問する姿勢が素晴らしい」と、同僚からそんなコメントをいただきました。確かに、質問するまえに自分でコードを見直したり、エラーを調べたりする習慣がついているからです。
まとめ
AI に質問するのも、一つの技術だと最近気づきました。質問の仕方を少しでも整えるようにしたことで、開発が格段に楽になりました。コードを添える、エラーメッセージを全部書く、期待する結果を明示する、そして自分で試したことを書く。これらの習慣が、単なる相談以上の価値を返してくれるようになったのです。
これからも、質問する前に一度自分のコードやエラーを見直す習慣をつけていこうと思います。そうすると、たぶん、AI からもっかい回答をもらえるかもしれませんし、自分でも問題の解決が速くなるでしょう。質問のコツを身につけた今、新しいチャレンジも怖くありません。