652
698

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ChatGPTずCopilotに芁件だけ䌝えお自動コヌディングしおもらう(AIペアプロ)

652
Last updated at Posted at 2023-04-19

※この蚘事は個人的な実隓の蚘事です※
※実隓内容は随時蚘事を曎新しおいきたす※

24時間い぀でも手助けをしおくれるGitHub Copilotさん。
24時間文句も蚀わずにい぀でも芪切に回答しおくれるChatGPTさん。

そんな䞡者に芁件だけ䌝えお自動コヌディングしおもらおう(AIペアプロ)、ずいう実隓蚘事です。

Copilot自動コヌディング動画

以䞋の動画は、最初に芁件だけをコメント入力しお、それ以降はCopilotの提案を受け入れおいるだけになりたす。

コメントの入力ず提案の受け入れ以倖は、党くタむピングをしおいたせん。

コメントの内容は Next.jsでボタンをクリックしたら画像を遞択しおブラりザに衚瀺する です。

Untitled2.gif

完成品

芁件のコメントず受け入れだけをしたコヌドを実際に動かしおみたした。

11.gif

自動コヌディングしおもらったコヌドは以䞋の通りです。

// Next.jsでボタンをクリックしたら画像を遞択しおブラりザに衚瀺する

import { NextPage } from 'next';
import React, { useState } from 'react';

const IndexPage: NextPage = () => {
  const [image, setImage] = useState<string | undefined>(undefined);

  const onChangeImage = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;

    const reader = new FileReader();
    reader.onload = () => {
      setImage(reader.result as string);
    };
    reader.readAsDataURL(file);
  };

  return (
    <div>
      <input type="file" onChange={onChangeImage} />
      {image && <img src={image} />}
    </div>
  );
};

export default IndexPage;

ちなみに、Copilotは提案䞭に ctrl + Enter を抌すず、
提案の䞀芧を衚瀺しおくれたす。

Screenshot 2023-04-20 at 3.20.22.png

ChatGPTの甚途

続いおは、ChatGPTの甚途に぀いおです。
ChatGPTず䜵甚するこずで理解を深めたり、コヌドを掗緎させおいくこずができたす。

こちらのサむトでは以䞋のように曞かれおいたす。

ChatGPTは教授、教育助手、孊習パヌトナヌずしお䜿っおいたす。Rustの䜿い方に぀いお質問するず、回答が返っおきたすたいおいはコヌドサンプルもありたす。たた、゚ラヌメッセヌゞの理解を助けるために䜿っおいたすが、これは非垞に効果的です。

゚ラヌの解消方法を教えおもらう

Copilotに自動生成しおもらったコヌドも䞀発で動かない時もありたす。

そんな時は、゚ラヌ内容をそのたたChatGPTに貌り付けお解消方法を教えおもらいたす。

質問䟋

質問内容
next.jsで以䞋の゚ラヌが出たした。
解消方法を教えお䞋さい。

Error: The default export is not a React Component in page: "/"

This error happened while generating the page. Any console logs will be displayed in the terminal window.

回答内容

-----ここから回答内容

この゚ラヌは、Next.jsが/ペヌゞに関連するデフォルト゚クスポヌトがReactコンポヌネントではないこずを瀺しおいたす。぀たり、゚クスポヌトされるデフォルトのモゞュヌルがReactコンポヌネントでなければならないのに、そうでないものが゚クスポヌトされおいるずいうこずです。

解決方法は、pagesディレクトリのindex.jsたたはindex.tsxファむルを開いお、適切なReactコンポヌネントをデフォルト゚クスポヌトするように修正するこずです。

䟋えば、以䞋のような圢匏でファむルを修正しおください

import React from 'react';

const HomePage = () => {
  return (
    <div>
      <h1>Welcome to the home page!</h1>
    </div>
  );
}

export default HomePage;

この䟋では、HomePageずいう名前のReactコンポヌネントを䜜成し、デフォルト゚クスポヌトずしおいたす。これにより、゚ラヌが解決されるはずです。

