はじめに
会社でAmazonQライセンスを貰えることになったので、Github Copilotと比較しつつ使い心地を知りたい筆者の記事です
この記事想定読者
-
VSCodeからAmazonQが使えるよう状態になっている
※ AmazonQのライセンスの申請手順は省略します -
AmazonQが使えるようになったけど、どのようなことが出来るのか分からない
-
GithubCopilotとの違いや、使い分け方
今回の題材
ちょっとしたチャットアプリを作る仕事があったので、今回の記事の題材にします~
今回はAWSに主眼をおいた記事にしたいので、フロントエンドはまた別の記事で
使用するAWSサービス
- DynamoDB
- Lambda
- API Gateway
- S3(今回触れません)
- Bedrock(今回触れません)
フロントエンド(今回は触れません)
- React
比較開始~AmazonQ vs Github Copilotの熱い戦い~
AmazonQ/GithubCopilotへの指示は、以下の緑色の部分に書きます
koko prompt kaku area desu
DynamoDBを作る
どういう挙動の差があるのか知りたいので、まずはざっくりな指示でいきます
チャット履歴を格納するDynamoDBを作成する
のちほど、それぞれの出力したコードの差異を整理するので、コードは読み飛ばしていただいても大丈夫です。
- AmazonQ
import { DynamoDBClient, CreateTableCommand } from "@aws-sdk/client-dynamodb";
const client = new DynamoDBClient({ region: "us-east-1" });
const createTable = async () => {
const command = new CreateTableCommand({
TableName: "ChatHistory",
KeySchema: [
{
AttributeName: "id",
KeyType: "HASH",
},
],
AttributeDefinitions: [
{
AttributeName: "id",
AttributeType: "S",
},
],
ProvisionedThroughput: {
ReadCapacityUnits: 1,
WriteCapacityUnits: 1,
},
});
try {
const response = await client.send(command);
console.log(response);
} catch (err) {
console.error(err);
}
};
createTable();
- Github Copilot
import * as cdk from '@aws-cdk/core';
import * as dynamodb from '@aws-cdk/aws-dynamodb';
export class DynamoDBStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const table = new dynamodb.Table(this, 'ChatHistory', {
tableName: 'ChatHistory',
partitionKey: {
name: 'SessionId',
type: dynamodb.AttributeType.STRING,
},
sortKey: {
name: 'Timestamp',
type: dynamodb.AttributeType.STRING,
},
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
});
table.addGlobalSecondaryIndex({
indexName: 'UserId-Timestamp-index',
partitionKey: {
name: 'UserId',
type: dynamodb.AttributeType.STRING,
},
sortKey: {
name: 'Timestamp',
type: dynamodb.AttributeType.STRING,
},
projectionType: dynamodb.ProjectionType.ALL,
});
}
}
比較
項目 | Amazon Q | GitHub Copilot |
---|---|---|
ツール | AWS SDK | AWS CDK |
テーブル設計 | 単純なテーブル構造のみ | GSI、ソートキーなどもある |
さっそく結構な差が発生してます
構築ツールの指定を失念していたので、次のAPI Gateway作成では、CDK決め打ちでいきます
API Gateway、Lambdaを作る
チャット履歴を格納するためにのDynamoDBがあります
API GatewayにPOSTリクエストを送信して、チャット履歴をDynamoDBに格納する処理を実行します
API GatewayとLambdaをCDKで書いてください
そのURLを、Reactのコードで取得し、表示するようにしてください
- AmazonQ
import * as cdk from "@aws-cdk/core";
import * as dynamodb from "@aws-cdk/aws-dynamodb";
import * as lambda from "@aws-cdk/aws-lambda";
import * as apigateway from "@aws-cdk/aws-apigateway";
export class ChatHistoryStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const table = new dynamodb.Table(this, "ChatHistory", {
partitionKey: { name: "id", type: dynamodb.AttributeType.STRING },
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
});
const lambdaFunction = new lambda.Function(this, "ChatHistoryFunction", {
runtime: lambda.Runtime.NODEJS_14_X,
code: lambda.Code.fromAsset("path/to/lambda/code"),
handler: "index.handler",
environment: {
TABLE_NAME: table.tableName,
},
});
table.grantReadWriteData(lambdaFunction);
const api = new apigateway.RestApi(this, "ChatHistoryAPI", {
restApiName: "Chat History API",
description: "This service stores chat history.",
});
const chatHistoryIntegration = new apigateway.LambdaIntegration(
lambdaFunction,
{
requestTemplates: { "application/json": '{ "statusCode": "200" }' },
}
);
api.root.addMethod("POST", chatHistoryIntegration);
}
}
- Github Copilot
// 以下のコードは、Lambda関数を作成するためのコードです
// このコードを元に、Lambda関数を作成してください
const chatHistoryTable = new dynamodb.Table(this, 'ChatHistoryTable', {
partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
sortKey: { name: 'createdAt', type: dynamodb.AttributeType.STRING },
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
});
const lambda = new lambda.Function(this, 'ChatHistoryLambda', {
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'index.handler',
code: lambda.Code.fromAsset(path.join(__dirname, 'lambda')),
environment: {
TABLE_NAME: chatHistoryTable.tableName,
},
});
chatHistoryTable.grantReadWriteData(lambda);
const api = new apigateway.RestApi(this, 'ChatHistoryApi', {
restApiName: 'ChatHistoryApi',
});
const integration = new apigateway.LambdaIntegration(lambda);
api.root.addMethod('POST', integration);
比較
両者に大差はないですが、一部異なる点があります
また、フロントエンド統合時にはCORS対応が必要になることが多いですが、CORSの設定はどちらも支援してくれませんでした
項目 | Amazon Q | GitHub Copilot |
---|---|---|
全体構成 | DynamoDB、Lambda、API Gatewayの基本構成は実現 | DynamoDB、Lambda、API Gatewayの基本構成は実現 |
CORS設定 | 設定されていない | 設定されていない |
DynamoDB |
id のみ |
id +createdAt ソートキーあり |
API Gateway | 基本的なPOSTメソッドを実装 | 基本的なPOSTメソッドを実装 |
Lambda | Lambdaコードパスを静的に指定 | Lambdaコードパスを相対パスで動的に計算 |
Lambdaについて具体的にピックアップすると、以下のような差異があります。
- AmazonQ
code: lambda.Code.fromAsset("path/to/lambda/code"),
- GithubCopilot
code: lambda.Code.fromAsset(path.join(__dirname, 'lambda')),
AmazonQでの実装では、パスをハードコードしているのに対して、GithubCopilotでは実行場所に依存しない実装です
今回は、指示をかなりアバウトなので少し難癖をつけているようですが、GithubCopilotの提案は有難いですね
まとめ
この記事では、Amazon QとGitHub Copilotを比較し、DynamoDBやAPI Gatewayを利用したAWS開発におけるコード生成の違いを確認しました
どちらも現時点で、実用に耐えうる性能だと感じますが、少ない事例から少し異なる印象を受けました
-
Amazon Q
AWSサービスに特化したシンプルで直感的なコード生成が得意 -
GitHub Copilot
Amazon Qと同じ指示でも、より柔軟で実践的な構成を効率的に作成可能
一方で、初心者には少し複雑な実装である可能性がある
今回の検証では、指示がアバウトであったのもあり、明確にどちらが優れているか・選ぶべきかは甲乙つけがたいです
ですが、初心者がすぐにAWSサービスを使いたい場合はAmazon Q、より柔軟で実践的ケースではGitHub Copilotが最適と言えそうです
今後はより実践的な(まともなプロンプトを書いた)指示をして比較をできればいいな~