IBM Bob과 함께하는 AI 페어 프로그래밍

Bob을 AI 페어 프로그래밍 어시스턴트로 활용해 FastAPI To-Do API를 빌드해 보세요 — 요구사항에서 계획, 코드 생성, 테스트, 문서화까지.

AI 페어 프로그래밍을 사용하면 단순히 코드 자동완성만 해주는 도구가 아니라, 계획·코딩·테스트·문서화 등 모든 단계에서 함께하는 어시스턴트와 나란히 소프트웨어를 개발할 수 있습니다. 이 튜토리얼에서는 IBM Bob과 페어를 이루어 주어진 요구사항을 바탕으로 FastAPI To-Do API를 빌드합니다.

요구사항에서 시작해 검토된 계획, 생성된 코드, 구현 설명, 코드 품질 개선, 유닛 테스트, 기술 문서화 순서로 진행합니다. 데이터 저장소는 인메모리 Python 리스트를 사용하므로 별도의 데이터베이스 설정이 필요하지 않습니다.

튜토리얼이 끝나면 컨테이너화된 To-Do API를 완성하고, 각 단계(계획, 생성, 설명, 리팩터링, 테스트, 문서화)에서 페어 프로그래밍 검토 루프를 실습하게 됩니다.

이 튜토리얼은 기본적인 Python과 REST 개념을 알고 AI 어시스턴트와 함께 소프트웨어를 빌드할 때 반복 가능한 검토 루프를 익히고자 하는 개발자를 위한 것입니다. FastAPI 사전 경험은 필요하지 않습니다.

이 튜토리얼은 새 프로젝트에서 전체 빌드 루프를 처음부터 끝까지 다룹니다. 기존 코드베이스에서 대규모 기능을 계획하고 구현하는 방법을 더 깊이 알아보려면 복잡한 기능 계획 및 구현을 참조하세요.

전제 조건

이 튜토리얼을 완료하려면 다음이 필요합니다:

  • Bob IDE 설치 및 설정 완료.
  • 주석에서 코드 생성 — 리터럿 코딩 사용에 대한 기본 이해.
  • 새 컨텍스트 창 만들기 완료. 이 다단계 워크플로에서 Bob의 컨텍스트를 관리하기 위해 필요합니다.
  • Docker 설치 및 실행 중. Bob이 Dockerfile을 생성하므로 Python이나 의존성을 로컬에 설치하지 않고도 컨테이너에서 API를 빌드하고 실행할 수 있습니다.
  • 기본적인 Python 지식.
  • REST API에 대한 기본 이해. FastAPI 사전 경험은 필요하지 않습니다. Bob이 FastAPI 코드를 생성하고 워크플로의 일부로 요청 시 설명해 줍니다.

Bob과 함께하는 AI 페어 프로그래밍 이해

이후 각 단계에서는 계획 수립, 생성, 설명, 리팩터링, 테스트, 문서화를 다룹니다. 모든 단계에서 Bob이 변경을 제안하면 Bob이 적용하기 전에 승인, 거부, 또는 수정합니다.

페어 프로그래밍 워크플로

이 튜토리얼에서는 다음 워크플로를 사용합니다:

요구사항

Bob이 계획 생성

계획 검토 및 개선

Bob이 코드 생성

출력 검토

실행 및 검증

Bob이 구현 설명

Bob이 코드 품질 개선 제안

테스트 생성

문서 생성

작업 공간 설정

Bob을 실행하고, 빈 프로젝트 폴더를 열고, Bob이 파일을 변경하기 전에 승인을 요청하도록 설정합니다.

IBM Bob 실행

IBM Bob IDE를 실행합니다.

Bob 채팅 인터페이스 열기

Bob 채팅 인터페이스가 보이지 않으면, 내비게이션 바 옆의 Bob 아이콘을 선택해 엽니다. Mac에서는 Option + Command + B, Windows 및 Linux에서는 Ctrl + Alt + B를 눌러도 됩니다.