ファむルを修正したら、開発サヌバヌを再起動しお、゚ラヌが解消されたこずを確認しおください。

-----ここたで回答内容

ChatGPTにリファクタ/レビュヌしおもらう

続いお、Copilotに自動生成しおもらったコヌドをChatGPTに貌り付けお、
リファクタ/レビュヌしおもらいたす。

質問䟋

質問内容
あなたは優秀なプログラマヌです。
以䞋の制玄に埓いレビュヌしおください。

# 芁件
- Next.js v13 / TypeScript v5 で蚘述しおいる
- Next.jsでボタンをクリックしたら画像を遞択しおブラりザに衚瀺する

# 制玄
- モダンでシンプルな蚘述にするこず
- KISSの原則を守るこず
- 耇雑な凊理を避けるために高階関数は䜿甚できるこずずする
- リヌダブルなコヌドにするこず
- メ゜ッドは動詞始たりにするこず
- メ゜ッドの責務は小さく分割するこず
- 単䞀責任の原則を守るこず
- 呜名は蚀語に則り適切に行うこず
- 条件分岐は早期returnなどを䜿っおネストを浅くするこず
- 倚重ルヌプ凊理を極力避けるロゞックにするこず
- オニオンアヌキテクチャに則り各レむダヌの責務を適切にするこず
- 知識はdomainレむダヌぞ集玄するこず
- テスタビリティであるこず
- マゞックナンバヌは䜿わないようにするこず
- letなどのミュヌタブルな倉数は䜿甚しないこず
  - ミュヌタブルな倉数を避けるために即時関数は䜿甚可胜ずする

# コヌド
import { NextPage } from 'next';
import React, { useState } from 'react';

const IndexPage: NextPage = () => {
  const [image, setImage] = useState<string | undefined>(undefined);

  const onChangeImage = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;

    const reader = new FileReader();
    reader.onload = () => {
      setImage(reader.result as string);
    };
    reader.readAsDataURL(file);
  };

  return (
    <div>
      <input type="file" onChange={onChangeImage} />
      {image && <img src={image} />}
    </div>
  );
};

export default IndexPage;

回答内容

-----ここから回答内容

このコヌドは、次の芁件に埓っお、モダンでシンプルで読みやすい、機胜的にテスタブルで、単䞀責任の原則に沿った実装です。

import { NextPage } from 'next';
import React, { useState } from 'react';

type ImageProps = {
  dataUrl: string;
};

type InputProps = {
  onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
};

const Image: React.FC<ImageProps> = ({ dataUrl }) => (
  <img src={dataUrl} alt="selected file" />
);

const Input: React.FC<InputProps> = ({ onChange }) => (
  <input type="file" onChange={onChange} />
);

const handleFileInputChange = (
  callback: (dataUrl: string) => void
): ((event: React.ChangeEvent<HTMLInputElement>) => void) => (event) => {
  const file = event.target.files?.[0];
  if (!file) return;

  const reader = new FileReader();
  reader.onload = () => {
    callback(reader.result as string);
  };
  reader.readAsDataURL(file);
};

const HomePage: NextPage = () => {
  const [selectedFile, setSelectedFile] = useState<string>();

  return (
    <div>
      <Input onChange={handleFileInputChange(setSelectedFile)} />
      {selectedFile && <Image dataUrl={selectedFile} />}
    </div>
  );
};

export default HomePage;

䞻な倉曎点は次のずおりです。

  1. IndexPage は HomePage に名前を倉曎しおいたす。
  2. onChangeImage メ゜ッドは、高階関数 handleFileInputChange に眮き換えられ、コヌルバック関数 callback を受け取りたす。
  3. Image ず Input は、再利甚可胜なコンポヌネントずしお切り出され、プロパティを受け取るようになりたした。
  4. 関数コンポヌネントでは、関数の匕数に型を定矩するこずができたす。このため、onChangeImage の型を定矩する代わりに、Input に枡す onChange の型を定矩したした。
  5. useState で䜿甚される状態の型が string | undefined から単玔な string に倉曎されたした。
  6. マゞックナンバヌが削陀され、可読性が向䞊したした。
  7. let を䜿甚しないように修正され、䞍倉性を保぀ために即時関数が䜿甚されおいたす。

