こんにちは、バックエンドエンジニアのまさです。

前回のVSCodeでgithub copilotを使った開発効率向上の話に引き続き、今回はVSCodeでGenieAIという拡張機能を用いてコード品質を高める手法のご紹介をしたいと思います。
OpenAIのAPIキーが必要になりますが、こちらも開発を強力にサポートしてくれるツールです。

GenieAIとは

GenieAIはVSCodeの拡張機能の一つでChatGPTを利用したAIアシスタント機能を提供する拡張機能です。

主な機能は以下の通りです。

  • コード補完: 開発者がコードを入力する際に、文脈に応じた最適なメソッド名や変数名といったコード補完候補をリアルタイムで提示します。コーディング速度の向上が期待できます。
  • テスト実装: 既存の関数やメソッドに対して、入力値や期待出力を考慮したテストケースをAIを用いて生成します。テスト駆動開発を強力にサポートします。
  • バグ検出: AIによるコード解析により、論理エラーや例外処理漏れなどのバグを即座に検出し警告を出します。手戻りの削減につながります。
  • コード最適化: パフォーマンスボトルネックやメモリ使用量の改善点を特定し、アルゴリズム変更やコード修正を提案します。効率的なコードへのリファクタリングを支援します。
  • コード解説: 複雑な処理の流れやクラスの設計意図などを、選択したコード部分に対して自然言語で丁寧な解説を生成します。コード理解を加速します。
  • コメント生成: コードファイルや関数に対して適切な概要説明やインラインコメントを自動で付与します。ドキュメント作成作業の軽減に寄与します。

GenieAIはAnthropic社が開発した新しいAIアシスタントで、VSCodeとChatGPTを連携させることが可能になっています。生産性向上やコーディング作業の効率化に有用なツールといえます。

GenieAIのインストール

GenieAIはVSCodeの拡張機能ですので、一般的な拡張機能と同様に以下のようにしてインストール可能です。

これでGenieAIのインストールは完了です。

GenieAIは内部的にOpenAIのAPIを利用しているため、利用時にはOpenAIのAPIキーの入力がもとめられます。こちらには利用中のOpenAIのAPIキーを入力してください。

またGenieAIの各機能を実現するためのプロンプトは初期は英語で設定されているため、こちらを出力結果が日本語になるようにプロンプトを変更しておくことをオススメします。 プロンプトの変更は以下のようにして行うことができます。

GenieAIの設定画面が表示されます。

上記で表示した設定画面内の各プロンプト設定項目を以下の例のように変更します。
※こちらは設定例ですので各種任意のプロンプト内容でOKです。

  • Genieai › Prompt Prefix: Add Tests:以下のコードに対するテストコード実装を生成してください」等
  • Genieai › Prompt Prefix: Find Problems:以下のコードの問題点を日本語で指摘してください」等
  • Genieai › Prompt Prefix: Optimize:以下のコードを最適化してください」等
  • Genieai › Prompt Prefix: Explain:以下のコードの内容をわかりやすく日本語で解説してください」等
  • Genieai › Prompt Prefix: Add Comments:以下のコードに対して適切なコメントを日本語で追加してください」等
  • Genieai › Prompt Prefix: Complete Code:以下のソースコードに対して適切にコード補完してください」等

このように設定することで日本語での利用がしやすくなります。

各機能を試してみる

コード補完

GenieAIのコード補完機能は、開発者がコードを入力している最中に次に入力する可能性が高いコード候補をリアルタイムで提示する機能です。 例として以下のようなコードを記載します。

# 配列データ内のnumdataを合計して返却する関数
def sum_numdata(jsdata):

if __name__ == "__main__":
    jsdata = {
        [
            {"strdata": "a", "numdata": 11,},
            {"strdata": "b", "numdata": 21,},
            {"strdata": "c", "numdata": 16,},
            {"strdata": "d", "numdata": 41,},
            {"strdata": "e", "numdata": 15,},
        ]
    }

