Potencia tu flujo de trabajo de desarrollo con Gemini Code Assist

1. Introducción

e5b98fd4e417c877.png

En este codelab, verás cómo Gemini Code Assist puede asistirte en etapas clave del ciclo de vida del desarrollo de software (SDLC), como el diseño, la compilación, la prueba y la implementación. Diseñaremos y desarrollaremos una aplicación completa y, luego, la implementaremos en Google Cloud.

Compilaremos una API y una aplicación para realizar búsquedas en las diferentes sesiones de un evento técnico. Cada sesión tendrá un título, resumen, duración, categorías y uno o más oradores.

Actividades

  • Diseñar, compilar, probar e implementar una aplicación web basada en una especificación de OpenAPI desde cero

Qué aprenderás

  • Cómo usar Gemini Code Assist para generar una especificación de OpenAPI
  • Cómo usar las funciones de generación de código de Gemini Code Assist para desarrollar una aplicación de Flask en Python para la especificación de OpenAPI
  • Cómo usar Gemini Code Assist para generar un frontend web para la aplicación de Flask en Python
  • Cómo usar Gemini Code Assist para obtener asistencia con la implementación de la aplicación en Google Cloud Run
  • Usar las funciones de Gemini Code Assist, como la Explicación de código y la generación de casos de prueba, mientras compilas y pruebas la aplicación

Requisitos

  • Navegador web Chrome
  • Una cuenta de Gmail
  • Un proyecto de Cloud con la facturación habilitada
  • Gemini Code Assist habilitado para tu proyecto de Cloud

Este lab está dirigido a desarrolladores de todos los niveles, incluidos principiantes. Aunque la aplicación de muestra está en lenguaje Python, no es necesario que sepas programar en ese lenguaje para entender lo que se hace. Nos enfocaremos en familiarizarte con las capacidades de Gemini Code Assist.

2. Configurar Gemini Code Assist

En esta sección, se explica todo lo que debes hacer para comenzar este lab.

Habilita Gemini Code Assist en el IDE de Cloud Shell

Para el resto del codelab, usaremos el IDE de Cloud Shell, un entorno de desarrollo completamente administrado y basado en Code OSS. Debemos habilitar y configurar Code Assist en el IDE de Cloud Shell. Sigue estos pasos:

  1. Visita ide.cloud.google.com. Es posible que el IDE tarde un poco en aparecer, así que ten paciencia y acepta las opciones de configuración predeterminadas. Si ves algunas instrucciones para configurar el IDE, complétalas con la configuración predeterminada.
  2. Haz clic en el botón Cloud Code - Acceder en la barra de estado de la parte inferior como se muestra. Autoriza el complemento según las instrucciones. Si ves "Cloud Code (ningún proyecto)" en la barra de estado, selecciónalo y elige el proyecto específico de Google Cloud de la lista de proyectos con los que planeas trabajar.

6f5ce865fc7a3ef5.png

  1. Haz clic en el botón Code Assist en la esquina inferior derecha como se muestra y selecciona una última vez el proyecto de Google Cloud correcto. Si se te solicita que habilites la API de Cloud AI Companion, hazlo y continúa.
  2. Una vez que selecciones tu proyecto de Google Cloud, asegúrate de poder verlo en el mensaje de estado de Cloud Code en la barra de estado y de tener habilitada Code Assist en la barra de estado, como se muestra a continuación:

709e6c8248ac7d88.png

Gemini Code Assist está listo para que lo uses

3. Configura Firestore

Cloud Firestore es una base de datos de documentos completamente administrada y sin servidores que usaremos como backend para los datos de nuestra aplicación. Los datos de Cloud Firestore se estructuran en colecciones de documentos.

Debemos crear una colección llamada sessions en nuestra base de datos predeterminada de Firestore. Esta colección contendrá datos de muestra (documentos) que luego usaremos en nuestra aplicación.

Abre la terminal desde tu IDE de Cloud Shell a través del menú principal, como se muestra a continuación:

f1535e14c9beeec6.png

Debemos crear una colección con el nombre sessions. Esto contendrá una lista de documentos de sesión de muestra. Cada documento tendrá los siguientes atributos:

  1. title: string
  2. category: un arreglo de strings
  3. speakers: matriz de cadenas
  4. duration: string
  5. summary: cadena

