Amazon Web Services ブログ

Amazon CodeWhisperer でアプリケーションをより速く構築する10の方法

Amazon CodeWhisperer は強力な生成 AI ツールで、コーディングの能力を与えてくれます。CodeWhisperer をワークフローに組み込んで以来、私はアプリケーションを構築するのがより速く、より賢く、そしてより楽しくなりました。ただし、生成 AI ツールを効果的に使用する方法を学ぶには、初心者の考え方と、新しい働き方を受け入れる意欲が必要です。

CodeWhisperer を活用するためのベストプラクティスはまだ出てきていません。しかし、初期の探検家として、この素晴らしいツールを最大限に活用するためのいくつかのテクニックを発見しました。この記事では、CodeWhisperer がプログラミングワークフローをどのように強化できるかを実践的な例を用いて説明します:

始める前に

これらのテクニックを自分で試してみたい場合は、AWS Toolkit 拡張機能がインストールされたコードエディタを使用する必要があります。VS Code、AWS Cloud9、および JetBrains のほとんどのエディターで動作可能です。セットアップ手順については、CodeWhisperer の “Getting Strarted” リソースを参照してください。

CodeWhisperer は、入力すると自動的に候補を表示します。候補が表示されない場合は、 Option + C (Mac) または Alt + C (Windows) のショートカットを使用して、いつでも手動で候補を表示できます。CodeWhisperer は、複数の候補を提示してその中から選択できる場合もあります。→ キーと ← キーを押すと、表示される候補をすべて順番に表示できます。

CodeWhisperer が提供する提案は非決定的であるため、この記事に示されているものとは少し異なる提案を受け取る可能性があります。ニーズに合わない提案を受け取った場合は、矢印キーを使用して候補をすべて順番に確認するか、コードコメントのプロンプトを少し言い換えてみてください。句読点を変えても、新しい提案が生まれます。

この記事の例は JavaScript と TypeScript で記述されています。ただし、これから説明する手法は、CodeWhisperer がサポートする多くのプログラミング言語にも同様に適用できます。それでは、例を見てみましょう!

タイピングの減少

最も基本的なレベルでは、CodeWhisperer は強力なオートコンプリート機能として使用でき、個々の行やコードブロックを書く際の入力を大幅に減らすことができます。CodeWhisperer をこのように使用するには、通常どおりにコードを書くだけです。CodeWhisperer は入力すると自動的に候補を表示します。役に立つ提案を受け入れ、役に立たない提案は無視します。私の経験では、CodeWhisperer をこのように使用するだけで、タイピングが 50% 以上減ります。

関数の生成

シグネチャから関数本体を自動生成

熟練したプログラマーは、関数やパラメータにわかりやすい名前を付けます。自分自身のプログラミングでこのプラクティスに従えば、CodeWhisperer は多くの関数を実装するのに必要なコンテキストを全て持つことができます。

以下のように関数シグネチャを入力すると、CodeWhisperer が関数本体を生成してくれます。

ユーザの入力 (JavaScript):

function standardDeviation(numbers)

出力結果:

function standardDeviation(numbers) {
  let mean = numbers.reduce((a, b) => a + b) / numbers.length;
  let variance =
    numbers.reduce((a, b) => a + Math.pow(b - mean, 2)) / numbers.length;
  return Math.sqrt(variance);
}

コメントから関数を生成

適切な関数シグネチャだけでは、関数の望ましい動作を伝えるのに十分ではない場合があります。このような場合は、詳細なコードコメントを CodeWhisperer へのプロンプトとして使用できます。このテクニックを使うときは、自分の言語のドキュメンテーションコメント区切り文字を使うことをお勧めします。

ユーザの入力 (JavaScript):

/**
 * Given a list that contains some numbers and strings, format them into a string
 * in which the numbers are prepended with "#" and the strings are wrapped in
 * double quotes.
 */

出力結果:

/**
 * Given a list that contains some numbers and strings, format them into a string
 * in which the numbers are prepended with "#" and the strings are wrapped in
 * double quotes.
 */
function formatList(list) {
  return list
    .map((item) => {
      if (typeof item === "number") {
        return `#${item}`;
      } else {
        return `"${item}"`;
      }
    })
    .join(", ");
}

クラスの生成