IBM Bob IDE에서 Bob 채팅 패널 열기

빈 프로젝트 폴더 열기

todo-api라는 빈 폴더를 만든 다음 File > Open Folder로 Bob에서 엽니다. Bob이 폴더의 파일 작성자를 신뢰하는지 묻는다면 Yes, I trust the authors를 선택합니다.

Bob은 생성된 애플리케이션을 이 폴더에 작성합니다. 이 튜토리얼에서는 기존 리포지토리가 필요하지 않습니다.

자동 승인 비활성화

Permissions를 열고 자동 승인이 꺼져 있는지 확인합니다. 자동 승인이 꺼진 상태에서 Bob은 파일을 읽거나, 편집하거나, 명령을 실행하기 전에 허가를 요청합니다. 이 튜토리얼의 모든 변경을 사용자가 직접 제어할 수 있습니다.

요구사항 및 계획 정의

Bob에게 To-Do API 요구사항을 제공하고, Bob이 코드를 작성하기 전에 제안된 계획을 검토합니다.

Plan 모드로 전환

Bob 사이드바 하단의 모드 드롭다운을 열고 Plan을 선택합니다.

IBM Bob 모드 드롭다운에서 Plan 모드 선택됨

모드는 최소 권한 원칙을 적용합니다. Plan 모드에서는 Bob이 코드를 읽고 Markdown 계획을 작성합니다. 명령을 실행하거나 구현 변경을 하지 않습니다. Bob이 애플리케이션 코드를 작성하기 전에 접근 방식을 검토할 수 있습니다.

애플리케이션 요구사항 정의

Bob 채팅 인터페이스에 다음 프롬프트를 입력합니다:

Create a simple FastAPI To-Do API.

Requirements:

- Store tasks in a Python list.
- Each task should contain:
    - id
    - task_name

Implement these endpoints with explicit HTTP status codes:

- GET /tasks: list all tasks. Return 200.
- POST /tasks: create a task from a JSON body containing only task_name. Return 201 with the created task.
- DELETE /tasks/{task_id}: delete a task. Return 204 on success and 404 if no task has that id.

Use FastAPI and Pydantic. Use Pydantic model validation so an invalid request body returns 422.

Include a requirements.txt and a Dockerfile. The Dockerfile must start Uvicorn bound to 0.0.0.0 on port 8000 so the API is reachable through a published container port.

Save the plan as Markdown files in a folder named `plans`.

Put the FastAPI application in a single file named `main.py` at the project root.

Keep the implementation simple.

Don't install any dependencies locally or run local tests. Everything will run in a Docker container.

계획을 수립하기 위해 Bob은 계획 skill을 실행합니다. 프롬프트가 표시되면 Approve skill tools for taskApprove subagent tools for task를 선택해 Bob이 워크스페이스를 조사하고 계획을 작성할 수 있도록 합니다.

계획 개선

Bob이 코드를 작성하기 전에 계획을 변경할 수 있습니다. Bob 채팅 인터페이스에 후속 프롬프트를 입력합니다:

Update the plan to reject a task whose task_name is empty or longer than 200 characters.

Bob이 추가 입력 유효성 검사를 포함하도록 계획을 수정합니다. 업데이트된 계획을 검토합니다.

계획 검토

Bob은 순서가 지정된 계획을 제시하며, 프로젝트에 Markdown 파일로 저장할 수도 있습니다. 계속하기 전에 다음을 검토합니다:

  • 범위: 계획이 모든 엔드포인트와 추가한 유효성 검사 규칙을 다루고 있으며, 요청하지 않은 내용은 포함되어 있지 않은지 확인합니다.
  • 파일 명시: 각 단계에서 생성하거나 변경하는 파일의 이름이 명시되어 있는지 확인합니다.
  • 모호한 표현: "오류를 적절히 처리"와 같은 표현은 가정을 숨깁니다. Bob에게 구체적으로 명시하도록 요청합니다.