Para propagar esta colección con datos de muestra, copiaremos un archivo que los contenga en un bucket de tu propio proyecto, desde donde podrás importar la colección con el comando gcloud firestore import.

Inicialización de la base de datos de Firestore

Visita la página de Firestore en la consola de Cloud.

Si no inicializaste una base de datos de Firestore antes en el proyecto, crea la base de datos default. Durante la creación de la base de datos, usa los siguientes valores:

  • Modo de Firestore: Native
  • Ubicación: Elige Region como Tipo de ubicación y selecciona la región adecuada para tu aplicación. Toma nota de esta ubicación, ya que la necesitarás en el siguiente paso para determinar la ubicación del bucket.
  • Crea la base de datos.

504cabdb99a222a5.png

Ahora, crearemos la colección sessions siguiendo los pasos que se indican a continuación:

  1. Crea un bucket en tu proyecto con el comando gsutil que se proporciona a continuación. En el siguiente comando, reemplaza la variable <PROJECT_ID> por el ID de tu proyecto de Google Cloud. Reemplaza <BUCKET_LOCATION> por un nombre de región que corresponda al área geográfica de tu base de datos predeterminada de Firestore (como se indicó en el paso anterior); podría ser US-WEST1, EUROPE-WEST1, ASIA-EAST1 :
gsutil mb -l <BUCKET-LOCATION> gs://<PROJECT_ID>-my-bucket
  1. Ahora que creamos el bucket, debemos copiar la exportación de la base de datos que preparamos en este bucket, antes de poder importarla a la base de datos de Firebase. Usa el comando que se proporciona a continuación:
gsutil cp -r gs://sessions-master-database-bucket/2024-03-26T09:28:15_95256  gs://<PROJECT_ID>-my-bucket

Ahora que tenemos los datos para importar, podemos avanzar al último paso, que consiste en importarlos a la base de datos de Firebase (default) que creamos.

  1. Usa el comando de gcloud que se proporciona a continuación:
gcloud firestore import gs://<PROJECT_ID>-my-bucket/2024-03-26T09:28:15_95256

La importación tardará unos segundos. Cuando esté lista, puedes validar tu base de datos de Firestore y la colección. Para ello, visita https://console.cloud.google.com/firestore/databases, selecciona la base de datos default y la colección sessions como se muestra a continuación:

d3e294d46ba29cd5.png

Esto completa la creación de la colección de Firestore que usaremos en nuestra aplicación.

4. Crea la plantilla de aplicación

Crearemos una aplicación de ejemplo (una aplicación Python Flask) que utilizaremos en el resto del codelab. Esta aplicación realizará búsquedas en las sesiones que se ofrecen en una conferencia técnica.

Lleve a cabo los pasos siguientes:

  1. Haz clic en el nombre del proyecto de Google Cloud en la barra de estado que aparece a continuación.

f151759c156c124e.png

  1. Aparecerá una lista de opciones. Haz clic en Aplicación nueva en la lista que aparece a continuación.

91ea9836f38b7f74.png

  1. Selecciona Cloud Run application (este será el entorno de ejecución de nuestra app).
  2. Selecciona la plantilla de aplicación Python (Flask): Cloud Run.
  3. Asígnale un nombre a la aplicación y guárdala en la ubicación que prefieras.
  4. Una notificación confirmará que se creó tu aplicación y se abrirá una nueva ventana con tu aplicación cargada, como se muestra a continuación. Se abrirá un archivo README.md. Ahora puedes cerrar esa vista.

aaa3725b17ce27cf.png

5. Interactúa con Gemini Code Assist

Para los fines de este lab, usaremos Gemini Code Assist Chat disponible en el IDE de Cloud Shell como parte de la extensión de Cloud Code en VS Code. Puedes abrirlo haciendo clic en el botón de asistencia de código en la barra de navegación izquierda. Busca el ícono de Code Assist a489f98a34898727.png en la barra de herramientas de navegación de la izquierda y haz clic en él.

Esto abrirá el panel de chat de Code Assist dentro del IDE de Cloud Shell y podrás chatear con Code Assist.

14ad103efaa0ddaa.png

