Codelab: 테스트 기반 개발을 가속화하는 Gemini

1. 소개

이 Codelab에서는 코드를 구현하기 전에 테스트를 작성하는 테스트 기반 개발 ( TDD)의 원칙을 소개합니다. Ruby를 사용하여 이 접근 방식을 보여주는 간단한 계산기 앱을 만들어 보겠습니다.

Gemini를 코딩 어시스턴트로 사용하는 방법도 알아봅니다. Gemini는 테스트 사례를 생성하고, 코드 구현을 제안하고, 코드에 대한 설명까지 제공하여 TDD 주기를 가속화하는 데 도움이 됩니다.

마지막으로 Google의 완전 관리형 서버리스 플랫폼인 Cloud Functions에 계산기 앱을 배포하여 앱에 액세스할 수 있도록 하는 방법을 살펴봅니다.

2. 기본 요건

  • 결제가 사용 설정된 Google Cloud 프로젝트
  • 웹브라우저

프로젝트 만들기

Gemini API 사용 설정

  • Gemini Marketplace로 이동하여 API를 사용 설정합니다. gcloud를 사용하여 API를 사용 설정할 수도 있습니다.
gcloud services enable cloudaicompanion.googleapis.com --project PROJECT_ID

Cloud Functions API 사용 설정

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

Cloud Shell 활성화

  • 필요한 언어가 사전 설치되어 제공되는 Google Cloud 콘솔에서 실행되는 명령줄 환경인 Cloud Shell을 사용하겠습니다. Cloud 콘솔에서 오른쪽 상단에 있는 Cloud Shell 활성화를 클릭합니다.

6757b2fb50ddcc2d.png

  • Cloud Shell에 연결되면 인증이 완료되었고 프로젝트가 해당 프로젝트 ID로 설정된 것을 확인할 수 있습니다. Cloud Shell에서 다음 명령어를 실행하여 인증되었는지 확인합니다.
gcloud auth list
  • Cloud Shell에서 다음 명령어를 실행하여 gcloud 명령어가 프로젝트를 알고 있는지 확인합니다.
gcloud config list project
  • 프로젝트가 설정되지 않은 경우 다음 명령어를 사용하여 설정합니다.
gcloud config set project <YOUR_PROJECT_ID>

gcloud 명령어 및 사용법은 문서를 참조하세요.

편집기 열기

  • 이 Codelab에서는 내장된 Cloud 편집기를 사용하겠습니다. Cloud Shell 창에서 오른쪽 상단의 편집기 열기 버튼을 클릭합니다. 그러면 VSCode 편집기가 열립니다.

e5a5e95d543db556.png

Ruby 확장 프로그램 추가

  • 왼쪽 메뉴에서 확장 프로그램 아이콘 999939b067e1d0dc.png을 클릭하고 검색창에 vscode ruby를 입력한 다음 VSCode Ruby 확장 프로그램을 설치합니다.

a6fd4e37b3d847d2.png

3. Gemini 워밍업

LLM은 비결정적입니다. 따라서 이러한 프롬프트를 시도하는 동안 수신되는 응답이 Codelab에 첨부된 스크린샷과 다르게 보일 수 있습니다.

먼저 Gemini에 TDD가 무엇인지 물어보겠습니다. 동일한 Cloud Shell 편집기에서 Gemini와 대화를 시작하려면 다음 단계를 따르세요.

  • 페이지 왼쪽에서 Gemini 아이콘 25fdcae4447d063c.png을 찾으면 왼쪽에 채팅 창이 열립니다.
  • 텍스트 상자에 Enter a prompt here라고 입력할 수 있습니다.

5e09b0fb6a1b44dd.png

프롬프트:

What is Test Driven Development?

대답:

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

TDD와 그 이점에 대해 간략하게 소개합니다.

이제 Gemini에 Ruby가 무엇인지 물어봅시다.

프롬프트:

What is Ruby?

대답:

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

Ruby가 무엇인지, Ruby를 언어로 사용할 경우의 이점에 대해 설명합니다.

4. 프로젝트 설정

이제 간단한 Sinatra 앱을 만들어 보겠습니다.

  • 빈 폴더를 만들어 보겠습니다. 원하는 이름을 지정할 수 있습니다. 이 Codelab에서는 gemini-tdd이라고 하겠습니다. Cloud Editor의 왼쪽 탐색 탭에서 /home/<YOUR-USERNAME>/ 아래에 폴더를 만듭니다.

