Blog de Amazon Web Services (AWS)

10 maneras de desarrollar aplicaciones más rápido con Amazon CodeWhisperer

Por Kris Schultz,
Amazon CodeWhisperer es una herramienta de Inteligencia Artificial Generativa que me da superpoderes para programar. Desde que incorporé CodeWhisperer a mi flujo de trabajo, me he vuelto más rápido, más inteligente e incluso disfruto más al desarrollar aplicaciones. Sin embargo, aprender a usar cualquier herramienta de IA generativa de manera efectiva requiere una mentalidad de principiante y una disposición a aprender nuevas formas de trabajar.

Las mejores prácticas para hacer uso de CodeWhisperer aún están emergiendo. Pero, como explorador temprano, he descubierto varias técnicas que me han permitido obtener lo máximo de esta increíble herramienta. En este artículo, voy a compartir estas técnicas contigo, utilizando ejemplos prácticos para ilustrar cómo CodeWhisperer puede mejorar tu flujo de trabajo de programación. Exploraré:

  • Escribir menos código
  • Generar funciones
  • Generar funciones usando comentarios
  • Generar clases
  • Implementar algoritmos
  • Escribir pruebas unitarias
  • Crear datos de prueba
  • Simplificar expresiones regulares
  • Aprender librerías de terceros de manera más rápida
  • Documentar código

Antes de comenzar

Si deseas probar estas técnicas, necesitaras usar un editor de código con la extensión AWS Toolkit instalada. VS Code, AWS Cloud9 y la mayoría de los editores de JetBrains funcionarán. Consulta los recursos de introducción de CodeWhisperer para obtener instrucciones de configuración.

CodeWhisperer presentará sugerencias automáticamente a medida que escribas. Si no recibes ninguna sugerencia, siempre puedes activarla manualmente con el método abreviado Option + C (Mac) o Alt + C (Windows). En ocasiones, CodeWhisperer también te presentará varias sugerencias entre las que elegir. Puedes pulsar las teclas → y ← para recorrer todas las sugerencias disponibles.

Los ejemplos de este artículo están escritos en JavaScript. Sin embargo, las técnicas que voy a demostrar son igualmente adecuadas para muchos de los lenguajes de programación compatibles con CodeWhisperer. ¡Ahora, pasemos a los ejemplos!

Escribir menos

En el nivel más básico, CodeWhisperer se puede utilizar como un auto completado poderoso, que reduce significativamente la necesidad de escribir al escribir líneas o bloques de código individuales. Para usar CodeWhisperer de esta manera, simplemente escribe el código como lo harías normalmente. CodeWhisperer te hará sugerencias automáticas a medida que escribes. Acepta las sugerencias cuando sean útiles e ignora las sugerencias cuando no lo sean. En mi experiencia, usar CodeWhisperer de esta manera reduce mi tiempo de escritura en un 50% o más.

CodeWhisperer fue entrenado con diversos orígenes de datos, incluidos los de Amazon y los de código fuente abierto. CodeWhisperer fue entrenado y validado para generar sugerencias de código a partir de comentarios en inglés. Dada la variedad de ejemplos en el conjunto de datos de entrenamiento, es posible que CodeWhisperer proporcione sugerencias de código a partir de comentarios escritos en idiomas distintos del inglés; sin embargo, este no es un caso de uso admitido. Es por esto que los siguientes ejemplos son en inglés.

Generar funciones

Generación automática de funciones a partir de firmas

Los programadores más experimentados utilizan nombres claros y descriptivos para sus funciones y parámetros. Si sigues esta práctica en tu código, CodeWhisperer tendrá todo el contexto que necesita para implementar muchas funciones por ti.

Después de introducir la firma de la función a continuación, CodeWhisperer me genera el cuerpo de la función.

Entrada del usuario (JavaScript):

function standardDeviation(numbers)
JavaScript

Resultado:

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);
}
JavaScript

Generar funciones a partir de comentarios

A veces, una buena firma de función por sí sola no es suficiente para transmitir el comportamiento deseado de una función. En esos casos, puedes usar un comentario de código detallado como mensaje para CodeWhisperer. Te recomiendo usar el delimitador de comentarios de documentos de tu lenguaje de programación cuando utilices esta técnica.

