はじめに
VSCodeには、GitHub Copilot Labsという拡張機能があります。
その中に、BRUSHES
という機能があります。
BRUSHES
を使えば、コードを読みやすくしたり各行ごとにコメントを追加してくれたりします。
実は、標準で提供してくれている機能で満足してない場合、CUSTOM
という機能を使うことで、ChatGPTにお願いするようなことをGitHub Copilotに対して指示することができます。
リファクタリング
例えば、次のようなメソッドを書いていたとします。
...
deserialize(json: string): void {
// should return when json is empty
if (!json) { return; }
this.elements.clear();
const tree = JSON.parse(json) as TreeElement[];
tree.forEach((element) => {
this.elements.set(element.data.id, element);
if (!element.parentId) {
this.rootId = element.data.id;
}
});
}
...
そして、このdeserialize()
に対して次のようなテストを書いていたとします。
このテストでは、JSONとして正しくない値を渡した場合、set()
が呼ばれないことを確認するためのテストです。
// Write a test case for when value is not empty string and is not valid JSON
test("when value is not empty string and is not valid JSON", () => {
// register vscode.ExtensionContext as a dependency using tsyringe
container.register("ExtensionContext", {
useValue: {
globalState: {
get: () => {
return "not valid JSON";
}
}
}
});
// create a fake ChatGPTEditorStorageImpl instance
const storage = new ChatGPTEditorStorageImpl();
// stub this.elements.set() method
const setStub = sinon.stub(storage.elements, "set");
// call deserialize method
storage.deserialize("not valid JSON");
// assert this.elements.set() method is called with empty array
assert.ok(setStub.notCalled);
});
このテストを実行すると、もちろんエラーが出てしまいます。
deserialize
when value is not empty string and is not valid JSON:
SyntaxError: Unexpected token o in JSON at position 1
これは、JSON.parse()
にJSONでない値を渡してしまっているため、エラーが発生しているのです。
GitHub Copilotにdeserialize()
をリファクタリングしてもらい、エラーが出ないようにしてみましょう。
まず、リファクタリングしたいコードのブロックを選択します。
GitHub Copilot LabsのBrushes
からCUSTOM
を選択します。
テキストフィールドに、refactor not to throw error when json is not valid
と入力します。
じゃじゃーん!!!これでコードのリファクタリングが完了しました!
めちゃくちゃ簡単ですよね。
deserialize(json: string): void {
// should return when json is empty
if (!json) { return; }
this.elements.clear();
let tree: TreeElement[];
try {
tree = JSON.parse(json) as TreeElement[];
} catch (error) {
return;
}
tree.forEach((element) => {
this.elements.set(element.data.id, element);
if (!element.parentId) {
this.rootId = element.data.id;
}
});
}
もちろんこの程度のリファクタリングなら、自分で書いた方が早いかもしれませんが、この程度のリファクタリングさえもAIに任しちゃった方が設計などの本質的な部分に集中できる気がしています。
それでは先ほどのテストをもう一度実行してみましょう。
今度はちゃんと成功しました。
✔ when value is not empty string and is not valid JSON
ChatGPTを使ってリファクタリング
今度は、ChatGPTを使ってリファクタリングをしてみたいと思います。
先ほど、CUSTOM
に入力したメッセージをコメントとして記述し、ChatGPTに渡してみたいと思います。
// refactor not to throw error when json is not valid
deserialize(json: string): void {
// should return when json is empty
if (!json) { return; }
this.elements.clear();
const tree = JSON.parse(json) as TreeElement[];
tree.forEach((element) => {
this.elements.set(element.data.id, element);
if (!element.parentId) {
this.rootId = element.data.id;
}
});
}
実行した結果、テストもちゃんと通るコードにリファクタリングされました!
ChatGPTはlet
を使わず、ブロック自体をtry-catch
で囲むという選択をしました。
// refactor to handle invalid JSON gracefully
deserialize(json: string): void {
try {
const tree = JSON.parse(json) as TreeElement[];
this.elements.clear();
tree.forEach((element) => {
this.elements.set(element.data.id, element);
if (!element.parentId) {
this.rootId = element.data.id;
}
});
} catch (error) {
console.error(`Error deserializing JSON: ${error}`);
}
}
ChatGPTに渡されたコンテキストは、GitHub Copilotに渡したものよりも少ないにもかかわらず、推論を行い正しい結果を出してくれていることにかなり驚愕しました。
まとめ
GitHub Copilot Labsは初見だとどの機能がどのように使えるのかよくわからなかったりしますが、どれもすごい機能ばかりなので是非トライアンドエラーの精神で使ってみることをおすすめします。