이러한 설계 결정에 대한 책임은 사용자에게 있습니다. Bob은 애플리케이션 생성 및 검토에서 Agent 모드로 전환할 때까지 아무것도 구현하지 않습니다.

애플리케이션 생성 및 검토

새 컨텍스트 창을 시작하고, Agent 모드로 전환해 Bob이 승인된 계획을 구현하도록 합니다.

새 컨텍스트 창 시작

채팅 박스의 New task 또는 채팅 패널 상단의 **+**를 선택해 새 컨텍스트 창을 시작합니다. 자세한 내용은 새 컨텍스트 창 만들기를 참조합니다. Bob이 계획을 plans 폴더에 저장했으므로 계획 대화는 더 이상 컨텍스트에 유지할 필요가 없습니다. 깨끗한 컨텍스트는 구현을 승인된 계획에 집중시킵니다.

Agent 모드로 전환하고 계획 실행

Bob 사이드바 하단의 모드 드롭다운을 열고 Agent를 선택합니다. 그런 다음 Bob에게 계획을 구현하도록 지시합니다:

Implement the plan in the plans folder.
@plans/

Agent 모드에서는 Bob이 파일을 작성하고 명령을 실행할 수 있습니다. 자동 승인을 비활성화했으므로 Bob은 각 변경 전에 승인을 요청합니다. Bob이 계획을 진행하는 동안 각 단계를 승인합니다.

생성된 애플리케이션 검토

구현이 완료되면 생성된 코드를 검토합니다. Bob의 출력은 확률적이므로 코드 스타일과 내부 이름이 여기 표시된 예시와 다를 수 있습니다. 애플리케이션은 다음 부분으로 구성됩니다.

데이터 모델. Bob은 두 가지 Pydantic 모델을 생성합니다: 태스크 생성 시 요청 본문용 모델과 저장된 태스크용 모델. 생성 모델은 계획 중에 추가한 길이 규칙을 적용합니다:

class TaskCreate(BaseModel):
    task_name: Annotated[str, Field(min_length=1, max_length=200)]


class Task(BaseModel):
    id: int
    task_name: str

엔드포인트 경로와 상태 코드는 Bob에게 제공한 요구사항과 일치하지만, 모델 클래스 이름과 파일 레이아웃은 다를 수 있습니다. 이 튜토리얼에서는 TaskTaskCreate 모델을 가정합니다. Bob이 다른 이름을 선택하면 이후 프롬프트를 그에 맞게 조정합니다.

인메모리 데이터 저장소. Bob은 빈 Python 리스트에 태스크를 저장하고 새 태스크마다 증가하는 id를 할당합니다:

tasks: list[dict] = []
id_counter = 0

API 작업. 애플리케이션은 다음 엔드포인트를 제공합니다:

  • GET /tasks
  • POST /tasks
  • DELETE /tasks/{task_id}

POST /tasks는 요청 본문에서 task_name만 받고 생성된 태스크와 함께 201을 반환합니다. DELETE /tasks/{task_id}는 성공 시 204를 반환하고 해당 task_id가 없는 경우 404를 반환합니다.

의존성. Bob이 FastAPI, Uvicorn, Pydantic을 나열하는 requirements.txt 파일을 생성합니다.

컨테이너. Bob이 의존성을 설치하고 Uvicorn으로 포트 8000에서 API를 실행하는 Dockerfile을 생성합니다.

HTTP 계약은 메서드, 경로, 상태 코드를 포함해 요구사항 프롬프트를 따릅니다. 다음 유효성 검사 단계는 그대로 적용됩니다.

리터럿 코딩으로 엔드포인트 추가

리터럿 코딩 모드를 사용해 채팅 창으로 전환하지 않고 에디터의 자연어 지시문으로 업데이트 엔드포인트를 직접 추가합니다.

리터럿 코딩 모드는 에디터에 직접 작성한 자연어 지시문으로 코드를 생성합니다.