Observa el ícono de la papelera en la parte superior, que es la forma de restablecer el contexto del historial de chat de Code Assist. Ten en cuenta también que esta interacción por chat es contextual a los archivos en los que estás trabajando en el IDE.

6. Diseño de API

El primer paso será usar Gemini Code Assist durante la fase de Diseño. En este paso, generaremos una especificación de OpenAPI para las entidades (sesiones técnicas en un evento) en las que queremos buscar.

Muestra la siguiente instrucción:

Generate an Open API spec that will allow me to retrieve all sessions, sessions by category, session by id. Each session has the following attributes: id, title, list of speakers, list of categories, summary and duration.

Esto debería generar una especificación de OpenAPI para realizar búsquedas en sesiones a través de varios parámetros de consulta. A continuación, se ofrece el ejemplo de especificación:

openapi: 3.0.0
info:
 title: Sessions API
 description: This API allows you to retrieve all sessions, sessions by category, and session by id.
 version: 1.0.0
servers:
 - url: https://sessions.example.com
paths:
 /sessions:
   get:
     summary: Get all sessions
     operationId: getSessions
     responses:
       '200':
         description: OK
         content:
           application/json:
             schema:
               type: array
               items:
                 $ref: '#/components/schemas/Session'
 /sessions/{id}:
   get:
     summary: Get session by id
     operationId: getSessionById
     parameters:
       - name: id
         in: path
         required: true
         description: The id of the session
         schema:
           type: string
     responses:
       '200':
         description: OK
         content:
           application/json:
             schema:
               $ref: '#/components/schemas/Session'
 /sessions/categories/{category}:
   get:
     summary: Get sessions by category
     operationId: getSessionsByCategory
     parameters:
       - name: category
         in: path
         required: true
         description: The category of the sessions
         schema:
           type: string
     responses:
       '200':
         description: OK
         content:
           application/json:
             schema:
               type: array
               items:
                 $ref: '#/components/schemas/Session'
components:
 schemas:
   Session:
     type: object
     properties:
       id:
         type: string
         description: The id of the session
       title:
         type: string
         description: The title of the session
       speakers:
         type: array
         items:
           type: string
         description: The list of speakers for the session
       categories:
         type: array
         items:
           type: string
         description: The list of categories for the session
       summary:
         type: string
         description: The summary of the session
       duration:
         type: string
         description: The duration of the session

Puedes observar que la especificación tiene lo siguiente:

  • Un esquema definido para el Tipo de sesión.
  • Se definieron varias rutas de acceso a la API:
  • /sessions
  • /sessions/{id}
  • /sessions/categories/{category}

Crea un archivo llamado sessionsapi.yaml en la carpeta superior y copia el contenido desde la ventana de chat de Code Assist usando la opción “insert in current file option” (el botón +) y mantén el archivo abierto en el IDE de Cloud Shell.

En este punto, puedes ver una función interesante de Gemini Code Assist: cita. Esta información se muestra al desarrollador cuando el código generado cita de forma directa con otra fuente, como el código abierto existente. Ofrece la fuente y la licencia para que el desarrollador decida qué hacer con él.

Suponiendo que estamos de acuerdo con el contenido generado, ahora podemos usar este documento de especificación para generar una aplicación de Flask en Python.

7. Genera la aplicación

Ahora, le pediremos a Code Assist que genere la aplicación. Proporciona la siguiente instrucción con el archivo sessionsapi.yaml abierto.

Generate a Python Application using the Flask framework, based on the sessionsapi.yaml file. This application uses a local in memory list of sessions. Do not use any Flask extensions.

Esto debería proporcionarte un esqueleto para la aplicación de Flask en Python que se basa en la funcionalidad y las rutas de acceso que se especificaron en el archivo de especificación de OpenAPI.

El código de la aplicación de Flask en Python que se proporciona debe ser similar al siguiente:

from flask import Flask, jsonify, request

app = Flask(__name__)

sessions = [
    {
        "id": "1",
        "title": "Session 1",
        "speakers": ["Speaker 1", "Speaker 2"],
        "categories": ["Category 1", "Category 2"],
        "summary": "This is a summary of session 1.",
        "duration": "1 hour",
    },
    {
        "id": "2",
        "title": "Session 2",
        "speakers": ["Speaker 3", "Speaker 4"],
        "categories": ["Category 3", "Category 4"],
        "summary": "This is a summary of session 2.",
        "duration": "1 hour 30 minutes",
    },
]