Entrada del usuario (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. */
JavaScript

Resultado:

/** * 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(", ");
}
JavaScript

Generar Clases

Puedes generar implementaciones de clases completas o parciales a partir de un solo comentario de código. El comentario debe describir las propiedades y los comportamientos clave de la clase. A menudo, todo lo que se necesita son descripciones sencillas.

Entrada del usuario (TypeScript):

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

Resultado:

Después de escribir el comentario de bloque anterior, CodeWhisperer proporciona múltiples sugerencias, incluyendo la siguiente implementación, ¡completa con comentarios de documentación para cada método!

/** * 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;
  }
}
TypeScript

Implementar algoritmos

CodeWhisperer te permite implementar algoritmos conocidos con facilidad. Simplemente dile a CodeWhisperer qué algoritmo deseas aplicar a un problema de codificación en particular y lo hará.

Entrada del usuario (JavaScript):

const actors = [ ... ];

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

Resultado:

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));
JavaScript

Escribir pruebas unitarias

CodeWhisperer acelera la implementación de las pruebas unitarias. No solo es capaz de implementar la lógica para la mayoría de las pruebas unitarias explícitas que solicito, sino que a menudo sugiere pruebas unitarias para casos extremos que ni siquiera se me habían ocurrido.

Cuando quiero que CodeWhisperer implemente una prueba unitaria, empiezo con una declaración de la condición que estoy probando y el resultado esperado, como en el siguiente ejemplo.

Entrada del usuario (JavaScript):

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

Resultado:

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);
  });
});
JavaScript

Después de haber escrito una o dos pruebas, es probable que CodeWhisperer sugiera más pruebas, incluso sin indicaciones explícitas.

Consejo: Te darás cuenta de que la descripción de mi prueba incluye 1) la función que estoy probando, 2) la condición que estoy probando y 3) cuál espero que sea el resultado. Seguir este patrón de tres partes es una excelente manera de garantizar que CodeWhisperer tenga el contexto que necesita para implementar una lógica de prueba de alta calidad.

Crear datos de prueba

Una de las funcionalidades más interesantes que he descubierto con CodeWhisperer es que puede generar datos ficticios, o realmente cualquier código que tenga un patrón repetitivo. Como ejemplo, para la siguiente lista ingresé solo el primer objeto “user” como ejemplo, y CodeWhisperer continúo creando el los datos

Entrada del usuario (JavaScript):

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

Resultado:

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

Incluso funciona para generar valores aleatorios pero plausibles como los “nombres” que se ven a continuación.

Entrada del usuario:

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

Resultado:

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" }
]
JavaScript

Simplificar expresiones regulares

Si bien CodeWhisperer no puede traducir el lenguaje natural en expresiones regulares personalizadas (todavía), sí conoce muchas expresiones regulares de uso común. Esto te ahorra tiempo al poner estas expresiones regulares al alcance de tu mano siempre que las necesites.

Veamos una expresión regular notoriamente compleja pero común.

Entrada del usuario  (JavaScript):

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

Resultado:

/** * 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());
}
JavaScript

Aprender librerías de código de terceros más rápido

CodeWhisperer ayuda a acelerar mi aprendizaje cuando estoy usando una biblioteca, módulo o framework desconocidos. En el siguiente ejemplo, necesitaba escribir una función auxiliar que tomara un valor comprimido gzip proveniente de una API y lo traduciría en un valor que el resto de mi código pudiera entender. Sabía que la biblioteca “pako” me ayudaría, pero no tenía idea de cómo usarla. Acabo de proveer a CodeWhisperer con una declaración de importación y un comentario describiendo mi objetivo.

Entrada del usuario (Javascript):

import pako from "pako";

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

Resultado:

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);
}
JavaScript

Documentar código

CodeWhisperer tiene cierta capacidad limitada para documentar código mediante la generación de comentarios de documentos simples para funciones individuales. Por ejemplo, digamos que quiero que CodeWhisperer documente el método matches () de esta clase favoritesFilter que he implementado (he omitido algunos detalles de implementación por brevedad).

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

Puedo solamente escribir un delimitador de comentario doc  (/** */) inmediatamente encima del nombre del método y CodeWhisperer generará el cuerpo del comentario doc por mí.

Nota: Al usar CodeWhisperer de esta manera, es posible que tengas que activar manualmente una sugerencia usando la Opción + C (Mac) o Alt + C (Windows).

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

Conclusión

Espero que las técnicas anteriores inspiren ideas sobre cómo CodeWhisperer puede convertirte en un programador más productivo. Instala CodeWhisperer hoy mismo para comenzar a usar estas técnicas de ahorro de tiempo en tus proyectos. Estos ejemplos solo rascan la superficie. A medida que las mentes creativas empiecen a aplicar CodeWhisperer a sus flujos de trabajo diarios, estoy seguro de que seguirán surgiendo nuevas técnicas y mejores prácticas. Si descubres un enfoque novedoso que te resulte útil, publica un comentario para compartir lo que has descubierto. Quizás la técnica llegue a un artículo en el futuro y ayude a otros en la comunidad de CodeWhisperer a mejorar sus superpoderes.

 

 


Acerca del autor

Kris Schultz ha pasado más de 25 años brindando experiencias de usuario atractivas a la vida al combinar tecnologías emergentes con diseño de clase mundial. En su papel de arquitecto especialista en soluciones 3D, Kris ayuda a los clientes a aprovechar los servicios de AWS para impulsar aplicaciones 3D de todo tipo.

 

 

 

 

Traductor

Manuel Quijano es un Arquitecto de Soluciones especializado en IaC, DevOps y Developer Experience en Amazon Web Services radicado en México. Manuel trabaja con clientes de AWS para proporcionar orientación y asistencia técnica en prácticas de DevOps, IaC y mejores prácticas de desarrollo, ayudándoles a mejorar el valor de sus soluciones cuando utilizan AWS.