애플리케이션 파일 열기

Bob이 생성한 main.py 파일을 열고, 마지막 라우트 핸들러 다음 파일 끝의 빈 줄에 커서를 놓습니다.

리터럿 코딩 모드 활성화

Mac에서는 Command + I, Windows 및 Linux에서는 Ctrl + I를 누릅니다. 에디터 툴바의 마법 지팡이 아이콘을 선택해도 됩니다.

지시문 작성

빈 줄에 다음 지시문을 입력합니다. 나머지 코드와 다른 색상으로 강조 표시됩니다.

Add a PUT /tasks/{task_id} endpoint that updates the task_name of an existing task, matching the style and conventions of the existing routes. Return 200 with the updated task, or 404 if no task has that id.

Bob은 주변 코드에서 파라미터 이름, 요청 모델, 오류 처리를 추론하므로 메서드와 경로만 지정하면 됩니다.

코드 생성 및 수락

Generate를 선택하거나, Mac에서는 Command + Enter, Windows 및 Linux에서는 Ctrl + Enter를 누릅니다. Bob이 지시문을 구현으로 교체하고 인라인 diff를 표시합니다.

diff를 검토한 다음 Accept All을 선택해 변경을 적용합니다. Mac에서는 Command + I, Windows 및 Linux에서는 Ctrl + I를 다시 눌러 리터럿 코딩 모드를 종료합니다.

설명, 실행, 검증

Bob에게 구현을 설명하도록 요청하고, 애플리케이션을 실행해 동작을 검증합니다.

Bob에게 코드 설명 요청

New task로 새 컨텍스트 창을 시작하고, 모드 드롭다운에서 Ask를 선택합니다. Ask 모드는 파일을 편집하지 않고 질문에 답하고 코드를 분석합니다. 변경 없이 설명이 필요할 때 사용합니다.

생성된 코드를 이해하는 것은 AI 페어 프로그래밍의 중요한 부분입니다. Bob에게 요청합니다:

Explain the generated To-Do API.

Bob은 애플리케이션 아키텍처, 데이터 흐름, FastAPI 컴포넌트, Pydantic 모델, 엔드포인트 동작, 설계 결정 사항을 설명할 수 있습니다. 설명을 통해 코드를 변경하거나 확장하기 전에 코드가 예상대로 동작하는지 확인합니다.

애플리케이션 실행

Bob이 명령을 실행할 수 있도록 Agent 모드로 다시 전환합니다. Bob에게 컨테이너에서 API를 빌드하고 실행하도록 요청합니다:

Build the Docker image and run the container with port 8000 mapped to the host. Confirm the API is reachable.

Bob이 빌드 및 시작 명령을 실행하고 컨테이너가 실행 중임을 보고합니다.

브라우저에서 http://localhost:8000/docs를 엽니다.

FastAPI는 /docs에서 대화형 Swagger UI를 제공합니다. 이를 사용해 각 엔드포인트를 탐색하고, 요청 및 응답 스키마를 확인하고, 브라우저에서 API 호출을 실행할 수 있습니다.

API 검증

/docs의 Swagger UI를 사용해 각 작업을 실행합니다. 모든 엔드포인트에 대해:

  1. 해당 행을 펼치고 Try it out을 선택합니다.
  2. 경로 파라미터나 요청 본문을 입력합니다.
  3. Execute를 선택합니다.
  4. Server response 코드와 본문을 확인합니다.

태스크 추가

  1. POST /tasks를 펼치고 Try it out을 선택합니다.

  2. 요청 본문을 다음으로 교체합니다:

    {
      "task_name": "My first API item!"
    }
  3. Execute를 선택합니다. 응답 코드가 201이고 응답 본문에 할당된 id와 함께 생성된 태스크가 표시되는지 확인합니다.

태스크 조회

  1. GET /tasks를 펼치고 Try it out을 선택합니다.
  2. Execute를 선택합니다. 응답 코드가 200이고 응답 본문에 추가했을 때 할당된 id와 함께 태스크 My first API item!이 나열되는지 확인합니다.