上記は不完全なコードですが、関数「sum_numdata」でメイン内での配列データjsdata内のnumdataを集計して合計数を出力する予定です。この状態で以下のようにVSCode上で操作を行います。

コードを全て選択し右クリックして表示されるコンテキストメニューで選択します。

するとGenieAIのコード補完機能によりサイドバーに補完されたコードが出力されます。

実装しようとしていた関数の内容が実装され、メイン内の変数の定義も最適化されています。

この状態で以下のようにすることでエディタに補完されたコードが反映されます。

補完により作成されたコードは以下のようになりました。

# 配列データ内のnumdataを合計して返却する関数
def sum_numdata(jsdata):
    # 合計値を初期化
    total = 0
    # 配列内の各要素についてループ
    for item in jsdata:
        # numdataの値を合計値に加算
        total += item["numdata"]
    # 最終的な合計値を返却
    return total

# メイン実行ブロック
if __name__ == "__main__":
    # 辞書ではなくリストとしてjsdataを定義
    jsdata = [
        {"strdata": "a", "numdata": 11},
        {"strdata": "b", "numdata": 21},
        {"strdata": "c", "numdata": 16},
        {"strdata": "d", "numdata": 41},
        {"strdata": "e", "numdata": 15},
    ]

    # 関数を呼び出し、結果をprintで表示
    result = sum_numdata(jsdata)
    print(f"合計: {result}")  # 出力: 合計: 104

コード補完を用いることでAI側でコード実装を予測し、実装しようとしていたコードを作成してくれるという例です。利用シーンによっては大いに工数を削減できる可能性があります。

テスト実装

GenieAIのテストコード生成機能は、既存のコードから自動的にテストコードを生成してくれる機能です。ここでは先程のコード内の関数「sum_numdata」に対するテストコードの生成を行ってみます。

関数「sum_numdata」を選択し右クリックして表示されるコンテキストメニューで選択します。

サイドバーに生成されたテストコードが出力されます。

生成されたテストコードは以下のようになりました。

import unittest

# 配列データ内のnumdataを合計して返却する関数
def sum_numdata(jsdata):
    # 合計値を初期化
    total = 0
    # 配列内の各要素についてループ
    for item in jsdata:
        # numdataの値を合計値に加算
        total += item["numdata"]
    # 最終的な合計値を返却
    return total

# テストケースクラスを定義
class TestSumNumdata(unittest.TestCase):
    
    # 正しい合計を返すかテスト
    def test_sum_numdata_correct(self):
        data = [
            {"strdata": "a", "numdata": 10},
            {"strdata": "b", "numdata": 20},
            {"strdata": "c", "numdata": 30},
        ]
        result = sum_numdata(data)
        self.assertEqual(result, 60) # 期待される合計値は60
    
    # 空のリストが渡された場合、0が返るかテスト
    def test_sum_numdata_empty(self):
        data = []
        result = sum_numdata(data)
        self.assertEqual(result, 0) # 期待される合計値は0
    
    # numdataキーがない場合の例外処理が適切かテスト
    def test_sum_numdata_missing_key(self):
        data = [
            {"strdata": "a"},
            {"strdata": "b", "numdata": 20},
        ]
        with self.assertRaises(KeyError):
            sum_numdata(data)

# テストランナーを実行
if __name__ == '__main__':
    unittest.main()

単純なテストだけでなく準正常系等のテストコードも生成してくれます。不足分があるなどいう場合には下記のように追加の生成要求も可能です。

サイドバーに追加のテストコードと説明が出力されます。

以下のようなコードが生成されました。

# numdataに文字データが含まれている場合のテストを追加

    # numdataに非数値データが含まれている場合にTypeErrorが発生するかテスト
    def test_sum_numdata_non_numeric(self):
        data = [
            {"strdata": "a", "numdata": "10"},
            {"strdata": "b", "numdata": 20},
            {"strdata": "c", "numdata": 30},
        ]
        with self.assertRaises(TypeError):
            sum_numdata(data)

