5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AI に聞き方のコツがわかってから、開発が楽になった話

5
Posted at

先週、あるプロジェクトで「なぜか 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 からもっかい回答をもらえるかもしれませんし、自分でも問題の解決が速くなるでしょう。質問のコツを身につけた今、新しいチャレンジも怖くありません。

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?