こんにちは、バックエンドエンジニアのまさです。
最近、開発プロセスを効率化するための取り組みの一つとして、Github Copilotを利用しています。この記事では、Github Copilotを使ってみた結果、開発効率が劇的に向上した経験について共有したいと思います。
Github Copilotとは
Github Copilotは、AI(人工知能)を利用してコーディングの補完や提案を行う開発ツールです。このツールは、コードを書く際に、自動的にコードの断片や関数を提案してくれます。また、コードの文脈に基づいて、適切なコードスニペットを生成することもできます。Github Copilotは、プログラミング言語やフレームワークに関係なく使用することができます。
まずは試してみる|GitHub Copilotの使い方
普段は開発用のIDEとしてVSCodeを利用しています。VSCodeにはこちらのGitHub Copilot用の拡張プラグインがありますので、こちらをインストールして使用します。
プラグインをインストールした後、新規にファイルを作成してCopilotを試してみます。今回はGo言語で試してみるため、main.go
というファイルを作成します。
試しにクエリパラメータを受け取り、それをレスポンスとして返却するHTTPサーバーを実装してみたいと思います。
まずは、main.go
に以下のようにコメントで記述します。
// httpサーバーでユーザーからのリクエストをqパラメタで受け取り、それをレスポンスとして返す処理の実装
そして改行すると
このようにcopilotが続けてコメント候補を提案してくれます。 今回はそのまま記述を行いたいのでパッケージ文package main
を記述しようと思います。 そのため一文字目のpという文字を打ち込むと
打ち込もうとしたpackage main
を候補として提案してくれました。 これはそのまま利用したいためtabキーを押下し、提案を承諾します。 続けて2行改行すると次は
import文の提案をしてくれます。以降は改行→提案承諾という形でしばらく進めてみます。 すると最終的には下記のような動作するコードを生成してくれます。
動作を確認するため、以下のようにしてこのプログラムを実行します。
go run main.go
コマンドを実行するとサーバー処理が起動し、リクエスト受付状態となります。 別のターミナルから下記のようにコマンドを実行してみます。
curl localhost:8080?q=test
「hello test」のように出力がされると思います。
最初のコメントに記載したとおり「httpサーバーでユーザーからのリクエストをqパラメタで受け取り、それをレスポンスとして返す処理の実装」を達成できました!
テストでの活用
Github Copilotはテストコードの作成にも役立ちます。テストケースやアサーションの生成、モックオブジェクトの作成など、テストに関連するコードの自動生成が行われます。これにより、手作業でのテストコードの作成時間やミスの可能性を減らすことができます。 実際に例を以下に記載したいと思います。
まずテスト対象のコードです。 ファイルはsrc/common/utils.go
として作成してあります。
package common
type ItemList struct {
IdList []int
ItemMap map[int]Item
NameConcat string
TotalPrice int
}
type Item struct {
ID int
Name string
Price int
}
// Item配列を受け取り、ItemListを返す関数
func NewItemList(items []Item) *ItemList {
// ItemListを初期化
itemList := &ItemList{
// IdListを初期化
IdList: []int{},
// ItemMapを初期化
ItemMap: map[int]Item{},
// TotalPriceを初期化
TotalPrice: 0,
}
// itemsを回す
for _, item := range items {
// IdListにitem.IDを追加
itemList.IdList = append(itemList.IdList, item.ID)
// ItemMapにitem.IDをキーとしてitemを追加
itemList.ItemMap[item.ID] = item
// NameConcatにitem.Nameを追加
itemList.NameConcat += item.Name
// TotalPriceにitem.Priceを加算
itemList.TotalPrice += item.Price
}
// ItemListを返す
return itemList
}
こちらは、Itemという構造体の配列から集計などを行い、ItemList構造体を返却する関数です。 具体的には、Item配列のIDのリストをIdListに、Idと実体を紐づけた連想配列をItemMapに、Nameを連結したものをNameConcatに、そして金額を合計したものをTotalPriceに格納したItemListを生成する処理となっています。
この関数のテストコードを作成するため、テスト用のソースsrc/common/utils_test.go
を新たに作成しVSCodeで開きます。
まずは冒頭で下記のように入力します。
package common
するとimport文の提案をしてくれますので了承します。
package common
import (
"testing"
)
続けて以下のようにテストの生成の為のコメントが提案されます。
package common
import (
"testing"
)
// NewItemListのテスト
その後は関数名からテストの実装まで全て提案してくれました。
package common
import (
"testing"
)
// NewItemListのテスト
func TestNewItemList(t *testing.T) {
// Itemを複数作成
items := []Item{
{ID: 1, Name: "item1", Price: 100},
{ID: 2, Name: "item2", Price: 200},
{ID: 3, Name: "item3", Price: 300},
}
// NewItemListの実行結果を取得
itemList := NewItemList(items)
// NewItemListの実行結果のIdListの長さが3でない場合
if len(itemList.IdList) != 3 {
// テスト失敗
t.Errorf("len(itemList.IdList) = %v, want %v", len(itemList.IdList), 3)
}
// NewItemListの実行結果のIdListの要素が1でない場合
if itemList.IdList[0] != 1 {
// テスト失敗
t.Errorf("itemList.IdList[0] = %v, want %v", itemList.IdList[0], 1)
}
// NewItemListの実行結果のIdListの要素が2でない場合
if itemList.IdList[1] != 2 {
// テスト失敗
t.Errorf("itemList.IdList[1] = %v, want %v", itemList.IdList[1], 2)
}
// NewItemListの実行結果のIdListの要素が3でない場合
if itemList.IdList[2] != 3 {
// テスト失敗
t.Errorf("itemList.IdList[2] = %v, want %v", itemList.IdList[2], 3)
}
// NewItemListの実行結果のItemMapの長さが3でない場合
if len(itemList.ItemMap) != 3 {
// テスト失敗
t.Errorf("len(itemList.ItemMap) = %v, want %v", len(itemList.ItemMap), 3)
}
// NewItemListの実行結果のItemMapの要素が1でない場合
if itemList.ItemMap[1] != items[0] {
// テスト失敗
t.Errorf("itemList.ItemMap[1] = %v, want %v", itemList.ItemMap[1], items[0])
}
// NewItemListの実行結果のItemMapの要素が2でない場合
if itemList.ItemMap[2] != items[1] {
// テスト失敗
t.Errorf("itemList.ItemMap[2] = %v, want %v", itemList.ItemMap[2], items[1])
}
// NewItemListの実行結果のItemMapの要素が3でない場合
if itemList.ItemMap[3] != items[2] {
// テスト失敗
t.Errorf("itemList.ItemMap[3] = %v, want %v", itemList.ItemMap[3], items[2])
}
// NewItemListの実行結果のNameConcatがitem1item2item3でない場合
if itemList.NameConcat != "item1item2item3" {
// テスト失敗
t.Errorf("itemList.NameConcat = %v, want %v", itemList.NameConcat, "item1item2item3")
}
// NewItemListの実行結果のTotalPriceが600でない場合
if itemList.TotalPrice != 600 {
// テスト失敗
t.Errorf("itemList.TotalPrice = %v, want %v", itemList.TotalPrice, 600)
}
}
このテストは実際にそのまま利用して関数のテストを行うことが可能です。
go test -v ./
=== RUN TestNewItemList
--- PASS: TestNewItemList (0.00s)
PASS
ok github.com/agest-inc/example/src/common 0.003s
このように、実装に対するテストコードの提案をしてもらえることで、開発の補助ツールとして非常に有用であり、工数の削減に大いに役立っていると考えています。ただし、提案されたコードが100%正しいという保証はありませんので、内容の確認は自己責任で行う必要があります。
それでも、テストデータのコーディングの手間を省くことや、似たようなコードの繰り返しで一部変更を行う必要がある場合には、一定の効果があるのではないかと思います。
開発効率の向上
Github Copilotを使ってみると、開発効率が以前に比べて大幅に向上している実感があります。以前は、コードの一部を手動で入力する必要がありましたが、Copilotを使うと、コードの提案を受けることができます。これにより、時間を節約できるだけでなく、開発のスピードも大幅に向上しました。
また、Copilotは私のコーディングスタイルに合わせて学習していくため、提案されるコードは私の好みや習慣に合ったものが多くなりました。これにより、コードの書き方に一貫性が生まれ、保守性も向上しました。
さらに、Copilotは私の知識の不足を補ってくれる頼もしい存在です。新しいライブラリやフレームワークに挑戦する際、Copilotが適切なコードの提案をしてくれるため、学習の助けになりました。これにより、新しい技術への取り組みもスムーズになりました。
この中でも最もおすすめな活用方法は、テストコードの実装です。効率的に実装できるだけでなく、想定していないテストパターンなども提案してくれる可能性があるという点もメリットだと思います。
一つ気をつけるべきなのはGithub Copilotがコードを作成してくれるのではなく、補助してくれるという意識で利用する必要があるという部分です。あくまでAIによる提案であり、確実に意図しているような実装を提案してくれるわけではないため、最終的な実装は自身の目で確認しながら利用していくということを意識していないと誤った実装をそのまま適用してしまいかねません。 それさえ意識していればとても便利に利用することができると思います。
結論
Github Copilotは、開発効率を劇的に向上させることができる素晴らしいツールです。コーディングの補完や提案により、時間の節約や一貫性の確保、知識の補完といった恩恵を受けることができます。私のように開発プロセスを効率化したい方には、ぜひGithub Copilotを試してみていただきたいです。
なお、「Visual Studio CodeとGitHub Copilotでコーディング効率を革新!AIを駆使した開発ガイド(Sqripts)」の記事では開発に導入する手順と実例を紹介していますので、併せてご覧ください。
<参考サイト・記事>
・今話題のAIツールについてはこちらのサイトから探すことができます。あわせてご確認ください。
AIツール紹介メディア:romptn AI