またテストコードの生成だけではなく対象の関数の修正提案もしてくれています。

(なぜか中国語が混じってしまっているようですが。。)

def sum_numdata(jsdata):
    total = 0
    for item in jsdata:
        try:
            # 确保只把数字类型的数据加到总和中
            total += int(item["numdata"])
        except ValueError:
            # 如果转换为整数失败,抛出TypeError
            raise TypeError(f"Expected a numeric value for 'numdata', but got '{item['numdata']}' instead.")
    return total

自身の記述したテストコードに加えて、こちらで出力されるテストコードも追加するといった使い方をすることでテストを充実させ、よりコードの保守性を高めることができるようになります。

バグ検出

GenieAIのバグ検出機能は、コード中の潜在的なバグをAIが自動的に特定して開発者に警告する機能です。実際にコードで試してみましょう。

import random

# メイン実行ブロック
if __name__ == "__main__":
    RETRY_MAX = 5
    retry_count = 0
    do_retry = True
    
    while do_retry:
        x = random.randint(1,10)
        if x == 5:
            print("ok.")
        else:
            retry_count += 1
        if retry_count > RETRY_MAX:
            raise Exception("retry error, x is not 5.")
    
    print("complete.")

コード全体を選択し右クリックして表示されるコンテキストメニューで選択します。

サイドバーにコードの問題点が出力されます。

上記のとおり、コードにはループが終了しない問題がありましたが、その問題を丁寧に指摘してくれています。対処法も説明してくれていますので修正も容易です。 今回は割と明らかなミスでしたが、そうでない場合でもよりセーフティなコードになるような提案をしてくれたりと、よりコードの品質が高まるように補助してくれます。

最適化

GenieAIのコード最適化機能は、開発者のコードをAIが解析し、実行速度やメモリ使用量といったパフォーマンスを向上させる提案をしてくれる機能です。

先程のコードを少し修正したものを対象に実行してみます。

import random

# メイン実行ブロック
if __name__ == "__main__":
    RETRY_MAX = 5
    retry_count = 0
    do_retry = True
    
    while do_retry:
        x = random.randint(1,10)
        if x == 5:
            print("ok.")
            do_retry = False
        else:
            retry_count += 1
        if retry_count > RETRY_MAX:
            raise Exception("retry error, x is not 5.")
    
    print("complete.")

コード全体を選択し右クリックして表示されるコンテキストメニューで選択します。

最適化されたコードと解説が出力されます。

最適化されたコードは以下のようになりました。

import random

# メイン実行ブロック
if __name__ == "__main__":
    RETRY_MAX = 5
    retry_count = 0

    while True:  # 無限ループ
        x = random.randint(1, 10)
        if x == 5:
            print("ok.")
            break  # ループを抜ける
        else:
            retry_count += 1
        
        if retry_count >= RETRY_MAX:  # `> RETRY_MAX`から`>= RETRY_MAX`に変更
            raise Exception("retry error, x is not 5.")
    
    print("complete.")

こちらの例ではフラグ変数を使わずにbreak文でループから抜けるように修正し、よりシンプルになるように最適化してくれました。 パフォーマンスに関わる部分などでも適切に提案してくれますので、細かく活用することで可読性と性能改善に関しての品質向上が期待できます。

コード解説

GenieAIのコード解説機能は、開発者が選択したコードスニペットに対して、その処理内容や意図を自然言語で解説してくれる機能です。

例として以下のようなコードに対して解説を実行してもらいます。

def sample(nums):
    n = len(nums)
    for i in range(n):
        for j in range(n-i-1):
            if nums[j] > nums[j+1]:
                nums[j], nums[j+1] = nums[j+1], nums[j]
    return nums

nums = [5, 2, 4, 1, 3]
print(sample(nums))

