🫢

1文字もコードを書かずにChatGPTでwebフロントを実装できてしまった話

2023/07/24に公開

はじめに

この記事は、Next.jsのコードをChatGPTに書いてもらっていたらロジックからCSSまで全部完成してしまったという話を個人的な備忘録としてまとめたものです。
ChatGPTのアップデートおよび仕様変更によって将来的にこの手順が使用できなくなる可能性があります。(記.2023/7/24)

事の始まり

例によってこの記事もハッカソンの中の話になりますが,色々あってwebフロントが全部ボツになって一から作り直すことになり,寝る時間もなかったので頭も回らず作業効率がどんどん落ちていくという負のループに陥ったところでChatGPTに書いてもらうことを思いつきました.
実際にChatGPTに実装してもらったサイトはこんな感じで,CSSも全てChatGPTに書いてもらいました.本当に私は一文字もコードを書いていません.レポジトリはここで,GPT3.5での話になります.


ロジックを実装する場合

ChatGPTに指示を出す場合はその指示が具体的であればあるほど意図した通りの返答が返ってきます.すなわち,仕様の定義をしっかりしてあげる必要があります.
例えばCookieに保存したTokenを削除してトップページにリダイレクトするログアウトページを実装したい場合,実際に次のような指示を出していました.
next.jsを用いて,tokenという名前のcookieを消してトップページにリダイレクトする,コンテンツは何もないページlogout.tsxを生成してください.なお,cookie管理にはreact-cookieを使用しています.
そして実際にChatGPTから返ってきたコードはこちら.

import React, { useEffect } from 'react';
import { useRouter } from 'next/router';
import { useCookies } from 'react-cookie';

const LogoutPage: React.FC = () => {
  const router = useRouter();
  const [, , removeCookie] = useCookies(['token']);

  useEffect(() => {
    // コンポーネントがマウントされたときに実行される処理
    // tokenという名前のcookieを削除してトップページにリダイレクトする
    removeCookie('token');
    router.push('/');
  }, [removeCookie, router]);

  return null; // 何も表示しないため、nullを返す
};

export default LogoutPage;

ChatGPTの返答にはどうしてもブレがあるため,場合によっては意図したものと若干異なるものが返ってくることもあります.そのような時は
ページ遷移にはReact RouterではなくNext Routerを使用してください
のような具体的な指示をそのままチャットの続きに入力すれば修正してくれました.もっと複雑なロジック,例えばAPIを叩いてその値を利用する場合などは,
全てのページの読み込み時にtokenを取得してエンドポイント/authにGETリクエストを投げ,200番が返ってきた場合はisLoggedInをtrueに,失敗した場合はfalseに変更したいです.
のようにエンドポイントを指定したり,
/authへのGETリクエストは200番の場合,{"id": 1,"is_admin": true}というbodyが返ってきます.isAdminとuserIdのコンテキストもこの値に揃えたいです.
のようにレスポンスの型を実際に示してあげるとちゃんと動くコードを書いてくれると思います.
あとは意図した仕様の通りになるまで指示を繰り返せばロジック部分は完成します.

装飾を実装する場合

装飾(CSS)を実装する場合も基本的にはロジックと同じですが,デザインについては具体的なイメージが固まっていなければある程度適当な指示で大丈夫です.
以下はハッカソン中デザインが固まってなかったのでとりあえず出してみた指示です.
このHeader.tsxをstyled-componentsを用いていい感じにしてください
そしてこのコードを指示と一緒に送りました.

import React from 'react';
import Link from 'next/link';

const Header = () => {
  return (
    <>
      <div>
        <div>
          <Link href="/">
            Megamouse CTF
          </Link>
        </div>
        <Link href="/scoreboard">
          Scoreboard
        </Link>
        <Link href="/challenges">
          Challenges
        </Link>
        <Link href="/profile">
          Profile
        </Link>
        <Link href="/login">
          Login
        </Link>
      </div>
    </>
  );
};

export default Header;

そして実際にChatGPTから返ってきたがこちら.

import React from 'react';
import Link from 'next/link';
import styled from 'styled-components';

