Atelier de programmation: Gemini pour accélérer le développement basé sur les tests

1. Introduction

Cet atelier de programmation présente les principes du développement piloté par les tests ( TDD, Test-Driven Development), qui consiste à écrire des tests avant d'implémenter le code. Nous allons créer une application de calculatrice simple à l'aide de Ruby pour illustrer cette approche.

Vous apprendrez également à utiliser Gemini comme assistant de programmation. Gemini vous aidera à accélérer le cycle TDD en générant des cas de test, en suggérant des implémentations de code et même en fournissant des explications sur le code.

Enfin, vous apprendrez à déployer l'application de calculatrice sur Cloud Functions, la plate-forme sans serveur entièrement gérée de Google, pour rendre votre application accessible.

2. Prérequis

  • Un projet Google Cloud avec la facturation activée
  • Un navigateur Web

Créer un projet

Activer l'API Gemini

  • Accédez à la Marketplace Gemini pour activer l'API. Vous pouvez également utiliser gcloud pour activer l'API :
gcloud services enable cloudaicompanion.googleapis.com --project PROJECT_ID

Activer l'API Cloud Functions

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

Activer Cloud Shell

  • Vous allez utiliser Cloud Shell, un environnement de ligne de commande exécuté dans la console Google Cloud et fourni avec les langages requis. Dans la console Cloud, cliquez sur Activer Cloud Shell en haut à droite :

6757b2fb50ddcc2d.png

  • Une fois connecté à Cloud Shell, vous êtes en principe authentifié, et le projet est défini avec votre ID de projet. Exécutez la commande suivante dans Cloud Shell pour vérifier que vous êtes authentifié :
gcloud auth list
  • Exécutez la commande suivante dans Cloud Shell pour vérifier que la commande gcloud connaît votre projet :
gcloud config list project
  • Si votre projet n'est pas défini, utilisez la commande suivante pour le définir :
gcloud config set project <YOUR_PROJECT_ID>

Consultez la documentation pour connaître les commandes gcloud ainsi que leur utilisation.

Ouvrir l'éditeur

  • Pour cet atelier de programmation, nous allons utiliser l'éditeur Cloud intégré. Dans la fenêtre Cloud Shell, cliquez sur le bouton "Ouvrir l'éditeur" en haut à droite. Un éditeur VSCode s'ouvre.

e5a5e95d543db556.png

Ajouter l'extension Ruby

  • Dans le menu de gauche, cliquez sur l'icône Extensions 999939b067e1d0dc.png, saisissez vscode ruby dans la barre de recherche, puis installez l'extension VSCode Ruby.

a6fd4e37b3d847d2.png

3. Échauffement Gemini

Les LLM ont un comportement non déterministe. Ainsi, lorsque vous testez ces requêtes, il se peut que la réponse que vous recevez soit différente de celles qui figurent sur les captures d'écran jointes à l'atelier de programmation.

Commençons par demander à Gemini ce qu'est un TDD. Pour commencer à discuter avec Gemini dans l'éditeur Cloud Shell où nous nous trouvons, procédez comme suit :

  • Sur la gauche de la page, recherchez l'icône Gemini 25fdcae4447d063c.png. La fenêtre de chat s'ouvre alors sur la gauche.
  • Vous pouvez commencer à saisir du texte dans la zone de texte Enter a prompt here.

5e09b0fb6a1b44dd.png

Prompt :

What is Test Driven Development?

Response:

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.
....

Il vous présente brièvement le TDD et ses avantages.

Demandons maintenant à Gemini ce qu'est Ruby :

Prompt :

What is Ruby?

Response:

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.
....

Il explique ce qu'est Ruby et les avantages de l'utiliser comme langage.

4. Configuration du projet

Commençons par créer une application Sinatra simple.

  • Créons un dossier vide. Vous pouvez lui donner le nom de votre choix. Nous l'appellerons gemini-tdd pour cet atelier de programmation. Dans l'éditeur cloud, sur la gauche, sous l'onglet "Explorateur", créez un dossier sous /home/<YOUR-USERNAME>/.