サイドバーにコードの内容の解説が出力されます。

上記のようにsampleという関数がバブルソートのアルゴリズムでソートしていることを解説してくれています。引数や仕組みについて細かく説明してくれるので非常に理解しやすいです。

主に他者のコードを扱うときのキャッチアップに大いに役立つと思います。このコードは何をしているのだろうというときにこちらを利用することで細かく理解できると思います。

コメント生成

最後はコメント生成機能です。GenieAIのコメント生成機能は、コード内に適切なコメントを自動で挿入することができる機能です。こちらもコード解説機能に近いですが、コード内に明確に説明が残るというメリットがあります。

例として以下のコードにコメントを付与してもらいます。

def fetch_user_data(user_id):
    user = db.find_user(user_id)
    if not user:
        return None
    
    transactions = get_transactions(user.id) 
    sum_amount = 0
    for transaction in transactions:
        sum_amount += transaction.amount
    
    data = {
        "user_id": user.id,
        "name": "{} {}".format(user.first_name, user.last_name),
        "total_transaction_amount": sum_amount
    }
    return data

コード全体を選択し右クリックして表示されるコンテキストメニューで選択します。

サイドバーにコメントを付与したコードが生成されます。

コメントを付与してくれた結果は以下のようになりました。

def fetch_user_data(user_id):
    # ユーザーIDを元にデータベースからユーザー情報を取得する
    user = db.find_user(user_id)
    # ユーザーが存在しない場合はNoneを返す
    if not user:
        return None
    
    # ユーザーIDに紐づくトランザクション(取引)情報を取得する
    transactions = get_transactions(user.id) 
    sum_amount = 0
    # 取引の合計金額を算出する
    for transaction in transactions:
        sum_amount += transaction.amount
    
    # 返すユーザーデータを辞書形式で構築する
    data = {
        "user_id": user.id,  # ユーザーID
        "name": "{} {}".format(user.first_name, user.last_name),  # フルネーム
        "total_transaction_amount": sum_amount  # トランザクションの合計金額
    }
    # 構築したユーザーデータを返す
    return data

わかりやすくコメントが追加されていますね。未定義の関数であっても名称と前後の流れから推測してコメントを付与してくれています。コメントの付与等は意外と工数がかかったりすることがあったり、人によりわかりやすいコメントのつけ方に悩んだりするものですが、こちらの機能を利用することで、そうした悩みも無くコメントを付与できます。

コメントもコードの品質において重要な要素の一つですので、こちらを利用することでまた一つコードの品質を高めることができたと思います。

その他

GenieAIは基本的にコードを選択し、そのコードに対してAIに操作をしてもらうというような処理を行っています。以下のようにすると上記以外に自由にAIに対して指示が可能です。

このように上部に自由にプロンプトを入力できるようになるので、ここにソースに対する質問や指示を指定することで、任意の処理をAIに依頼可能です。

まとめ

いかがでしたでしょうか。GenieAIはGitHub Copilotよりも能動的にAIに処理を行わせることが可能です。特にバグ検出とコメント生成では、GitHub CopilotよりもGenieAIの方が使いやすさと生産性が高いと考えられます。

GenieAIなら人間の開発者が気づきにくいコード上の欠陥をAIが特定し、保守性の向上に役立てることができます。工数の削減と品質の向上を同時に実現できるため、ソフトウェア開発における生産性向上に期待できると思います。

開発者とAIアシスタントが協調して作業を進めるアプローチも、生成AIを最大限に活用する方法の一つではないかと思います。

SHARE

  • facebook
  • twitter

SQRIPTER

AGEST Engineers

AGEST

記事一覧

AGESTのエンジニアが情報発信してます!

株式会社AGEST

Sqriptsはシステム開発における品質(Quality)を中心に、エンジニアが”理解しやすい”Scriptに変換して情報発信するメディアです

  • 新規登録/ログイン
  • 株式会社AGEST