const HeaderWrapper = styled.div`
  display: flex;
  align-items: center;
  justify-content: space-between;
  background-color: #333;
  color: #fff;
  padding: 10px;

  & a {
    color: #fff;
    text-decoration: none;
    margin-left: 20px;

    &:hover {
      text-decoration: underline;
    }
  }
`;

const Logo = styled.div`
  font-size: 24px;
  font-weight: bold;
`;

const Header = () => {
  return (
    <HeaderWrapper>
      <Logo>
        <Link href="/">Megamouse CTF</Link>
      </Logo>
      <div>
        <Link href="/scoreboard">Scoreboard</Link>
        <Link href="/challenges">Challenges</Link>
        <Link href="/profile">Profile</Link>
        <Link href="/login">Login</Link>
      </div>
    </HeaderWrapper>
  );
};

export default Header;

いい感じにはなりましたが,これではリンク文字列部分がよくある下線付き文字で少しチープな印象を受けます.なのでそのまま
テキストの下線部を消し,色を固定し,ホバーしたときに色が変わるようにしてください
という指示を出しました.するとこんな感じで修正してくれます.

import React from 'react';
import Link from 'next/link';
import styled from 'styled-components';

const HeaderWrapper = styled.div`
  display: flex;
  align-items: center;
  justify-content: space-between;
  background-color: #333;
  color: #fff;
  padding: 10px;

  & a {
    color: #fff;
    text-decoration: none;
    margin-left: 20px;

    &:hover {
      color: #ff9900; /* ホバー時の色をここで指定 */
    }
  }
`;

const Logo = styled.div`
  font-size: 24px;
  font-weight: bold;
`;

const Header = () => {
  return (
    <HeaderWrapper>
      <Logo>
        <Link href="/">Megamouse CTF</Link>
      </Logo>
      <div>
        <Link href="/scoreboard">Scoreboard</Link>
        <Link href="/challenges">Challenges</Link>
        <Link href="/profile">Profile</Link>
        <Link href="/login">Login</Link>
      </div>
    </HeaderWrapper>
  );
};

export default Header;

これでHeaderが完成しました.ChatGPTはファイル分割よりも一つのファイルの方が得意な印象があるので,今回はページ構成もCSSも同じファイルに書けるStyled Componentsを使うことにしました.Tailwind CSSなどでも同じように書いてもらえると思います.

メリットとデメリット

まずメリットとしては,圧倒的時間の短縮です.特にCSSについては必要に応じてdivタグなどの構成ごと書き換えてくれるので,例えば上で挙げた画像2枚目のようなflexを使ってBoxを横並びにしつつカテゴリごとに分けて縦に並べるなどの大きな実装ですら,修正含めて15分もあれば完成してしまいます.
さらに,同じチャット枠で続けて別のページの装飾を頼めばチャット履歴にあるデザインに近しいものを作ってくれる,すなわち統一感のあるページを作ることが容易になります.実際に私もまずHeaderを完成させ,それに合った雰囲気のページを作ってもらえるような指示を出していました.
一方で,ChatGPTはどうしてもブレがあるため,CSSつよつよマンからすれば自分で書いた方が確実だし速いと思います.特にデザインが完全に固まっている場合,中々意図した装飾にならないことが多いと思います.
また,ChatGPTはファイル分割が苦手という話をしましたが,それ繋がりでリファクタリングも苦手なようです.例えばロジックでuseContextやRecoilを使って欲しくい場合はそのことを伝えてくれないとuseEffectしか使わなかったですし,Styled Componentのコンポーネントを使いまわしなどは中々難しい(ファイルごとに中身が同じコンポーネントを定義してしまう)ようです.
今回はNext.jsという,情報がインターネット上に溢れていてChatGPTが学習済みの技術だったので上手くいきましたが,ここ1,2年で新しく出てきたようなフレームワークはそもそもChatGPTが学習しておらず,分かりませんと返されると思います.

おわりに

今回使用したのはGPT-3.5なので,GPT-4であればさらにクオリティの高いコードを生成してもらえると思います.というか,こういうのに特化したプラグインがもう既に存在しても何も驚かないです.
自分で書いたTypeScriptのコードよりもChatGPTが書いたコードの方が綺麗だったことで少し心に傷を負いました.いつも書いてるのはサーバーサイドだから勘弁してくれ
AIの発展は本当に著しいですね……

Discussion