d1d920b074cd7c79.png

  • 방금 만든 폴더를 엽니다. 가장 왼쪽 메뉴에서 아이콘 1d080370a3ccad53.png을 클릭하고 파일 ->을 클릭합니다. 폴더를 엽니다.
  • 이 루트 폴더에 앱의 시작점으로 사용할 새 Ruby 파일을 만들어 보겠습니다. 원하는 이름을 지정할 수 있습니다. 이 Codelab에서는 app.rb라고 합니다. 7beab8d21c59eee7.png
  • 또한 루트 폴더에 Gemfile도 추가해 보겠습니다. Gemfile에 관해 Gemini에 질문하는 것도 좋습니다.
  • 테스트 사례를 작성하기 위한 app_test.rb 파일도 생성합니다.

5. Gemini 기반 구현

이제 Gemini에 수행하려는 작업에 관한 컨텍스트를 제공하고 동일한 테스트 사례를 생성하도록 요청하겠습니다. Gemini 채팅 프롬프트에서 다음 프롬프트를 복사합니다.

프롬프트:

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.

대답:

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

이 계산기는 숫자 두 개를 더하기 위한 계산기 앱의 샘플 테스트 사례가 제공됩니다. 또한 테스트에 필요한 종속 항목 minitest/autorun도 가져왔습니다. 콘텐츠를 app_test.rb에 복사해 보겠습니다. 이제 이 테스트를 실행해 보겠습니다. 작성된 코드가 없기 때문에 확실히 실패합니다.

Gemini에 이 테스트를 실행하는 방법을 물어보겠습니다.

프롬프트:

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

대답:

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.

이제 테스트를 실행해 보겠습니다. 탐색기 탭에서 app_test.rb을 마우스 오른쪽 버튼으로 클릭하고 'Open in Integrated Terminal'을 클릭합니다.

66b4bb9598c1feca.png

app_test.rb 파일과 동일한 폴더에 있는지 확인합니다. cd 명령어를 사용하여 이 위치로 이동하지 않습니다. 터미널에서 Gemini가 반환한 명령어를 실행합니다.

ruby app_test.rb

다음과 같은 오류가 발생합니다.

NameError: uninitialized constant Calculator

Gemini에 편집기에서 바로 수정하는 방법을 요청해 보겠습니다. Cloud Shell 편집기의 탐색창에서 채팅 아이콘을 클릭하고 아래 프롬프트를 요청합니다.

프롬프트:

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

대답:

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에 Calculator라는 클래스가 없으며 클래스를 만들어야 한다고 합니다. Calculator 클래스를 만드는 코드도 제공합니다. 이 코드를 사용해 보겠습니다. 탐색기 탭에서 app.rb을 열고 Gemini가 제공한 코드를 복사합니다. app.rb에서 콘텐츠를 수정하는 동안 Gemini에서 자동 완성으로 몇 가지 제안을 받을 수 있습니다. 수락하려면 tab를 누르고 수락하려면 Esc를 눌러야 합니다.

이제 테스트를 다시 실행해 보겠습니다. 통합 터미널에서 다음 명령어를 입력합니다.

ruby app_test.rb

하지만 동일한 오류('NameError: uninitialized constant Calculator')가 계속 발생합니다. Gemini에 문제 해결 방법을 물어볼까요?

6. Gemini를 사용한 반복적 TDD

프롬프트:

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

대답:

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

Google에 제공한 답변은 위와 동일할 수도 있고 그렇지 않을 수도 있습니다. 이제 app.rb에 계산기 클래스가 정의되어 있음을 Gemini에 명시적으로 알려 보겠습니다 .

프롬프트:

Calculator class is defined in app.rb already.

대답:

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"

계산기 클래스가 정의된 위치에 app.rb를 가져오라는 Gemini의 응답을 받았습니다. 프롬프트를 2~3번 반복해야 올바른 응답을 얻는 경우도 있지만, 익숙해지면 나아질 것입니다. Gemini의 응답으로 require "./app"이 표시될 수도 있습니다. app_test.rb의 app.rb에 다음을 추가하고 동일한 테스트를 다시 실행해 보겠습니다.

이때 app_test.rb가 다음과 같아야 합니다.

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

프로젝트 폴더의 Cloud Shell 터미널에서 아래 명령어를 실행합니다.

ruby app_test.rb

모두 순조롭게 진행되면 테스트를 통과한 것입니다. 그래서 TDD 접근 방식을 사용하여 매우 간단한 Ruby 앱을 개발했으며 Gemini의 도움을 받았습니다. 프롬프트 응답은 항상 동일하지는 않으며 이는 LLM 모델의 특성입니다. Gemini에서 더 많은 계산기 연산을 얻을 수 있지만 전반적으로 방금 따랐던 것과 동일한 프로세스가 작동합니다.

