Codelab: Gemini para acelerar el desarrollo basado en pruebas

1. Introducción

En este codelab, se presentan los principios del desarrollo basado en pruebas ( TDD), con los que se escriben pruebas antes de implementar código. Compilaremos una aplicación de calculadora simple con Ruby mostrando este enfoque.

También aprenderás a usar Gemini, como tu asistente de programación. Gemini ayudará a acelerar el ciclo del TDD generando casos de prueba, sugiriendo implementaciones de código y hasta proporcionando explicaciones de este.

Por último, verás cómo implementar la app de calculadora en Cloud Function, la plataforma sin servidores completamente administrada de Google, para que tu app sea accesible.

2. Requisitos previos

  • Un proyecto de Google Cloud con la facturación habilitada
  • Un navegador web

Crea tu proyecto

Habilita la API de Gemini

  • Navega a Gemini Marketplace para habilitar la API. También puedes usar gcloud para habilitar la API:
gcloud services enable cloudaicompanion.googleapis.com --project PROJECT_ID

Habilitar la API de Cloud Functions

gcloud services enable cloudfunctions.googleapis.com --project PROJECT_ID

Activar Cloud Shell

  • Usarás Cloud Shell, un entorno de línea de comandos que se ejecuta en la consola de Google Cloud y que viene precargado con los lenguajes necesarios instalados. En la consola de Cloud, haz clic en Activar Cloud Shell en la esquina superior derecha:

6757b2fb50ddcc2d.png

  • Una vez que te conectes a Cloud Shell, deberías ver que ya te autenticaste y que el proyecto está configurado con tu ID del proyecto. En Cloud Shell, ejecuta el siguiente comando para confirmar que estás autenticado:
gcloud auth list
  • Ejecuta el siguiente comando en Cloud Shell para confirmar que el comando de gcloud conoce tu proyecto:
gcloud config list project
  • Si tu proyecto no está configurado, usa el siguiente comando para hacerlo:
gcloud config set project <YOUR_PROJECT_ID>

Consulta la documentación para ver los comandos y el uso de gcloud.

Abrir editor

  • En este codelab, usaremos el editor de Cloud incorporado. En la ventana de Cloud Shell, haz clic en el botón Abrir editor en la esquina superior derecha. Se abrirá el editor de VSCode.

e5a5e95d543db556.png

Agregar extensión de Ruby

  • En el menú lateral izquierdo, haz clic en el ícono de extensiones 999939b067e1d0dc.png, escribe vscode ruby en la barra de búsqueda y, luego, instala la extensión VSCode para Ruby.

a6fd4e37b3d847d2.png

3. Práctica de Gemini

Los LLM no son deterministas. Por lo tanto, mientras pruebas estas instrucciones, es posible que la respuesta que recibas sea diferente de las de las capturas de pantalla adjuntas en el codelab.

Primero, le pregunté a Gemini qué es un TDD. Para comenzar a conversar con Gemini en el mismo editor de Cloud Shell donde estamos, sigue estos pasos:

  • En el lado izquierdo de la página, busca el ícono de Gemini 25fdcae4447d063c.png. Esto abrirá la ventana de chat en el lado izquierdo.
  • Puedes comenzar a escribir en el cuadro de texto que dice Enter a prompt here.

5e09b0fb6a1b44dd.png

Instrucción:

What is Test Driven Development?

Respuesta:

Test-driven development (TDD) is a software development methodology that requires developers to write automated tests before writing any production code. This helps ensure the code is correct and meets the requirement.
....

Se presenta una breve introducción del TDD y sus beneficios.

Ahora, pregúntale a Gemini qué es Ruby:

Instrucción:

What is Ruby?

Respuesta:

Ruby is a general-purpose, interpreted, object-oriented programming language. It is designed to be easy to read and write. Ruby is dynamically typed, meaning that the type of a variable is not declared and can change during execution.
....

Explica qué es Ruby y cuáles son los beneficios de usar Ruby como lenguaje.

4. Configuración del proyecto

Ahora, comencemos creando una app de Sinatra simple.

  • Creemos una carpeta vacía. Puedes asignarle el nombre que desees. Para este codelab, la llamaremos gemini-tdd. En el editor de Cloud en el lado izquierdo, en la pestaña Explorador, crea una carpeta en /home/<YOUR-USERNAME>/