d1d920b074cd7c79.png

  • Ouvrons le dossier que nous venons de créer. Dans le menu le plus à gauche, cliquez sur l'icône 1d080370a3ccad53.png, puis sur Fichier > Ouvrir le dossier.
  • Créons un fichier Ruby dans ce dossier racine, qui servira de point de départ pour l'application. Vous pouvez lui donner le nom de votre choix. Dans cet atelier de programmation, nous l'appellerons app.rb. 7beab8d21c59eee7.png
  • Ajoutons également un Gemfile dans le dossier racine. Il est également conseillé de demander à Gemini des informations sur Gemfile.
  • Nous allons également créer un fichier app_test.rb pour écrire nos scénarios de test.

5. Implémentation basée sur Gemini

Commençons par donner à Gemini un peu de contexte sur ce que nous essayons de faire et demandons-lui de générer des cas de test. Copiez le prompt suivant dans la discussion Gemini.

Prompt :

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.

Response:

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. 
.....

Il vous fournit un exemple de scénario de test pour l'application Calculatrice, c'est-à-dire pour l'addition de deux nombres. Il a également importé la dépendance requise minitest/autorun pour les tests. Copions le contenu dans app_test.rb. Essayons d'exécuter ce test maintenant. Comme nous n'avons écrit aucun code, il échouera à coup sûr.

Demandons à Gemini comment exécuter ce test.

Prompt :

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

Response:

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.

Alors, allons-y et exécutons le test. Effectuez un clic droit sur app_test.rb dans l'onglet "Explorateur", puis cliquez sur "Ouvrir dans le terminal intégré".

66b4bb9598c1feca.png

Assurez-vous de vous trouver dans le même dossier que le fichier app_test.rb. Si ce n'est pas le cas, utilisez la commande cd pour y accéder. Dans le terminal, exécutez la commande renvoyée par Gemini :

ruby app_test.rb

L'erreur suivante s'affiche :

NameError: uninitialized constant Calculator

Demandons à Gemini comment résoudre le problème directement depuis l'éditeur. Cliquez sur l'icône de chat dans le volet de navigation de l'éditeur Cloud Shell, puis saisissez la requête ci-dessous :

Prompt :

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

Response:

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 nous indique que nous n'avons pas de classe appelée Calculator et que nous devons en créer une. Il nous a également fourni le code permettant de créer la classe Calculator. Utilisons ce code. Ouvrez app.rb depuis l'onglet "Explorateur" et copiez-y le code fourni par Gemini. Lorsque vous modifiez le contenu dans app.rb, Gemini peut vous faire des suggestions d'autocomplétion. Appuyez sur tab si vous souhaitez les accepter ou sur Esc si vous ne le souhaitez pas.

Maintenant, exécutons à nouveau le test. Saisissez la commande suivante dans votre terminal intégré :

ruby app_test.rb

Toutefois, vous rencontrerez toujours la même erreur "NameError: uninitialized constant Calculator". Demandons à Gemini comment la résoudre.

6. TDD itératif avec Gemini

Prompt :

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

Response:

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
....

Il nous a donné une réponse, qui peut être la même que ci-dessus ou non. Indiquons donc explicitement à Gemini que la classe Calculator est définie dans app.rb .

Prompt :

Calculator class is defined in app.rb already.

Response:

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"

Nous avons obtenu la réponse de Gemini pour importer le fichier app.rb où la classe Calculator est définie. Il peut parfois falloir deux ou trois itérations de requêtes pour obtenir la bonne réponse, mais vous vous améliorerez au fur et à mesure. Veuillez noter que vous pouvez également voir require "./app" dans la réponse de Gemini. Ajoutons cela à app.rb dans app_test.rb et exécutons à nouveau le même test.

Veuillez vous assurer que votre fichier app_test.rb se présente comme suit :

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

Exécutez la commande ci-dessous à partir du terminal Cloud Shell dans le dossier du projet :

ruby app_test.rb

Si tout se passe bien, le test devrait réussir. Nous avons donc développé une application Ruby très simple à l'aide de l'approche TDD et nous avons sollicité l'aide de Gemini. Les réponses aux requêtes ne seront pas toujours les mêmes, car c'est la nature même des modèles LLM. Vous pouvez obtenir plus d'opérations de la calculatrice de Gemini, mais le processus que nous venons de suivre devrait fonctionner dans l'ensemble.

