2023.5.12
プロダクト
GPTに実装をお願いできたらというのは多くのエンジニアの願いです。色んなお願いの仕方があるかと思いますが、今回はJSDocを投げてみることにします。
GPTはトークンの上限の問題でお願いできる実装の規模は限られています。ちょうど良くまとまった実装単位として、今回はReactコンポーネントの実装をお願いしてみます。適当にロジックが必要なものである方が良いので、ページネーションコンポーネントを実装してみます。GPTのバージョンは3.5です。
まずは普段書くようなJSDocで、少ない記述でやってみます。
/**
* Pagination component
* ページネーションを表示するコンポーネント
* @param {number} current - 現在のページ位置
* @param {function} clickButton - ボタンをクリックしたときの処理
* @param {number} max - 最大のページ位置
* @returns {JSX.Element}
*/
次のような出力が得られました。
import React, { FC } from 'react';
type Props = {
current: number;
clickButton: (page: number) => void;
max: number;
};
const Pagination: FC<Props> = ({ current, clickButton, max }) => {
const pages = [];
for (let i = 1; i <= max; i++) {
pages.push(
<button key={i} onClick={() => clickButton(i)}>
{i}
</button>
);
}
return <div>{pages}</div>;
};
export default Pagination;
出してくれたコードの挙動を確認したいので、続けてStorybookのコードもお願いしてみます。
import React from 'react';
import { Story, Meta } from '@storybook/react';
import Pagination, { Props } from './Pagination';
export default {
title: 'Components/Pagination',
component: Pagination,
argTypes: {
current: {
control: { type: 'number' },
defaultValue: 1,
},
max: {
control: { type: 'number' },
defaultValue: 10,
},
clickButton: { action: 'clickButton' },
},
} as Meta;
const Template: Story<Props> = (args) => <Pagination {...args} />;
export const Default = Template.bind({});
Default.args = {};
export const Custom = Template.bind({});
Custom.args = {
current: 5,
max: 20,
};
export const OnePage = Template.bind({});
OnePage.args = {
max: 1,
};
Props
をexportするように少しだけ実装に手を入れると、↓のようなStorybookを確認する事が出来ました。
max
を変化させるとそれに従って表示される数字が変わります。一方current
は特に実装には用いられていないようです(悲しい)。最低限のページネーションと呼べなくもないですが、ちょっと寂しいです。
パラメータの数が少なすぎてぼんやりした要求になってしまったかもしれません。
最終的に以下のようなJSDocを投げてみました。
/**
* @name Paging
* @description ページネーションを表示するコンポーネント
* @kind class
* @throws 現在のページ位置が不正
* @param {number} current - 現在のページ位置
* @param {function} clickButton - ボタンをクリックしたときの処理
* @param {number} max - 最大のページ位置
* @param {number} displayNumberNearCurrent - 現在のページ位置の前後に表示させるページ数
* @param {string} [currentBtnClass=current] - 現在のページ位置のボタンに適用するクラス名
* @param {string} [previousLabel=<] - 一つ前に戻るボタンとして表示するラベル
* @param {string} [nextLabel=>] - 一つ先に進むボタンとして表示するラベル
* @param {string} [breakLabel=...] - 非表示にしているページ番号を埋めるラベル
* @returns {JSX.Element}
* @example
* // return < 1 ... 3 4 5 6 7 ... 10 >
* <Pagination current={5} max={10} displayNumberNearCurrent={2} />
* @example
* // return 1 2 3 ... 10 >
* <Pagination current={1} max={10} displayNumberNearCurrent={2} />
*/
クラスコンポーネントで実装してくれました。ただし出力の安定感はやや下がりました(何度かリトライしました)。クラスコンポーネントはあまり得意じゃないかもしれません。
始めは少ない@param
でお願いしてみましたが、必要最低限の実装しかしてくれませんでした。そこで自由度のある箇所を徹底的に@params
で指定できるようにしようと増やしていきましたが、あるところからロジックが破綻した出力ばかりになってしまいました。出力の安定化を狙って@example
を追加したところ、Few-shotの働きがあったのか効果が見られました。他にもJSDocのタグの種類を増やすことでいろいろな要件を満たす実装が出来そうでした。
結論として、フロントエンドである程度の複雑さを持つページネーションコンポーネントがGPT-3.5で実装出来ました。
何故今回JSDocでお願いしたかというと、JSDocがあればコードの仕様がつかめて人間にとっても嬉しいからです。GPTに書いてもらったコードをStorybook上で確認し(何だったらテストも書いてもらって)、問題なさそうでしたらJSDocをコンポーネント上部にペタッとはれば、保守性もそこそこに良いものが出来上がると思われます。