@app.route('/sessions', methods=['GET'])
def get_sessions():
    return jsonify(sessions)

@app.route('/sessions/<id>', methods=['GET'])
def get_session_by_id(id):
    session = next((session for session in sessions if session['id'] == id), None)
    if session is None:
        return jsonify({}), 404
    return jsonify(session)

@app.route('/sessions/categories/<category>', methods=['GET'])
def get_sessions_by_category(category):
    sessions_by_category = [session for session in sessions if category in session['categories']]
    return jsonify(sessions_by_category)

if __name__ == '__main__':
    app.run()

Hay un archivo app.py existente generado como parte del paso anterior. Simplemente reemplaza su contenido con el código que genera Code Assist y guarda el archivo.

Queremos cambiar la línea app.run() para usar el puerto 8080, la dirección de host 0.0.0.0 y también ejecutar en modo de depuración durante la ejecución local.A continuación, se muestra una manera de hacerlo. En primer lugar, destaquemos o seleccionemos la línea:

app.run()

Luego, en la interfaz del chat de Code Assist, escribe el mensaje: Explain this..

Esto debería mostrar una explicación detallada de esa línea en particular. A continuación, se muestra un ejemplo:

58ec896a32a4fb68.png

Ahora, usa la siguiente instrucción:

update the code to run the application on port 8080, host address 0.0.0.0, and in debug mode

El código sugerido que se genera debería ser el siguiente:

app.run(host='0.0.0.0', port=8080, debug=True)

Recuerda actualizar el archivo app.py con este fragmento.

Ejecuta la aplicación de manera local

Ahora ejecutemos la aplicación de forma local para validar sus requisitos según lo que habíamos comenzado.

El primer paso será crear un entorno virtual de Python con las dependencias del paquete de Python en requirements.txt para que se instalen en el entorno virtual. Para ello, ve a la Paleta de comandos (Ctrl + Mayúsculas + P) en el IDE de Cloud Shell y escribe Crear entorno de Python. Sigue los pasos a continuación para seleccionar un entorno virtual (venv), un intérprete de Python 3.x y el archivo requirements.txt.