7. Déployer l'application sur Cloud Functions

Demandons maintenant à Gemini de déployer cela sur Cloud Functions :

Prompt :

Let's deploy this app to Cloud Functions

Response:

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 explique comment le déployer manuellement à l'aide de l'interface utilisateur de Cloud Functions. Mais je ne veux pas faire ça. Demandons à Gemini de nous donner la commande gcloud que je peux exécuter directement depuis le terminal intégré.

Prompt :

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

Response:

...
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

Exécutons la commande gcloud fournie par Gemini dans le terminal.

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

L'erreur suivante s'affiche :

"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"

Demandons à Gemini de nous aider à corriger l'erreur.

Prompt :

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

Response:

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.
...

Exécutons bundle install dans le terminal, ce qui créera Gemfile.lock . Après avoir exécuté la commande, vérifiez l'onglet de l'explorateur. Vous devriez voir le Gemfile.lock.

Essayons de déployer à nouveau sur Cloud Functions. Exécutez la même commande de déploiement dans le terminal :

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

L'erreur suivante s'affiche :

"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 pour Ruby

Demandons à Gemini de nous en dire plus sur l'erreur :

Prompt :

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

Response:

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 gros, il nous manque le gem functions_framework dans notre application. Ajoutons cette ligne dans notre Gemfile :

gem "functions_framework"

Exécutez maintenant bundle install dans le terminal. Il est possible que le message d'erreur "No explicit global resource in Gemfile" (Aucune ressource globale explicite dans Gemfile) s'affiche ou non. Si vous rencontrez ce problème, assurez-vous que la première ligne de votre fichier Gemfile est la suivante :

source "https://rubygems.org"

Ensuite, exécutez à nouveau bundle install depuis le terminal. Exécutons à nouveau la commande de déploiement :

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

L'erreur suivante s'affiche :

"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"

Pour résoudre ce problème, essayons la fonctionnalité Generate Code de Gemini. Ouvrons app.rb depuis l'onglet "Explorer", où se trouve déjà le code de l'application Calculatrice. Dans app.rb, sur la première ligne, commencez à saisir FunctionsFramework , puis saisissez ".". Des suggestions s'affichent en gris :

9e17476a4a586433.png

Appuyez sur la touche de tabulation pour accepter la suggestion. Une fois la suggestion acceptée, vous verrez d'autres suggestions comme celles ci-dessous :

f3c35d1539789acc.png

Appuyez sur la touche de tabulation pour accepter d'autres suggestions. Votre fichier app.rb devrait se présenter comme suit :

( Renommez la fonction add en 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

Nous venons de créer le point d'entrée de l'application Cloud Functions et nous avons également appris à utiliser la suggestion de code de Gemini dans l'éditeur. Essayons maintenant de déployer à nouveau l'application.

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

Si tout se passe bien, le déploiement devrait se dérouler sans problème et vous devriez pouvoir voir l'URL où votre application est hébergée. Bien, modifions un peu app.rb pour renvoyer le résultat de l'addition. Votre fichier app.rb final doit se présenter comme suit :

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. Tests de bout en bout

Ouvrez l'URL et transmettez les paramètres de requête a et b comme indiqué ci-dessous :

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

La réponse devrait s'afficher comme suit : "Result: 5". Une calculatrice peut effectuer de nombreuses opérations. Vous pouvez étendre cette application pour effectuer ces tâches et demander l'aide de Gemini.

10. Conclusion

Nous avons vu comment développer une application Ruby aujourd'hui en utilisant l'approche TDD avec l'aide de Gemini. Comme vous l'avez remarqué, Gemini peut vous donner des résultats différents, mais il peut certainement vous aider à accélérer le processus de développement dans une langue que vous ne maîtrisez peut-être pas, et vous montrer des fonctions ou des extraits pour accélérer votre courbe d'apprentissage.

Tout développeur ( quel que soit son niveau d'expérience) peut demander l'aide de Gemini pour son processus de développement. Si vous ne souhaitez pas développer, vous pouvez utiliser Gemini pour expliquer le code existant. Vous pouvez également lui demander de générer des tests pour le code existant, ce qui est la tâche la plus ennuyeuse pour moi, du moins 🙂

Bon codage avec Gemini !