d1d920b074cd7c79.png

  • Abramos la carpeta que creamos. En el menú de la izquierda, haz clic en el ícono 1d080370a3ccad53.png y, luego, en Archivo ->. Abrir carpeta
  • Creemos un nuevo archivo Ruby en esta carpeta raíz que funcionará como punto de partida para la app. Puedes asignarle el nombre que desees. En este codelab, la llamaremos app.rb. 7beab8d21c59eee7.png
  • Agreguemos un Gemfile a la carpeta raíz. También te recomendamos preguntarle a Gemini sobre Gemfile.
  • También crearemos un archivo app_test.rb para escribir nuestros casos de prueba.

5. Implementación impulsada por Gemini

Ahora comencemos por darle a Gemini algo de contexto sobre lo que estamos tratando de hacer y pedirle que genere casos de prueba para lo mismo. Copia la siguiente instrucción en la instrucción de chat de Gemini.

Instrucción:

Answer as a software engineer with Ruby expertise. We want to build a Ruby calculator application with a test driven development approach. Let's start by writing some tests for the calculator app using minitest gem.

Respuesta:

Here is a simple test for a calculator app that adds two numbers:
require "minitest/autorun"

describe "Calculator" do
  it "should add two numbers" do
    calculator = Calculator.new
    assert_equal 5, calculator.add(2, 3)
  end
end
This test uses the assert_equal method to verify that the result of the add method is correct. 
.....

Te proporciona un caso de prueba de muestra para la app de Calculadora, es decir, para sumar dos números. También importó la dependencia minitest/autorun requerida para las pruebas. Copiemos el contenido en app_test.rb. Intentemos ejecutar esta prueba ahora. como no tenemos ningún código escrito, fallará con seguridad.

Pregunta a Gemini cómo ejecutar esta prueba.

Instrucción:

How do we run the tests written in app_test.rb using ruby command?

Respuesta:

To run the tests written in app_test.rb using the ruby command, you can use the following steps:
1.Make sure that you are in the same directory as the app_test.rb file.
2.Open a terminal window.
3.Type the following command:
ruby app_test.rb
This will run all of the tests in the app_test.rb file and report the results.

Avancemos y ejecutemos la prueba. Haz clic con el botón derecho en app_test.rb en la pestaña Explorador y, luego, en “Open in Integrated Terminal”

66b4bb9598c1feca.png

Asegúrate de estar en la misma carpeta que el archivo app_test.rb; de lo contrario, usa el comando cd para llegar a ella. En la terminal, ejecuta el comando que devuelve Gemini:

ruby app_test.rb

Verás el siguiente error:

NameError: uninitialized constant Calculator

Vamos a preguntarle a Gemini cómo solucionar el problema directamente desde el editor. Haz clic en el ícono de chat en el panel de navegación del editor de Cloud Shell y pide la siguiente instrucción:

Instrucción:

NameError: uninitialized constant Calculator. Give me Calculator class code.

Respuesta:

The error you are getting is because you have not defined the Calculator class. You need to define the Calculator class before you can use it in your tests.
Here is the code for the Calculator class:
Class Calculator
  def add(a, b)
    a + b
  end
end
Once you have defined the Calculator class, you can run the tests again and they will pass.
.....

Gemini nos dice que no tenemos una clase llamada Calculator y que debemos crear una. También nos proporcionó el código para crear la clase Calculator. Continuemos y usemos este código. Abre app.rb desde la pestaña Explorador y copia el código que le proporcionó Gemini. Mientras modificas el contenido en app.rb, es posible que recibas algunas sugerencias de Gemini como autocompletar. Debes presionar tab si deseas aceptarlo o Esc si no lo deseas.

Ahora, vuelva a ejecutar la prueba. Escribe el siguiente comando en tu terminal integrada:

ruby app_test.rb

Sin embargo, seguirás viendo el mismo error "NameError: uninitialized constant Calculator". Pregúntale a Gemini cómo solucionarlo.

6. TDD iterativo con Gemini

Instrucción:

I am still getting this error: "NameError: uninitialized constant Calculator".

Respuesta:

The error you are getting is because you have not defined the Calculator class. You need to define the Calculator class before you can use it in your tests.
Here is the code for the Calculator class:
class Calculator
  def add(a, b)
    a + b
  end

  def subtract(a, b)
    a - b
  end

  def multiply(a, b)
    a * b
  end

  def divide(a, b)
    a / b
  end
end
....

Nos dio alguna respuesta, puede o no ser la misma que la anterior. Por lo tanto, le digamos a Gemini explícitamente que tenemos la clase Calculadora definida en app.rb .

Instrucción:

Calculator class is defined in app.rb already.

Respuesta:

I see that the Calculator class is defined in the app.rb file. However, you are getting the NameError error because you are trying to use the Calculator class in the app_test.rb file without requiring the app.rb file.
To fix this, you need to add the following line to the top of the app_test.rb file:
require_relative "app"

Obtuvimos la respuesta de Gemini para importar el app.rb donde está definida la clase Calculadora. A veces, se necesitan 2 o 3 iteraciones de instrucciones para obtener la respuesta correcta, pero a medida que te familiarices con ella, mejorará. Ten en cuenta que es posible que también veas el mensaje requerir "./app" en su lugar, como respuesta de Gemini. Agreguemos esto a app.rb en app_test.rb y ejecutemos la misma prueba nuevamente.

Asegúrate de que, en este punto, tu app_test.rb se vea de la siguiente manera:

require "minitest/autorun"
require "./app"

describe "Calculator" do
  it "should add two numbers" do
    calculator = Calculator.new
    assert_equal 5, calculator.add(2, 3)
  end
end

Ejecuta el siguiente comando desde la terminal de Cloud Shell en la carpeta del proyecto:

ruby app_test.rb

Si todo sale bien, la prueba debería ser exitosa. Por lo tanto, desarrollamos una app de Ruby muy simple usando el enfoque de TDD y obtuvimos ayuda de Gemini. Las respuestas a las instrucciones no serán las mismas todo el tiempo y eso se debe a la naturaleza de los modelos de LLM. Es posible que obtengas más operaciones de la Calculadora de Gemini, pero, en general, debería funcionar el mismo proceso que acabamos de seguir.

7. Implementa la app en Cloud Functions

Ahora, pidamos a Gemini que implemente esto en Cloud Function:

Instrucción:

Let's deploy this app to Cloud Functions

Respuesta:

To deploy your app to Cloud Functions, you can use the following steps:
1.Create a new Cloud Functions project.
2.Create a new Cloud Function.
3.Set the trigger for the Cloud Function to be an HTTP request.
4.Set the entry point for the Cloud Function to be the app method in the app.rb file.
5.Deploy the Cloud Function.
Once you have deployed the Cloud Function, you can test it by sending an HTTP request to the function's URL. 
....

Gemini explica cómo implementarlo de forma manual con la IU de Cloud Functions. Pero no quiero hacer eso. Pídele a Gemini que nos dé el comando gcloud, que puedo ejecutar directamente desde la terminal integrada.

Instrucción:

How do I deploy this app to Cloud Functions gen2 using the gcloud command?

Respuesta:

...
Here are the specific commands you can use to deploy your app to Cloud Functions using the gcloud command:

gcloud functions deploy calculator --runtime ruby32 --trigger-http --entry-point app

This command will create a new Cloud Function called calculator that is triggered by an HTTP request and uses the app method in the app.rb file as the entry point.

Once the Cloud Function is deployed, you can test it by sending an HTTP request to the function's URL. For example, you can use the following command to send a request to the function:

curl -X POST -H "Content-Type: application/json" -d '{"a": 2, "b": 3}' https://REGION-PROJECT_ID.cloudfunctions.net/calculator

Ejecutaremos en la terminal el comando de gcloud que proporciona Gemini.

gcloud functions deploy calculator --runtime ruby32 --trigger-http --entry-point app

Verás el siguiente error:

"ERROR: (gcloud.functions.deploy) OperationError: code=3, message=Build failed: Could not find Gemfile.lock file in your app. Please make sure your bundle is up to date before deploying.; Error ID: 7916f05c"

Pídele ayuda a Gemini para corregir el error.

Instrucción:

ERROR: (gcloud.functions.deploy) OperationError: code=3, message=Build failed: Could not find Gemfile.lock file in your app. Please make sure your bundle is up to date before deploying.; Error ID: 7916f05c

Respuesta:

It looks like you're trying to deploy a function to Cloud Functions, but you don't have a Gemfile.lock file in your app. To fix this, run the following command in your app directory:
bundle install
This will create a Gemfile.lock file that lists all of the gems that your app uses.
...

Ejecutemos bundle install en la terminal, que creará Gemfile.lock . Después de ejecutar el comando, verifica la pestaña del explorador. Deberías poder ver Gemfile.lock.

Intentemos volver a realizar la implementación en Cloud Functions. Ejecuta el mismo comando de implementación en la terminal:

gcloud functions deploy calculator --runtime ruby32 --trigger-http --entry-point app

Verás el siguiente error:

"ERROR: (gcloud.functions.deploy) OperationError: code=3, message=Build failed: unable to execute functions-framework-ruby; please ensure a recent version of the functions_framework gem is in your Gemfile; Error ID: 89ae7dda"

8. Functions Framework para Ruby

Pregúntale a Gemini sobre el error:

Instrucción:

ERROR: (gcloud.functions.deploy) OperationError: code=3, message=Build failed: unable to execute functions-framework-ruby; please ensure a recent version of the functions_framework gem is in your Gemfile; Error ID: 89ae7dda

Respuesta:

It looks like you're trying to deploy a function to Cloud Functions, but the build is failing because the functions_framework gem is not in your Gemfile. To fix this, add the following line to your Gemfile:

gem "functions_framework"

Then, run the following command to install the gem:

bundle install

Once the gem is installed, you can try deploying your function again.
....

En esencia, nos falta la gema functions_framework en nuestra app. Agreguemos esta línea a nuestro Gemfile:

gem "functions_framework"

Ahora ejecuta bundle install en la terminal. Es posible que aparezca o no el error "No hay recursos globales explícitos en Gemfile". de Google Cloud. Si te encuentras con esto, asegúrate de tener lo siguiente como primera línea del Gemfile:

source "https://rubygems.org"

Luego, vuelve a ejecutar bundle install desde la terminal. Ahora, ejecutemos de nuevo el comando de implementación:

gcloud functions deploy calculator --runtime ruby32 --trigger-http --entry-point app --project PROJECT_ID

Ahora verás el siguiente error:

"ERROR: (gcloud.functions.deploy) OperationError: code=3, message=Build failed: failed to verify function target "app" in source "app.rb": Undefined function: "app"; Error ID: e12ab0f9"

Para resolver este problema, probemos la función Generate Code de Gemini. Abramos app.rb desde la pestaña Explorador, donde ya tenemos el código de la app de Calculadora. En app.rb, en la primera línea, comienza a escribir FunctionsFramework y, luego, escribe ".". Verás algunas sugerencias en texto gris :

9e17476a4a586433.png

Presiona Tab para aceptar la sugerencia. Una vez que lo aceptes, verás más sugerencias como las que se muestran a continuación:

f3c35d1539789acc.png

Presiona Tab para aceptar más sugerencias. Por lo tanto, tu app.rb debería verse de la siguiente manera:

( Cambia el nombre de la función de add a app).

require "functions_framework"

FunctionsFramework.http "app" do |request|
 a = request.params["a"].to_i
 b = request.params["b"].to_i
 Calculator.new.add(a, b)
end

class Calculator
 def add(a, b)
   a + b
 end
end

Acabamos de crear el punto de entrada para la app de Cloud Functions y aprendimos a usar la sugerencia de código de Gemini en el editor. Ahora intentemos volver a implementar la app.

gcloud functions deploy calculator --runtime ruby32 --trigger-http --entry-point app --project PROJECT_ID

Si todo sale bien, se debería completar la implementación y deberías poder ver la URL en la que está alojada tu app. Genial, modifiquemos un poco el app.rb para mostrar el resultado de la adición. El archivo app.rb final debería verse de la siguiente manera:

require "functions_framework"

FunctionsFramework.http "app" do |request|
 a = request.params["a"].to_i
 b = request.params["b"].to_i
 calculator = Calculator.new
 add = calculator.add(a, b)
 "Result: #{add}"
end

class Calculator
 def add(a, b)
   a + b
 end
end

9. Prueba de extremo a extremo

Abre la URL y pasa los parámetros de consulta a y b como se muestra a continuación:

https://[APP-URL]/?a=2&b=3

Deberías poder ver la respuesta como : "Result: 5". La Calculadora tiene muchas operaciones. Puedes extender esta app para que también realice esas tareas y obtener ayuda de Gemini.

10. Conclusión

Vimos cómo desarrollar una app de Ruby hoy mismo con el enfoque de TDD con la ayuda de Gemini. Como notaste, Gemini puede darte diferentes resultados, pero definitivamente puede ayudar a acelerar el proceso de desarrollo en un lenguaje que quizás no conozcas más y aun así mostrarte funciones o fragmentos para acelerar tu curva de aprendizaje.

Cualquier desarrollador ( sin importar la experiencia) puede solicitar ayuda de Gemini en su proceso de desarrollo. Si no es para desarrollar, puedes usar Gemini para explicar el código existente, puedes pedirle que genere pruebas para el código existente, que es el trabajo más aburrido para mí al menos 🙂

¡Feliz codificación con Gemini!