Una vez creado el entorno, inicia una nueva ventana de terminal (Ctrl + Mayúsculas +`) y ejecuta el siguiente comando:

python app.py

A continuación, se muestra una ejecución de ejemplo:

(.venv) romin@cloudshell: $ python app.py 
 * Serving Flask app 'app'
 * Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:8080
 * Running on http://10.88.0.3:8080
Press CTRL+C to quit
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 132-247-368

Ahora puedes obtener una vista previa de la API en las siguientes URLs. Suponemos que tu servidor de desarrollo se ejecuta en el puerto 8080. De lo contrario, cámbialo al número de puerto adecuado.

  • https://<host-name>:8080/sessions
  • https://<host-name>:8080/sessions/{id}
  • https://<host-name>:8080/sessions/categories/{category}

Sigue los pasos que se indican a continuación para asegurarte de poder recuperar los datos JSON incluidos en el archivo app.py usando estas URLs:

Abre una nueva ventana de terminal y prueba cualquiera de los siguientes comandos:

curl -X GET http://127.0.0.1:8080/sessions
curl -X GET http://127.0.0.1:8080/sessions/<ID>
curl -X GET http://127.0.0.1:8080/sessions/categories/<CATEGORY_NAME> 

8. Refactorización de código

En lugar de que app.py contenga los datos JSON de muestra hard-coded, es probable que queramos separarlos o extraerlos en otro módulo para poder mantener una separación clara entre el código y los datos. ¡Hagámoslo!

Mantén abierto el archivo app.py y muestra el siguiente mensaje:

Can I improve this code and separate out the sessions data from this app.py file?

Deberías ver algunas sugerencias sobre cómo hacerlo. A continuación, se muestra una sugerencia de muestra que obtuvimos y debería ser similar a ella:

9b9c56cb527dac4c.png

Seguiremos y separaremos nuestros datos en un archivo sessions.py como sugiere Code Assist.

Crea un nuevo archivo llamado sessions.py.

, cuyo contenido es la lista JSON, según nuestros datos generados, se muestra a continuación:

sessions = [
   {
       "id": "1",
       "title": "Session 1",
       "speakers": ["Speaker 1", "Speaker 2"],
       "categories": ["Category 1", "Category 2"],
       "summary": "This is a summary of session 1.",
       "duration": "1 hour",
   },
   {
       "id": "2",
       "title": "Session 2",
       "speakers": ["Speaker 3", "Speaker 4"],
       "categories": ["Category 3", "Category 4"],
       "summary": "This is a summary of session 2.",
       "duration": "1 hour 30 minutes",
   },
]

El archivo app.py ahora está mucho más simple y se muestra a continuación:

from flask import Flask, jsonify, request
from sessions import sessions

app = Flask(__name__)

@app.route('/sessions', methods=['GET'])
def get_sessions():
   return jsonify(sessions.sessions)

@app.route('/sessions/<id>', methods=['GET'])
def get_session_by_id(id):
   session = next((session for session in sessions.sessions if session['id'] == id), None)
   if session is None:
       return jsonify({}), 404
   return jsonify(session)

@app.route('/sessions/categories/<category>', methods=['GET'])
def get_sessions_by_category(category):
   sessions_by_category = [session for session in sessions.sessions if category in session['categories']]
   return jsonify(sessions_by_category)

if __name__ == '__main__':
   app.run(host='0.0.0.0', port=8080, debug=True)

Asegúrate de poder ejecutar la aplicación de manera local y ejercitar la API con estos cambios refactorizados. Es probable que el servidor de desarrollo de Python continúe ejecutándose, por lo que solo necesitas recuperar los comandos curl del paso anterior.

9. Integración en la colección de Firestore

El siguiente paso es alejarnos de la lista local de JSON en la memoria que tenemos para nuestras sesiones y conectar nuestra aplicación a la colección sessions en la base de datos de Firestore, que creamos al comienzo de este codelab.

Mantén abierto el archivo sessions.py y muestra el siguiente mensaje:

Can you further refactor the sessions.py code to read from a Firestore database that has a collection named sessions. The collection has the same attributes as the session object that we have defined. Use the Python module google-cloud-firestore. 

Recibimos la siguiente sugerencia para leer todas las sesiones de la colección de Firestore:

import google.cloud.firestore

# Create a Firestore client
db = google.cloud.firestore.Client()

# Get the sessions collection
sessions_collection = db.collection("sessions")

# Create a list of sessions
sessions = []

# Iterate over the documents and add them to the list
for doc in sessions_collection.stream():
   session = doc.to_dict()
   session["id"] = doc.id
   sessions.append(session)

Incorpora el código en sessions.py.

Si ejecutas el servidor de desarrollo de Flask de manera local, es posible que tu aplicación se haya cerrado e indica que no se encontró el módulo de Python.

Por ejemplo, puedes preguntarle a Code Assist qué módulo de Python debe agregarse al archivo requirements.txt, de la siguiente manera:

Which Python package needs to be installed to make the firestore code work?

Esto te proporcionará el nombre del módulo de Python (p.ej., google-cloud-firestore). Agrégalo al archivo requirements.txt.

Deberás volver a crear el entorno de Python con el módulo recién agregado (google-cloud-firestore). Para ello, ejecuta el siguiente comando en la ventana de la terminal existente:

pip install -r requirements.txt

Vuelve a ejecutar la aplicación (reiníciala con python app.py) y visita la URL de /sessions. Ahora deberías obtener los documentos de muestra que agregamos a la colección sessions.

975d05e6518f1a6a.png

No dudes en consultar otros URI para recuperar sesiones específicas o todas las sesiones de una categoría determinada, como se describió en los pasos anteriores.

10. Explicación del código

Este es un buen momento para usar la función "Explain this" de Gemini Code Assist para comprender bien el código. Puedes ir a cualquiera de los archivos o seleccionar fragmentos específicos de código y pedirle a Code Assist con el siguiente mensaje: Explain this.

Como ejercicio, visita el archivo sessions.py, destaca el código específico de Firestore para obtener la explicación del código. Intenta usar esta función también en otros archivos de tu proyecto, no solo en el código de Python.

11. Genera la aplicación web

Ahora que generamos la API y la integramos a una colección activa de Firestore, vamos a generar un frontend basado en la Web para la aplicación. En este momento, nuestro frontend web mantendrá su funcionalidad al mínimo, es decir, podrá buscar sesiones que pertenezcan a una categoría específica. Ten en cuenta que tenemos una ruta de API para eso, es decir, /sessions/categories/{category}, por lo que nuestra aplicación web debe invocarla y recuperar los resultados.

Analicémoslo de inmediato. Proporciona la siguiente instrucción a Code Assist:

Generate a web application that allows me to search for sessions by category and uses the Flask application that we created. Please use basic HTML, CSS and JS. Embed all the Javascript and CSS code into a single HTML file only.

Esto generará el HTML de la aplicación web con JavaScript y CSS incorporados. También se te pedirá que agregues una nueva ruta al archivo app.py, de modo que cualquier usuario que visite la URL raíz o base verá la página principal. Si no se menciona esa información, pregunta al respecto o usa el fragmento que aparece a continuación:

@app.route('/')
def index():
   return render_template('index.html')

Puedes guardarlo como index.html, pero es posible que tengas una pregunta sobre dónde debe guardarse este archivo (es decir, ¿en qué carpeta?). Podemos hacer una pregunta adicional a Code Assist.

Given that I am using the flask framework, where should I put the index.html file?

Debería darte información clara de que usa el framework render_template, por lo que el archivo index.html deberá colocarse dentro de la carpeta templates. Encontrarás esta carpeta disponible, ya que, al comienzo de este codelab, generamos una aplicación basada en la plantilla de Flask. Como resultado, hay un archivo index.html existente y solo debes reemplazar su contenido por el nuevo que se generó aquí. Code Assist también menciona que debes importar render_template en el archivo app.py.

Guarda el código de la aplicación web en el archivo index.html y recuerda colocarlo en la carpeta templates.

Ejecuta la aplicación de manera local

Ahora ejecutemos la aplicación de forma local para validar sus requisitos según lo que habíamos comenzado.

Asegúrate de que el servidor local de Flask aún se esté ejecutando y no muestre ningún error. En caso de errores, soluciónalos e inicia el servidor.

Una vez que esté en funcionamiento, visita la URL de la página principal de la aplicación. Debería mostrarte el archivo index.html que se entrega de la siguiente manera:

8ca586acc4536879.png

Proporciona una de las categorías de los datos como entrada (p.ej., AI) y haz clic en el botón Search. Se deberían mostrar las sesiones etiquetadas con la categoría AI.

165faded790a6c.png

Un ejercicio opcional es mostrar metadatos adicionales, como la duración, las categorías, los oradores y el resumen de cada una de las sesiones.

12. Generación de casos de prueba

Generamos la API de sesiones y es hora de usar Gemini Code Assist para generar casos de prueba de unidades para las diferentes rutas de API.

Mantén abierto el archivo app.py y muestra el siguiente mensaje:

Generate unit test cases for app routes. Use unittest module.

Obtuvimos la siguiente respuesta:

import unittest
from app import app

class FlaskAppTestCase(unittest.TestCase):

    def test_index(self):
        tester = app.test_client()
        response = tester.get('/')
        self.assertEqual(response.status_code, 200)

    def test_get_sessions(self):
        tester = app.test_client()
        response = tester.get('/sessions')
        self.assertEqual(response.status_code, 200)

    def test_get_session_by_id(self):
        tester = app.test_client()
        response = tester.get('/sessions/1')
        self.assertEqual(response.status_code, 200)

    def test_get_sessions_by_category(self):
        tester = app.test_client()
        response = tester.get('/sessions/categories/category1')
        self.assertEqual(response.status_code, 200)

if __name__ == '__main__':
    unittest.main()

Crea un archivo llamado tests.py con el código anterior.

Nota sobre la generación de casos de prueba

Es posible que veas una lista de códigos diferente a la anterior, lo que podría causar algunos problemas en la ejecución de los casos de prueba. Por ejemplo, vimos que, en algunas de nuestras ejecuciones, se perdieron los siguientes fragmentos clave de código:

from app import app

El código anterior es necesario para importar la app de Flask existente en la que invocaremos los casos de prueba.

if __name__ == '__main__':

`unittest.main()`

El código anterior es necesario para ejecutar los casos de prueba.

Te recomendamos observar cada uno de los casos de prueba, revisar la assertEqual y otras condiciones en el código generado para asegurarte de que funcione. Dado que los datos son externos en la colección de Firestore, es posible que no tengan acceso a ellos y que usen algunos datos ficticios, por lo que las pruebas podrían fallar. Por lo tanto, modifica tus casos de prueba según corresponda o comenta algunos de los que no necesites de inmediato.

Como demostración, ejecutamos los casos de prueba con el siguiente comando (asegúrate de ejecutar el servidor de desarrollo local, ya que las llamadas se harán a los extremos de la API local):

python tests.py

Obtuvimos el siguiente resultado de resumen:

Ran 4 tests in 0.274s

FAILED (failures=2)

Eso es correcto, ya que el ID de sesión no era correcto en la 3a prueba y no hay una categoría llamada category1

.

Así que ajusta los casos de prueba según corresponda y pruébalo.

13. Desarrollo basado en pruebas

Ahora analicemos cómo agregar un nuevo método de búsqueda en nuestra API de sesiones siguiendo la metodología de desarrollo basado en pruebas (TDD), que consiste en escribir primero los casos de prueba, hacer que fallen por falta de implementación y usar Gemini Code Assist para generar la implementación faltante de modo que la prueba sea exitosa.

Ve al archivo tests.py (suponiendo que corregiste el archivo tests.py para que todas las pruebas sean exitosas). Consulta la siguiente instrucción a Code Assist:

Generate a new test case to search for sessions by speaker

Esto nos proporcionó la siguiente implementación del caso de prueba que insertamos correctamente en el archivo tests.py.

  def test_get_sessions_by_speaker(self):
        tester = app.test_client()
        response = tester.get('/sessions/speakers/speaker1')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json, [sessions.sessions[0], sessions.sessions[1]])

Si ejecutas las pruebas, deberías ver el siguiente error:

$ python tests.py 
.F.
======================================================================
FAIL: test_get_sessions_by_speaker (__main__.FlaskAppTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/romin/hello-world-5/tests.py", line 21, in test_get_sessions_by_speaker
    self.assertEqual(response.status_code, 200)
AssertionError: 404 != 200

----------------------------------------------------------------------
Ran 3 tests in 0.010s

FAILED (failures=1)

Esto se debe a que el caso de prueba invocó la siguiente ruta de acceso (/sessions/speakers/) y no se implementó en app.py.

Solicitamos a Code Assist que nos proporcione una implementación. Ve al archivo app.py y solicita la siguiente instrucción a Code Assist:

Add a new route to search for sessions by a specific speaker

Recibimos la siguiente implementación que sugirió Code Assist y que agregamos al archivo app.py:

@app.route('/sessions/speakers/<speaker>', methods=['GET'])
def get_sessions_by_speaker(speaker):
    sessions_by_speaker = [session for session in sessions.sessions if speaker in session['speakers']]
    return jsonify(sessions_by_speaker)

Revisa el archivo tests.py y modificamos nuestro caso de prueba de la siguiente manera para realizar una verificación rápida:

   def test_get_sessions_by_speaker(self):
       tester = app.test_client()
       response = tester.get('/sessions/speakers/Romin Irani')
       self.assertEqual(response.status_code, 200)
       self.assertEqual(len(response.json), 1)

La prueba se ejecutó correctamente. Lo dejamos como un ejercicio para que examines los casos de prueba generados, los modifiques un poco según los datos que tengas en Firestore y cuentes con los métodos assert* adecuados en los casos de prueba de unidades de Python.

14. Implementa en Google Cloud Run

Ahora que nos sentimos bien con respecto a la calidad de nuestro desarrollo, el último paso será implementar esta aplicación en Google Cloud Run. Pero tal vez, para tomar buenas medidas, debamos preguntarle a Code Assist si nos olvidamos de algo. Con app.py abierto, envía la siguiente instrucción :

Is there something here I should change before I deploy to production?

Qué bueno que preguntaste, ya que nos olvidamos de desactivar la marca de depuración :

2f87ed3a811fb218.png

Como se indica, desactiva la depuración y pide ayuda a Gemini Code Assist con el comando gcloud que se puede usar para implementar la aplicación en Cloud Run directamente desde la fuente (sin tener que compilar un contenedor primero).

Muestra la siguiente instrucción:

I would like to deploy the application to Cloud Run directly from source. What is the gcloud command to do that?

Prueba con algunas variaciones de la instrucción anterior. Otra opción que probamos fue la siguiente:

I would like to deploy this application to Cloud Run. I don't want to build a container image locally but deploy directly from source to Cloud Run. What is the gcloud command for that?

Idealmente, deberías obtener el siguiente comando gcloud:

gcloud run deploy sessions --source .

Es posible que también veas lo siguiente:

gcloud run deploy <service-name> --source . \
—-platform managed \
—-allow-unauthenticated

Ejecuta el comando anterior desde la carpeta raíz de la aplicación. Cuando se te solicite region, selecciona us-central1 y, cuando se te solicite permitir unauthenticated invocations, elige Y. Es posible que también se te solicite que habilites las APIs de Google Cloud, como Artifact Registry, Cloud Build y Cloud Run, y el permiso para crear un repositorio de Artifact Registry. Otorga el permiso.

El proceso de implementación tardará unos 2 minutos en completarse, así que ten paciencia.

Una vez que se implemente correctamente, verás la URL de servicio de Cloud Run. Visita esa URL pública y deberías ver que la misma aplicación web se implementa y ejecuta correctamente.

c5322d0fd3e0f616.png

¡Felicitaciones, buen trabajo!

15. Usa Cloud Logging (opcional)

Podemos incorporar registros en nuestra aplicación de modo que los registros de la aplicación estén centralizados en uno de los servicios de Google Cloud (Cloud Logging). Luego, podemos usar la función de Gemini sobre observabilidad para comprender también las entradas de registro.

Para ello, primero tendremos que usar una biblioteca de Cloud Logging para Python existente de Google Cloud y usarla para registrar mensajes informativos, de advertencia o de error (según el nivel de registro o gravedad).

Primero intentemos pedirle eso a Code Assist. Prueba la siguiente instrucción:

How do I use the google-cloud-logging package in Python?

Deberías obtener una respuesta con información al respecto, como se muestra a continuación:

2472e1ccaf8a217d.png

Agreguemos instrucciones de registro a la función que busca sesiones por categoría.

Primero, agrega el paquete de Python google-cloud-logging al archivo requirements.txt.

A continuación, se muestra un fragmento de código que muestra cómo integramos el código para implementar el registro:

...
from google.cloud import logging
...
app = Flask(__name__)

# Create a logger
logger = logging.Client().logger('my-log')

@app.route('/sessions/categories/<category>', methods=['GET'])
def get_sessions_by_category(category):
   logger.log_text(f"Fetching sessions with category {category}")
   sessions_by_category = [session for session in sessions.sessions if category in session['categories']]
   logger.log_text(f'Found {len(sessions_by_category)} sessions with category {category}')
   return jsonify(sessions_by_category)

# # Other App Routes

Vuelve a implementar el servicio en Cloud Run con el mismo comando que en la sección anterior y, una vez implementado, ejecuta algunas llamadas al extremo /sessions/categories/<category>.

Ve a la Cloud Console → Logs Explorer.

59e297577570695.png

...y deberías poder filtrar estas instrucciones de registro como se muestra a continuación:

914f1fb6cac30a89.png

Puedes hacer clic en cualquiera de las instrucciones de registro, expandirla y, luego, hacer clic en Explain this log entry, que usará Gemini para explicar la entrada de registro. Ten en cuenta que, si no habilitaste Gemini para Google Cloud, se te pedirá que habilites la API de Cloud AI Companion. Sigue las instrucciones que se indican.

A continuación, se proporciona una respuesta de muestra:

8fC9783910fa92cc.png

16. Felicitaciones

¡Felicitaciones! Compilaste con éxito una aplicación desde cero y usaste Gemini Code Assist en varios aspectos del SDLC, incluidos el diseño, la compilación, las pruebas y la implementación.

¿Qué sigue?

Consulta algunos codelabs sobre los siguientes temas:

Documentos de referencia