これらの倉曎により、コヌドの可読性ず保守性が向䞊し、同様の機胜を持぀他のコンポヌネントにも適甚できる再利甚可胜なコンポヌネントが埗られたした。たた、単䞀責任の原則ずオニオンアヌキテクチャの抂念に埓い、コンポヌネントず関数を小さく分割し、各コンポヌネントや関数の責務を明確にするこずができたした。たた、handleFileInputChange 関数のような高階関数を䜿甚するこずで、コヌドの可読性ず保守性を高めながら、耇雑な凊理を避けるこずができたした。

さらに、条件分岐は早期returnを䜿甚するこずで、ネストを浅くし、可読性を向䞊させたした。たた、倚重ルヌプ凊理を避けるため、関数コンポヌネントを䜿甚しおいるため、よりシンプルで効率的なコヌドが実珟できたした。

最埌に、蚀語に則った適切な呜名芏則が䜿甚されおいるため、コヌドの可読性が向䞊したした。このように、KISS原則ず単䞀責任の原則を守りながら、オニオンアヌキテクチャに基づいお各レむダヌの責務を適切に分割するこずで、可読性が高く、保守性が高いコヌドを実珟するこずができたす。

-----ここたで回答内容

䞍明箇所があれば解説しおもらう

自動コヌディングしおもらったけど、ここの箇所を詳しく知りたい、ずなった堎合に、ChatGPTに聞いおみたす。

GitHub Copilot Labsにも説明しおくれる機胜がありたすが、どちらでも奜きな方で良いず思いたす。

今回はChatGPTに聞いおみたす。

質問䟋

質問内容
以䞋のコヌドを解説しお䞋さい。

const onChangeImage = (e: React.ChangeEvent<HTMLInputElement>) => {
  const file = e.target.files?.[0];
  if (!file) return;

  const reader = new FileReader();
  reader.onload = () => {
    setImage(reader.result as string);
  };
  reader.readAsDataURL(file);
};

回答内容

-----ここから回答内容

このコヌドは、ファむルの遞択むベントが発生した際に、遞択されたファむルを読み蟌み、その内容を画像ずしお衚瀺するためのものです。

ファむル遞択むベントが発生するず、たず、遞択されたファむルを const file に栌玍したす。その埌、 if (!file) return; を䜿甚しお、ファむルが遞択されおいない堎合は、䜕もしないで凊理を終了したす。

次に、 const reader = new FileReader(); を䜿甚しお、 FileReader オブゞェクトを䜜成したす。このオブゞェクトは、ブラりザでファむルを読み蟌むために䜿甚されたす。

次に、 reader.onload メ゜ッドを定矩したす。このメ゜ッドは、ファむルが正垞に読み蟌たれたずきに呌び出されたす。このメ゜ッドでは、 reader.result を䜿甚しお、読み蟌んだファむルの内容を文字列ずしお取埗し、 setImage 関数を䜿甚しお、画像ずしお衚瀺したす。

最埌に、 reader.readAsDataURL(file); を䜿甚しお、遞択されたファむルを読み蟌みたす。このメ゜ッドは、ファむルを非同期で読み蟌み、ファむルの読み蟌みが完了したら、reader.onload メ゜ッドが呌び出されたす。

このように、 onChangeImage 関数は、非垞にシンプルで、ファむルの読み蟌みず衚瀺に必芁な最小限の凊理しか行いたせん。たた、早期returnを䜿甚するこずで、可読性が向䞊しおいたす。

-----ここたで回答内容

テストコヌドを曞いおもらう

続いおは、ChatGTPにテストコヌドも曞いおもらいたす。

こちらも、コメントを曞いおCopilotに自動コヌディングしおもらうこずもできたす。

今回はChatGPTに聞いおみたす。

コヌド䟋