1 つのコードコメントからクラス実装の全部または一部を生成できます。コメントには、クラスの主要なプロパティと動作を説明する必要があります。多くの場合、必要なのは簡単な説明だけです。

ユーザの入力 (TypeScript):

/**
 * A folder has a name, children, and an optional parent. A child can't be added
 * twice.
 */

出力結果:

上記のブロックコメントを書いた後、CodeWhisperer は次の実装を含む複数の提案をしてくれ、各メソッドのドキュメンテーションコメントも付いています!

/**
 * A folder has a name, children, and an optional parent. A child can't be added
 * twice.
 */
export class Folder {
  name: string;
  children: Folder[];
  parent?: Folder;

  constructor(name: string, parent?: Folder) {
    this.name = name;
    this.children = [];
    this.parent = parent;
  }

  /**
   * Add a child to the folder.
   * @param child The child to add.
   * @returns True if the child was added, false if it was already present.
   */
  addChild(child: Folder): boolean {
    if (this.children.includes(child)) {
      return false;
    }
    this.children.push(child);
    child.parent = this;
    return true;
  }

  /**
   * Remove a child from the folder.
   * @param child The child to remove.
   * @returns True if the child was removed, false if it wasn't present.
   */
  removeChild(child: Folder): boolean {
    const index = this.children.indexOf(child);
    if (index === -1) {
      return false;
    }
    this.children.splice(index, 1);
    child.parent = undefined;
    return true;
  }
}

アルゴリズムの実装

CodeWhisperer を使えば、よく知られたアルゴリズムを簡単に実装することができます。特定のコーディング問題に適用したいアルゴリズムをCodeWhisperer に伝えるだけで、その通りに実装してくれます。

ユーザの入力 (JavaScript):

const actors = [ ... ];

// Sort the actors by age using the merge sort algorithm.

出力結果:

const actors = [ ... ];

// Sort the actors by age using the merge sort algorithm.
function mergeSort(arr) {
  if (arr.length < 2) {
    return arr;
  }

  const middle = Math.floor(arr.length / 2);
  const left = arr.slice(0, middle);
  const right = arr.slice(middle);

  return merge(mergeSort(left), mergeSort(right));
}

function merge(left, right) {
  const result = [];

  while (left.length && right.length) {
    if (left[0].age < right[0].age) {
      result.push(left.shift());
    } else {
      result.push(right.shift());
    }
  }

  while (left.length) {
    result.push(left.shift());
  }

  while (right.length) {
    result.push(right.shift());
  }

  return result;
}

console.log(mergeSort(actors));

ユニットテストを書く

CodeWhisperer はユニットテストの実装を加速します。私が求めているほとんどの明示的なユニットテストのロジックを実装できるだけでなく、思いつかなかったようなエッジケースのユニットテストを提案してくれることがよくあります。

CodeWhisperer に単体テストを実装させたいときは、まずテストする条件と期待される結果を次の例のように宣言することから始めます。

ユーザの入力 (JavaScript):

describe("Folder.addChild()", () => {
  it("when adding an existing folder should not add duplicate"

出力結果:

describe("Folder.addChild()", () => {
  it("when adding an existing folder should not add duplicate", () => {
    const folder = new Folder("root");
    const child = new Folder("child");
    folder.addChild(child);
    folder.addChild(child);
    expect(folder.children.length).toBe(1);
  });
});

テストを 1 つか 2 つ書くと、CodeWhisperer は明示的なプロンプトがなくても、さらに多くのテストを提案する可能性があります。

ヒント: 私のテストの説明には、1) テストしている関数、2) テストしている条件、3) 期待する結果が含まれていることがわかります。この 3 つの部分から成るパターンに従うことは、CodeWhisperer が高品質のテストロジックを実装するのに必要なコンテキストを確実に得られるようにする素晴らしい方法です。

サンプルデータの作成

私が発見した嬉しいことの 1 つは、CodeWhisperer がダミーデータ、あるいは繰り返しパターンを持つどんなコードでも生成できるということです。例として、以下のリストでは、例として最初の “user” オブジェクトのみを入力しましたが、CodeWhisperer はパターンを続けてくれて役に立ちました。

ユーザの入力 (JavaScript):