태스크 업데이트

  1. PUT /tasks/{task_id}를 펼치고 Try it out을 선택합니다.

  2. 생성한 태스크의 task_id를 입력합니다.

  3. 요청 본문을 다음으로 교체합니다:

    {
      "task_name": "Build and ship a To-Do API"
    }
  4. Execute를 선택합니다. 응답 코드가 200이고 반환된 태스크에 업데이트된 task_name이 표시되는지 확인합니다.

  5. task_id를 존재하지 않는 값으로 변경하고 Execute를 다시 선택합니다. 응답 코드가 404인지 확인합니다.

태스크 삭제

  1. DELETE /tasks/{task_id}를 펼치고 Try it out을 선택합니다.
  2. 생성한 태스크의 task_id를 입력하고 Execute를 선택합니다. 응답 코드가 204인지 확인합니다.
  3. GET /tasks를 펼치고, Execute를 선택하고, 응답에서 태스크가 더 이상 나타나지 않는지 확인합니다.
  4. DELETE /tasks/{task_id}를 다시 펼치고, 같은 task_id를 입력하고, Execute를 선택합니다. 응답 코드가 404인지 확인합니다.

리터럿 코딩으로 추가한 업데이트 엔드포인트를 포함해 구현이 원래 요구사항을 충족합니다.

코드 품질 개선

Bob에게 생성된 코드의 품질 문제를 검토하도록 요청하고, 동의하는 변경 사항을 적용합니다. 이 단계에서는 Bob을 단순한 코드 생성기가 아닌 리뷰어로 활용합니다.

Bob에게 개선 제안 요청

New task로 새 컨텍스트 창을 시작하고, 다음을 입력합니다:

Review the To-Do API and suggest improvements to code quality, error handling, and HTTP status codes.

Bob은 단일 태스크를 조회하는 엔드포인트 누락, 유효성 검사된 Task 모델 대신 일반 딕셔너리를 저장하는 인메모리 저장소, 재설정이나 테스트가 어려운 모듈 수준 id_counter 등의 문제를 식별합니다.

개선 사항 적용

유지하고 싶은 제안을 Bob에게 구현하도록 요청합니다:

Add a GET /tasks/{task_id} endpoint that returns 404 when the task ID does not exist, and store tasks as Task models instead of dictionaries.

제안된 변경 사항을 검토하고 승인해 적용합니다. Bob에게 이미지를 다시 빌드하고 컨테이너를 재시작하도록 요청한 다음 검증 단계를 반복합니다. 유효한 ID에 대해 GET /tasks/{task_id}가 태스크와 함께 200을 반환하고 알 수 없는 ID에 대해 404를 반환하는지, 기존 엔드포인트가 이전과 동일하게 동작하는지 확인합니다.

테스트 및 문서 생성

Bob에게 API의 테스트 스위트와 기술 문서를 생성하도록 요청합니다.

유닛 테스트 생성

New task로 새 컨텍스트 창을 시작하고, Bob에게 요청합니다:

Generate pytest unit tests for this application. Add pytest and httpx to a dev requirements file, build a test image, and run the suite in a container.

Bob이 pytesthttpx 테스트 의존성을 추가하고, 이를 포함하는 이미지를 빌드하고, 컨테이너에서 스위트를 실행하고, 결과를 보고합니다. 컨테이너에서 테스트를 실행하므로 로컬 Python 환경이 필요하지 않습니다. 생성된 테스트를 검토하고 개선합니다.

생성된 테스트를 검토하고 유지하는 것은 사용자의 책임입니다.

기술 문서 생성

Bob에게 요청합니다:

Generate technical documentation for this To-Do API.

Bob은 애플리케이션 개요, 아키텍처 설명, 엔드포인트 요약, 요청 및 응답 예시, 사용 방법을 생성할 수 있습니다. 이 문서는 FastAPI가 자동으로 생성하는 API 문서를 보완합니다.