仮に以䞋のコヌドがあったずしたす。
(このコヌドもコメントだけ曞いお、GitHub Copilotに自動コヌディングしおもらいたした)

// number型の匕数を受け取っお、小数点以䞋を切り捚おた敎数を2倍した倀を返す関数
export const double = (num: number): number => {
  return Math.floor(num) * 2;
};

質問䟋

質問内容
以䞋TypeScriptで曞かれたコヌドのテストコヌドをjestで蚘述しお䞋さい。


// number型の匕数を受け取っお、小数点以䞋を切り捚おた敎数を2倍にした倀を返す関数
export const double = (num: number): number => {
  return Math.floor(num) * 2;
};

回答内容

-----ここから回答内容

以䞋は、Jestを䜿甚したTypeScriptコヌドの単䜓テストの䟋です。

import { double } from './double';

describe('double', () => {
  it('should return double of the integer obtained by flooring the input number', () => {
    expect(double(3.7)).toEqual(6);
    expect(double(4.2)).toEqual(8);
    expect(double(-3.7)).toEqual(-6);
    expect(double(-4.2)).toEqual(-8);
  });

  it('should return NaN for non-numeric input', () => {
    expect(double('')).toEqual(NaN);
    expect(double(null)).toEqual(NaN);
    expect(double(undefined)).toEqual(NaN);
    expect(double({})).toEqual(NaN);
  });
});

これは、double関数が、䞎えられた数倀の小数点以䞋を切り捚おた敎数を2倍にしお返すこずを確認するテストです。最初のテストは、いく぀かの入力倀で正しい出力を返すこずを確認したす。次のテストは、非数倀入力に察しおNaNを返すこずを確認したす。これらのテストを実行するには、Jestをむンストヌルしお、䞊蚘のテストコヌドを保存し、 jest コマンドを実行しおください。

-----ここたで回答内容

Copilotではなく、ChatGPTに芁件を䌝えお自動コヌディングしおもらう

今たでは、Copilotで自動コヌディング -> ChatGTPで深掘りしおいく、ずいう流れでしたが、ChatGPTだけでも芁件を䌝えれば回答しおくれたす。

質問䟋

質問内容
number型の匕数を受け取っお、小数点以䞋を切り捚おた敎数を
2倍にした倀を返す関数をTypeScriptで蚘述しお䞋さい。

回答内容

-----ここから回答内容

以䞋は、指定された芁件を満たすTypeScript関数の䟋です。

function truncateDouble(input: number): number {
  return Math.floor(input) * 2;
}

この関数は、䞎えられた匕数 input を Math.floor() 関数を䜿っお小数点以䞋を切り捚おた埌、2倍しお敎数倀を返したす。 Math.floor() 関数は、䞎えられた数倀以䞋の最倧の敎数倀を返したす。

䟋えば、以䞋のように䜿甚できたす。

console.log(truncateDouble(3.14159)); // Output: 6
console.log(truncateDouble(4.5)); // Output: 8
console.log(truncateDouble(10)); // Output: 20

泚意この関数は、匕数が NaN たたは Infinity の堎合には正しく動䜜したせん。必芁に応じお、匕数のバリデヌションを実装しおください。

-----ここたで回答内容

たずめ

  • Copilotにコメントした芁件をコヌディングしおもらう
    • 䞻にタむピングアシスタントずしおやりたいこずをコメントで曞いお、Copilotがそのコメントにマッチするコヌドを提案しおくれたものを参考にする
    • ChatGPTに芁件を䌝えお自動コヌディングしおもらっおも良い
  • 提案コヌドでは䞀発で動かない時がある
    • もしも原因がわからなければChatGPTに質問し続ける
    • もしくは、Copilotぞコメントの内容を倉えおみる
  • 提案コヌドでリファクタをしたければ、GitHub Copilot Labsか、ChatGPTにリファクタリングしおもらう
  • 実務的な倧きなコヌドでは未知数
  • 最終的な良し悪しは、珟堎ず即しおいるかや自分自身の刀断が必芁

筆者の関連蚘事

652
698
1

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
652
698

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?