7. Cloud Functions에 앱 배포

이제 Gemini에 이를 Cloud 함수에 배포하도록 요청합니다.

프롬프트:

Let's deploy this app to Cloud Functions

대답:

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에서 Cloud Functions UI를 사용하여 이를 수동으로 배포하는 방법을 설명합니다. 하지만 하고 싶지 않아요. 통합 터미널에서 바로 실행할 수 있는 gcloud 명령어를 Gemini에 요청해 보겠습니다.

프롬프트:

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

대답:

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

터미널에서 Gemini가 제공한 gcloud 명령어를 실행해 보겠습니다.

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

다음과 같은 오류가 발생합니다.

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

Gemini의 도움을 받아 오류를 해결해 보세요.

프롬프트:

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

대답:

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

터미널에서 bundle install를 실행하여 Gemfile.lock를 만들어 보겠습니다 . 명령어를 실행한 후 탐색기 탭을 확인하면 Gemfile.lock가 표시됩니다 .

Cloud Functions에 다시 배포해 보겠습니다. 터미널에서 동일한 배포 명령어를 실행합니다.

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

다음과 같은 오류가 추가로 발생합니다.

"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. Ruby용 함수 프레임워크

Gemini에 오류에 관해 질문해 보겠습니다.

프롬프트:

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

대답:

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

기본적으로 앱에는 functions_framework gem이 없습니다. 계속해서 Gemfile에 다음 줄을 추가하겠습니다.

gem "functions_framework"

이제 터미널에서 bundle install를 실행합니다. 'Gemfile에 명시적 전역 리소스가 없습니다.'라는 오류가 표시될 수도 있고 표시되지 않을 수도 있습니다. 에서 자세한 내용을 확인하실 수 있습니다. 이 오류가 발생하면 Gemfile의 첫 번째 줄에 다음이 있는지 확인합니다.

source "https://rubygems.org"

그런 다음 터미널에서 bundle install를 다시 실행합니다. 이제 배포 명령어를 다시 실행해 보겠습니다.

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

이제 다음 오류가 표시됩니다.

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

이 문제를 해결하기 위해 Gemini의 Generate Code 기능을 사용해 보겠습니다. 계산기 앱 코드가 이미 있는 탐색기 탭에서 app.rb를 열어 보겠습니다. app.rb의 첫 번째 줄에 FunctionsFramework를 입력한 다음 '.'를 입력합니다. 몇 가지 제안사항은 회색 텍스트로 표시됩니다.

9e17476a4a586433.png

추천을 사용하려면 Tab 키를 누르세요. 제안이 수락되면 아래와 같은 제안이 더 많이 표시됩니다.

f3c35d1539789acc.png

추가 제안을 수락하려면 Tab 키를 누르세요. 따라서 app.rb는 다음과 같아야 합니다.

함수 이름을 add에서 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

Cloud Functions 앱의 진입점을 만들었으며 편집기에서 Gemini의 코드 제안을 사용하는 방법도 배웠습니다. 이제 앱을 다시 배포해 보겠습니다.

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

모든 것이 잘 진행되면 배포가 진행되고 앱이 호스팅되는 URL을 볼 수 있습니다. 이제 추가 결과를 반환하도록 app.rb를 약간 수정해 보겠습니다. 최종 app.rb는 다음과 같습니다.

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. 엔드 투 엔드 테스트

URL을 열고 아래와 같이 쿼리 매개변수 ab를 전달합니다.

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

응답은 "Result: 5"과 같이 표시됩니다. 계산기에는 많은 연산이 있습니다. 이 앱을 확장하여 이러한 작업도 실행하고 Gemini의 도움을 받을 수 있습니다.

10. 결론

오늘 Gemini의 도움을 받아 TDD 접근 방식을 사용하여 Ruby 앱을 개발하는 방법을 살펴봤습니다. 아시다시피 Gemini는 다양한 결과를 제공할 수 있지만, 친숙하지 않은 언어로 개발 프로세스를 가속화하는 데 도움이 될 뿐만 아니라 학습 속도를 높이는 데 도움이 되는 함수나 스니펫을 표시할 수 있습니다.

경험과 관계없이 모든 개발자는 개발 과정에서 Gemini의 도움을 받을 수 있습니다. 개발용이 아니라면 Gemini를 사용하여 기존 코드를 설명할 수도 있고, 기존 코드에 대한 테스트를 생성해 달라고 요청할 수도 있습니다. 이 작업은 제게는 가장 지루한 일입니다. 승인

Gemini와 함께 즐겁게 코딩해 보세요.