const fakeUsers = [
  { name: "User 1", id: "user1" },

出力結果:

const fakeUsers = [
  { name: "User 1", id: "user1" },
  { name: "User 2", id: "user2" },
  { name: "User 3", id: "user3" },  
  { name: "User 4", id: "user4" },
  { name: "User 5", id: "user5" },
  { name: "User 6", id: "user6" }
]

以下に示すようなランダムでもっともらしい値を生成するのにも使えます。

ユーザの入力 (JavaScript):

const fakeUsers = [
  { name: "Sally", id: "user1" },

出力結果:

const fakeUsers = [
  { name: "Sally", id: "user1" },
  { name: "Bob", id: "user2" },
  { name: "Joe", id: "user3" },
  { name: "Jane", id: "user4" },
  { name: "Jill", id: "user5" },
  { name: "Jack", id: "user6" }
]

正規表現の簡略化

CodeWhisperer は(まだ)自然言語をカスタム正規表現に変換することはできませんが、一般的に使用される正規表現をたくさん知っています。これにより、これらの正規表現を必要なときにすぐに利用できるようになり、時間を節約できます。

ここでは有名かつ複雑だが、よく使われる正規表現を見てみましょう。

ユーザの入力 (JavaScript):

/**
 * Function that validates whether a string is a valid email address.
 */

出力結果:

/**
 * Function that validates whether a string is a valid email address.
 */
function validateEmail(email: string): boolean {
  const re =
    /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
  return re.test(String(email).toLowerCase());
}

サードパーティーのコードライブラリをより早く学習

CodeWhisperer は、なじみのないライブラリ、モジュール、またはフレームワークを使用しているときに、学習を早めるのに役立ちます。以下の例では、API から gzip で圧縮された値を取得し、それをコードの他の部分が利用できる値に変換するユーティリティ関数を作成する必要がありました。「pako」ライブラリが役に立つことはわかっていましたが、使い方がわかりませんでした。インポートステートメントと目的を説明したコメントを用いて CodeWhisperer にコードを生成させました。

import pako from "pako";

/**
 * Accepts a base64-encoded, gzip-compressed JSON string and returns
 * a parsed JSON object.
 */

出力結果:

import pako from "pako";

/**
 * Accepts a base64-encoded, gzip-compressed JSON string and returns
 * a parsed JSON object.
 */
export function decodeGzipJson(base64String) {
  const compressed = atob(base64String);
  const uncompressed = pako.inflate(compressed, { to: "string" });
  return JSON.parse(uncompressed);
}

コードの文書化

CodeWhisperer は、生成するコードだけでなく、既存のコードに対してもドキュメント文字列やコメントを生成することができます。たとえば、CodeWhisperer に、私が実装したこの FavoritesFilter TypeScriptクラスの matches () メソッドのドキュメントを生成させたいとしましょう(簡潔にするために実装の詳細は省略しています)。

class FavoritesFilter implements IAssetFilter {
  ...
  matches(asset: Asset): boolean {
    ...
  }
}

メソッド名のすぐ上にドキュメンテーションコメントの区切り文字 (/** */) を入力するだけで、CodeWhisperer がドキュメンテーションコメントを生成してくれます。

注: CodeWhisperer をこの方法で使用する場合、 Option + C (Mac) or Alt + C (Windows) を使用して手動でサジェストをトリガーしなければならない場合があります。

class FavoritesFilter implements IAssetFilter {
  ...
  /**
   * Determines whether the asset matches the filter.
   */
  matches(asset: Asset): boolean {
    ...
  }
}

結論

上記のテクニックが、CodeWhisperer がいかに生産性の高いコーダーになれるかについてのアイデアを刺激してくれることを願っています。 CodeWhisperer をインストール して、これらの時間を節約するテクニックを自分のプロジェクトで使い始めましょう。これらの例は表面的なものにすぎません。CodeWhisperer を日々のワークフローに適用し始めるクリエイティブな頭脳が増えれば、新しいテクニックやベストプラクティスが次々と出てくると確信しています。役に立つと思う新しいアプローチを見つけたら、コメントを投稿して発見したことを共有してください。あなたのテクニックが将来の記事となり、CodeWhisperer コミュニティの他の人たちがスーパーパワーを高めるのに役立つかもしれません。

この記事は 10 ways to build applications faster with Amazon CodeWhisperer (記事公開日: 2023 年 4 月 26 日) の翻訳記事です。

翻訳はソリューションアーキテクトの江口が担当しました。