🫣

ChatGPT(GPT-4)のコーディングテストにチャレンジしてみた

2023/03/23に公開

ビルゲイツがAIへの期待として「教育の公平性」というニュアンスの記載があったので、ChatGPT(GPT-4)にコーディングテストを出題してもらい。挑戦してみました。結論としては、手の速さと基本的な部分の確認にはかなり使えそうです。
https://www.gatesnotes.com/The-Age-of-AI-Has-Begun

ChatGPTが出題した課題

課題: ToDoリストアプリの作成

要件:
ユーザーが新しいToDoアイテムを追加できる。
ユーザーがToDoアイテムを完了済みとしてマークできる。
ユーザーが完了済みのToDoアイテムを未完了に戻すことができる。
ユーザーがToDoアイテムを削除できる。
ユーザーがすべてのToDoアイテムをフィルタリングして表示できる(すべて、未完了、完了済み)。

技術スタック:
React、Vue.js、Angularのいずれかのフレームワークを使用してください。
状態管理には、選択したフレームワークの状態管理ツール(Redux、Vuex、NgRxなど)またはローカルステートを使用してください。
スタイリングには、CSSフレームワーク(Bootstrap、Bulmaなど)またはCSS in JS(styled-components、Emotionなど)を使用してください。

この課題を完成させることで、フロントエンド開発における基本的な技術スキルを実践的に試すことができます。ToDoリストアプリはシンプルながら、データの追加、更新、削除、フィルタリングといった一般的な操作をカバーしています。

作成したコードの評価

技術スタックはこちらを使いました。
React、useState, tailwind

実際に作ったのはこちら

ChatGPTの評価

このコードは機能的には完全で、要件を満たしています。ただし、以下のような改善点があります:

filterSwitchBtnGroupのような複雑なデータ構造は、コードの可読性を低下させる可能性があります。シンプルなデータ構造や、直接コンポーネントに渡す方法を検討してください。
複数の状態を管理する際、useReducerを検討することで、より一貫性のある状態管理が可能になります。
全体として、このコードは機能的であり、要件を満たしているため、採点すると以下のようになります。

機能性: 10/10
コードの可読性: 8/10
状態管理: 8/10
スタイリング: 9/10
合計: 35/40

このコードは、要件を満たすための良い基本的な解決策を提供していますが、いくつかの改善点があります。お疲れ様でした!


useReducerを使い慣れていないのがバレました。。汗

ChatGPTのお手本コード

かなり綺麗に描き直してくれました。

import React, { useReducer } from 'react';
import styled from 'styled-components';

const initialState = {
  todos: []
};

const actionTypes = {
  ADD_TODO: 'ADD_TODO',
  TOGGLE_TODO: 'TOGGLE_TODO',
  DELETE_TODO: 'DELETE_TODO'
};

const reducer = (state, action) => {
  switch (action.type) {
    case actionTypes.ADD_TODO:
      return {
        ...state,
        todos: [...state.todos, { id: Date.now(), text: action.text, completed: false }]
      };
    case actionTypes.TOGGLE_TODO:
      return {
        ...state,
        todos: state.todos.map((todo) =>
          todo.id === action.id ? { ...todo, completed: !todo.completed } : todo
        )
      };
    case actionTypes.DELETE_TODO:
      return {
        ...state,
        todos: state.todos.filter((todo) => todo.id !== action.id)
      };
    default:
      return state;
  }
};

const Container = styled.div`
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 20px;
`;

const Input = styled.input`
  padding: 5px;
`;

const Button = styled.button`
  padding: 5px;
  margin-left: 5px;
`;

const List = styled.ul`
  list-style-type: none;
  padding: 0;
`;

const ListItem = styled.li`
  display: flex;
  align-items: center;
  margin-bottom: 5px;
`;

const TodoText = styled.span`
  text-decoration: ${(props) => (props.completed ? 'line-through' : 'none')};
  margin-right: 10px;
`;

const TodoApp = () => {
  const [state, dispatch] = useReducer(reducer, initialState);
  const [inputText, setInputText] = React.useState('');

  const handleAddTodo = () => {
    dispatch({ type: actionTypes.ADD_TODO, text: inputText });
    setInputText('');
  };

  return (
    <Container>
      <div>
        <Input value={inputText} onChange={(e) => setInputText(e.target.value)} />
        <Button onClick={handleAddTodo} disabled={!inputText.trim()}>
          Add Todo
        </Button>
      </div>
      <List>
        {state.todos.map((todo) => (
          <ListItem key={todo.id}>
            <TodoText completed={todo.completed}>{todo.text}</TodoText>
            <Button onClick={() => dispatch({ type: actionTypes.TOGGLE_TODO, id: todo.id })}>
              Toggle
            </Button>
            <Button onClick={() => dispatch({ type: actionTypes.DELETE_TODO, id: todo.id })}>
              Delete
            </Button>
          </ListItem>
        ))}
      </List>
    </Container>
  );
};

export default TodoApp;

所要時間のChatGPTの評価