문제 해결

다음은 일반적인 문제에 대한 해결 방법입니다:

  • Docker 데몬에 연결할 수 없음: 이미지를 빌드하기 전에 Docker Desktop 또는 Docker 서비스를 시작합니다.
  • 컨테이너는 시작됐지만 http://localhost:8000/docs가 로드되지 않음: Dockerfile이 컨테이너 내부에서 API를 127.0.0.1에 바인딩하면 게시된 포트로 접근할 수 없습니다. Dockerfile이 --host 0.0.0.0으로 Uvicorn을 시작하는지 확인하고 이미지를 다시 빌드합니다.
  • Bind for 0.0.0.0:8000 failed: port is already allocated: 포트 8000을 사용하는 프로세스를 중지하거나, docker run -d --name todo-api -p 8080:8000 todo-api로 다른 호스트 포트에 매핑하고 http://localhost:8080/docs를 엽니다.
  • The container name "/todo-api" is already in use: docker rm -f todo-api를 실행한 다음 컨테이너를 다시 시작합니다.
  • 테스트 실행 시 pytest가 없음: 애플리케이션 이미지에는 테스트 의존성이 포함되어 있지 않습니다. Bob에게 pytesthttpx를 dev requirements 파일에 추가하고 별도의 테스트 이미지를 빌드하도록 요청합니다.

정리

컨테이너를 중지하고 제거해 포트 8000을 해제합니다:

Stop and remove the To-Do API and test container and image.

API는 태스크를 메모리에만 저장하므로 컨테이너를 제거하면 모든 데이터가 삭제됩니다. 추가적인 정리는 필요하지 않습니다.

다음 단계

이 튜토리얼에서는 Bob과 페어를 이루어 각 단계에서 변경을 검토하고 적용하며 컨테이너화된 FastAPI To-Do API를 빌드하고 검증했습니다.

FAQ

FastAPI를 알아야 하나요? 아니요. Bob이 FastAPI와 Pydantic 코드를 생성하고 요청 시 설명해 줍니다. 기본적인 Python과 REST 지식으로 충분합니다.

단계마다 모드를 전환하는 이유는 무엇인가요? 모드는 최소 권한을 적용합니다. Plan 모드는 코드를 읽고 계획을 작성하지만 아무것도 실행하지 않습니다. Agent 모드는 파일을 편집하고 명령을 실행할 수 있습니다. Ask 모드는 파일을 변경하지 않고 질문에 답합니다. 모드를 전환하면 Bob의 권한이 현재 작업에 맞게 유지됩니다.

Bob이 파일이나 모델 이름을 다르게 지정하면 어떻게 되나요? HTTP 계약은 요구사항 프롬프트에 의해 고정되므로 경로와 상태 코드는 일치합니다. 클래스 이름과 파일 레이아웃은 다를 수 있습니다. 이 튜토리얼은 TaskTaskCreate 모델을 가정합니다. Bob이 다른 이름을 선택하면 이후 프롬프트를 그에 맞게 조정합니다.

각 단계마다 새 컨텍스트 창을 시작하는 이유는 무엇인가요? Bob이 계획을 plans 폴더에 저장하므로 이전 대화를 더 이상 컨텍스트에 유지할 필요가 없습니다. 깨끗한 컨텍스트는 각 단계를 집중적으로 유지하고 토큰 비용을 절감합니다.

Docker 없이도 이 튜토리얼을 진행할 수 있나요? 기술적으로는 Docker 없이도 이 튜토리얼을 진행할 수 있지만, Bob에 대한 계획과 프롬프트를 수정해야 합니다.

Plan 모드에서 파일이 변경되나요? 아니요. Plan 모드에서 Bob은 코드를 읽고 Markdown 계획만 작성합니다. Agent 모드로 전환하기 전까지 애플리케이션 코드는 변경되지 않습니다.

이 주제는 어떤가요?