本記事はGitHub dockyard Advent Calendar 2024の11日目の記事です
はじめに
こんにちは!大学生でWebフロントエンドエンジニアをしている、hibikiです:-)
VS Codeの10月リリースでは、GitHub Copilotについて多くの新機能が追加されました
GitHub Copilotの新機能についてのチェンジログ
上の記事では、見出しの機能としてCopilot Edits
が挙げられています
Copilot Edits
に関する記事は同じくGitHub dockyard Advent Calendar 2024で@youtoyさんが執筆されている、GitHub Copilot の「Copilot Edits」で直接の部分的なコード書きかえを行ってもらう(機能の有効化の話も)【GitHub dockyard】をご覧いただければと思います
ここでは、同じく新機能として追加されたCode Review(Preview)
についてReact+Viteのテストプロジェクトで試してみました
え!GitHub Copilotがコードレビューまで!?👀
GitHub Copilotの進化は凄まじく、質問に答えてくれるだけでなく複数ファイルの編集もしてくれるようになりました
実際に先月、Copilot EditsでFlutterやReactプロジェクトを爆速で形に仕上げることができました。ファイル同士のコンテキストを汲み取ってくれるのでアプリ開発に大変便利です
そして、遂にはコードレビューまでしてくれるようです
上記のチェンジログには次のように書いてあります
With Copilot-powered code review in Visual Studio Code, you can now get fast, AI-powered feedback on your code as you write it, or request a review of all your changes before you push. Code review in Visual Studio Code is currently in preview. Try it out and provide feedback through our issues.
Copilotが自分の書いたコードに対してフィードバック、レビューを返してくれます!
それもCIのようにプッシュ後ではなくローカル上で任意のタイミングで実行することができます
これなら書いている途中でもコードを改善できますし、ブランチの状態をきれいに保つことにも繋がります。そしてなにより、レビュワーの負担を減らせます!
開発生産性⤴⤴
How to Use
チェンジログで挙げられているレビュー方法は2つあります
-
選択内容のレビュー
こちらはカーソルで選択した箇所のコードをレビューしてくれます、コンテキストメニューもしくはコマンドパレットから実行可能 -
変更内容のレビュー(ウェイトリストに入っておく必要あり)
コミットしていないすべての変更内容についてより詳しくレビューをしてくれます(GitHub上のプルリクエストで実行できるものと同様)、「ソース管理」メニューにある「Copilot Code Review」ボタンから実行可能
今回はウェイトリストに入っていないため、「選択内容のレビュー」のみについて取り上げますmm
コンテキストメニュー
コマンドパレット
カーソルを関数内に置いてコマンドパレットから実行すると、ファイル内の階層ごとに選択してくれます
(addTodoの内部、newTodo変数の宣言など)
実際にReact+Viteプロジェクトで試してみた
それでは、実際に試していきましょう
今回はシングルページでTodoリストを作成しました
import { useState } from 'react'
import './index.css'
interface Todo {
id: number;
text: string;
completed: boolean;
}
function App() {
// 状態の分割管理(本来はuseReducerを使うべき)
const [todos, setTodos] = useState<Todo[]>([]);
const [inputText, setInputText] = useState('');
const [searchText, setSearchText] = useState('');
const [isEditing, setIsEditing] = useState(false);
const [editId, setEditId] = useState<number | null>(null);
const [editText, setEditText] = useState('');
const [filterType, setFilterType] = useState<'all' | 'active' | 'completed'>('all');
// イベントハンドラの型安全性が欠如
const addTodo = (e: any) => {
if (inputText.trim() === '') return;
const newTodo: Todo = {
id: Date.now(),
text: inputText,
completed: false
};
setTodos([...todos, newTodo]);
setInputText('');
};
const toggleTodo = (id: number) => {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
));
};
// 非効率な実装(毎回新しい配列を生成)
const getFilteredAndSortedTodos = () => {
let result = [...todos];
if (filterType === 'active') {
result = result.filter(todo => !todo.completed);
} else if (filterType === 'completed') {
result = result.filter(todo => todo.completed);
}
result = result.filter(todo =>
todo.text.toLowerCase().includes(searchText.toLowerCase())
);
return result.sort((a, b) => b.id - a.id);
};
// メモ化されていない計算プロパティ
const stats = {
total: todos.length,
completed: todos.filter(t => t.completed).length,
remaining: todos.filter(t => !t.completed).length
};
const filteredTodos = getFilteredAndSortedTodos();
return (
<div className="w-full h-full p-8">
<div style={{ width: '100%', maxWidth: '42rem', margin: '0 auto', backgroundColor: 'white', borderRadius: '0.5rem', borderWidth: '2px' }}>
<div className="p-4 border-b-2">
<input
className="w-full h-12 px-4 mb-4 border-2 rounded-lg"
placeholder="検索..."
value={searchText}
onChange={(e) => setSearchText(e.target.value)}
/>
<div className="flex gap-2 mb-4">
<button
className={`px-4 py-2 rounded ${filterType === 'all' ? 'bg-blue-500 text-white' : 'bg-gray-200'}`}
onClick={() => setFilterType('all')}
>
全て
</button>
<button
className={`px-4 py-2 rounded ${filterType === 'active' ? 'bg-blue-500 text-white' : 'bg-gray-200'}`}
onClick={() => setFilterType('active')}
>
未完了
</button>
<button
className={`px-4 py-2 rounded ${filterType === 'completed' ? 'bg-blue-500 text-white' : 'bg-gray-200'}`}
onClick={() => setFilterType('completed')}
>
完了済み
</button>
</div>
<div className="flex gap-2">
<input
className="flex-1 h-12 px-4 border-2 rounded-lg"
placeholder="新しいタスク"
value={inputText}
onChange={(e) => setInputText(e.target.value)}
// コールバック関数の不適切な定義(レンダリングごとに新しい関数が作成される)
onKeyPress={function(e: React.KeyboardEvent<HTMLInputElement>) {
if (e.key === 'Enter') {
addTodo(e)
}
}}
/>
<button
style={{ padding: '0 1.5rem', backgroundColor: '#3b82f6', color: 'white', borderRadius: '0.5rem' }}
onClick={addTodo}
>
追加
</button>
</div>
</div>
<div className="p-4 border-b-2 text-sm text-gray-500">
全て: {stats.total} | 完了: {stats.completed} | 残り: {stats.remaining}
</div>
<ul className="divide-y">
{filteredTodos.map(todo => (
<li
key={todo.id}
className="flex items-center p-4 hover:bg-gray-50 cursor-pointer"
onClick={() => toggleTodo(todo.id)}
>
<input
type="checkbox"
checked={todo.completed}
className="w-5 h-5 mr-4"
readOnly
/>
<span className={`flex-1 ${todo.completed ? 'line-through text-gray-400' : ''}`}>
{todo.text}
</span>
</li>
))}
</ul>
</div>
</div>
)
}
export default App
UIライブラリは普段使用しているtailwindCSSを使用しています
ところどころに修正すべき点を加えて(正常に動作はする)、ちゃんとレビューをしているかを確かめます
ちゃんとレビューしてくれた!でも...
Code Reviewを走らせると上の画像のようにレビューと変更の提案をしてくれます!
提案までしてくれるのはありがたいですね✨️
この実行では他のコメントアウトしている5箇所のほとんど(getFilteredAndSortedTodos
以外)でレビューをしてくれました
しかし、何度か試してみると、この機能はかなりばらつきがあるのかなと感じました。
というのも、同じコードでもレビューの箇所を検出できるときとできないときがあり(大半は検出できていない)、またコメントを削除すると実行してもほとんど検出されていませんでした
これはまだプレビューの機能であるため、今後の改善に期待したいところです🌈
まとめ
今回は、GitHub Copilotに追加された新機能Code Review(Preview)
について、テストプロジェクトで試してみました!
現段階では精度に課題がありますが、今後の改善によって開発者とレビュワー双方の負担を軽減し、開発生産性の工場向上が期待できると感じました!
今後も引き続き情報を追っていこうと思います👀
それでは、引き続きGitHub dockeryard Advent Calendar 2024をお楽しみください!
ご清覧ありがとうございました🙇♂️