所要時間の評価も頼んでみました。

ChatGPTの評価目安

習熟度別の所要時間の目安は以下の通りです。ただし、これらの時間はあくまで一般的な目安であり、個人差があります。

初級者: 初級者の場合、ReactやJavaScriptに慣れていないため、このようなコードを書くのに数時間から半日程度かかることがあります。基本的な概念や文法を理解するのに時間がかかるため、より長い時間が必要になることがあります。

中級者: 中級者は、ReactやJavaScriptの基本的な概念に精通しており、このようなコードを1〜2時間程度で書くことができるでしょう。ただし、より高度な機能や最適化を実装するのには、追加の時間が必要になることがあります。

上級者: 上級者は、ReactやJavaScriptに非常に習熟しているため、このようなコードを30分から1時間程度で書くことができます。また、最適化や追加機能の実装も素早く行うことができるでしょう。

これらの目安はあくまで一般的なものであり、個人差やコーディング環境、タスクの複雑さなどによって所要時間は変わります。自分の習熟度や経験に基づいて、適切な時間を見積もることが重要です。


今回50m程度だったので、上級者判定🙌

まとめ

ChatGPTにコーディングテストを出してもらい、実際に提出してみました。
採用にも使えそうかとも思いましたが、ここまででお気づきの方もいるかもしれませんが、オフラインじゃないと相手にChatGPTを使われるかもしれないので初心者自身の自己研鑽としての利用としては有能ですね!

おまけ

口頭質問も考えてもらいました。面談で聞くことに困ることもあるので、アイディア出しとしてはかなり便利です。回答もして採点してもらいましたが、かなり甘くニュアンスがあってれば点数くれるので、そこは注意して使う必要がありそうです。

初級

  • HTML は何の略語ですか?
  • CSS は何の略語ですか?
  • JavaScript はどのような目的で使用されますか?
  • ウェブページに画像を表示するために、HTML のどのタグを使用しますか?
  • HTML で、リンクを作成するために使用されるタグは何ですか?

中級

  • レスポンシブデザインの原則とは何ですか?
  • Flexbox と Grid Layout の違いは何ですか?
  • クロスオリジンリソース共有 (CORS) とは何ですか?
  • クライアントサイドレンダリングとサーバーサイドレンダリングの違いは何ですか?
  • プログレッシブウェブアプリ (PWA) の特徴を3つ挙げてください。

上級

  • Virtual DOM(仮想DOM)とは何ですか?また、それが何のために使用されるのか説明してください。
  • ウェブアクセシビリティに関して、WCAGのガイドラインを遵守することが重要な理由は何ですか?
  • シングルページアプリケーション(SPA)とマルチページアプリケーション(MPA)の違いを説明してください。
  • フロントエンドのパフォーマンス最適化のために実施できる方法を3つ挙げてください。
  • フロントエンド開発でよく使われるパッケージマネージャーであるnpmとyarnの主な違いを述べてください。

上級+

  • ReactとVue.jsの主な違いを説明してください。どのようなシチュエーションで、どちらを選択すると良いですか?
  • フロントエンド開発でパフォーマンスを計測するために、どのようなツールや指標が利用できますか?
  • ウェブアプリケーションのセキュリティ上の脆弱性を防ぐために、フロントエンド開発者が実施すべきベストプラクティスを3つ挙げてください。
  • フロントエンドでの状態管理について、どのようなアプローチやツールがありますか?
  • ウェブコンポーネントとは何ですか?その利点と制約を説明してください。

おまけ2(test)

先程のお手本コードをvitestでtestを書いてもらいました。

import { test } from 'vitest';
import { render, fireEvent, screen } from '@testing-library/react';
import TodoApp from './TodoApp';

test('should add todo item', async () => {
  render(<TodoApp />);

  const input = screen.getByRole('textbox');
  const addButton = screen.getByText('Add Todo');

  await fireEvent.change(input, { target: { value: 'New Todo' } });
  await fireEvent.click(addButton);

  expect(screen.getByText('New Todo')).toBeInTheDocument();
});

test('should toggle todo item', async () => {
  render(<TodoApp />);

  const input = screen.getByRole('textbox');
  const addButton = screen.getByText('Add Todo');

  await fireEvent.change(input, { target: { value: 'New Todo' } });
  await fireEvent.click(addButton);

  const toggleButton = screen.getByText('Toggle');
  await fireEvent.click(toggleButton);

  const todoText = screen.getByText('New Todo');
  expect(todoText.closest('span')).toHaveStyle('text-decoration: line-through;');
});

test('should delete todo item', async () => {
  render(<TodoApp />);

  const input = screen.getByRole('textbox');
  const addButton = screen.getByText('Add Todo');

  await fireEvent.change(input, { target: { value: 'New Todo' } });
  await fireEvent.click(addButton);

  const deleteButton = screen.getByText('Delete');
  await fireEvent.click(deleteButton);

  expect(screen.queryByText('New Todo')).not.toBeInTheDocument();
});

Discussion