본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 05. 21. 12:03

AI를 사용하여 전체 코드베이스를 리팩터링하는 방법 (Gemini 3.5 사용)

요약

레거시 모놀리스 코드베이스를 마이크로서비스로 분리하기 위해 Gemini 3.5 Flash를 활용한 자율 추출 에이전트 'Flash'를 구축한 사례를 소개합니다. 100만 토큰의 넓은 컨텍스트 윈도우를 활용하여 프로젝트 전체의 의존성을 파악하고, 상태 유지 워크플로우를 통해 자동화된 리팩터링을 수행합니다.

핵심 포인트

  • Gemini 3.5 Flash의 100만 토큰 컨텍스트 윈도우를 활용해 전체 저장소의 의존성을 한 번에 파악 가능
  • 벡터 데이터베이스 없이도 프로젝트 전체 컨텍스트를 유지하며 정밀한 리팩터링 수행
  • Interactions API와 thinking_level 파라미터를 사용하여 아키텍처 계획 단계의 추론 능력 강화
  • 에이전틱 워크플로우(Agentic Workflows)를 통한 수동 리팩터링 작업의 자동화

모든 1인 개발자는 금요일 오후 배포가 주는 공포를 알고 있습니다. 사용자 프로필 컴포넌트에 사소한 업데이트를 푸시했는데, 웬일인지 결제 처리 파이프라인 전체가 오프라인 상태가 되는 상황 말입니다. 이것이 레거시 모놀리스 (Legacy Monolith)와 함께 살아가는 가혹한 현실입니다. 5년 동안의 급격한 개발 과정에서 저의 사이드 프로젝트는 서로 밀접하게 결합된 로직의 거대한 망으로 변해버렸습니다. 사용자 시스템은 결제 시스템에 의존했고, 결제 시스템은 알림 서비스에 의존했습니다. 이러한 조각들을 깨끗한 마이크로서비스 (Microservices)로 추출하는 것은 수년 동안 제 할 일 목록에 있었습니다. 문제는 제가 단 한 명뿐이라는 점입니다. 문서화되지 않은 수천 개의 파일을 수동으로 추적하고 혼자서 이 엉망진창인 상태를 풀어내는 데 필요한 6개월이라는 시간을 도저히 낼 수 없었습니다. Google I/O 2026 기조연설을 시청했을 때, 에이전틱 워크플로우 (Agentic Workflows)에 관한 발표가 즉시 제 주의를 끌었습니다. 저는 마침내 이 악몽을 자동화할 수 있다는 것을 깨달았습니다. 저는 자율 추출 워커 (Autonomous Extraction Worker)를 구축했고 이름을 Flash라고 지었습니다. Flash는 제 전체 저장소 (Repository)를 읽고, 숨겨진 의존성을 매핑하며, 코드를 독립적인 마이크로서비스로 격리하는 깨끗한 풀 리퀘스트 (Pull Requests)를 생성하도록 설계되었습니다. 개발자 발표를 놓치셨다면, Google이 이를 가능하게 하는 새로운 에이전트 플랫폼과 컨텍스트 윈도우 (Context Windows)를 공개한 아래의 기조연설 임베드 영상을 시청하실 수 있습니다:

지연 시간 및 메모리 문제

코드베이스 리팩터링 도구를 구축하려면 두 가지가 필요합니다. 방대한 메모리와 놀라운 속도입니다. 이전의 설정들은 코드 스니펫 (Code Snippets)을 검색하기 위해 복잡한 벡터 데이터베이스 (Vector Databases)를 필요로 했습니다. 이러한 접근 방식은 리팩터링에서 항상 실패했는데, AI가 한 번에 세 개의 파일만 볼 수 있다면 결제 모듈을 재구성할 수 없기 때문입니다. 변수 하나를 변경하는 것이 10개의 폴더 너머에 중첩된 파일에 어떤 영향을 미치는지 이해하려면 프로젝트 전체의 컨텍스트 (Context)가 필요합니다. Google은 Gemini 3.5 Flash가 다른 프런티어 모델 (Frontier Models)보다 훨씬 빠르면서도 100만 토큰의 컨텍스트 윈도우 (Context Window)로 작동한다고 밝혔습니다. 이 프로젝트에서 가장 중요한 점은, Gemini 3.5 Flash가 코딩 벤치마크에서 더 무거운 모델들보다 더 높은 점수를 기록했다는 것입니다.

이는 타임아웃이 발생하거나 개인 클라우드 예산을 소진하지 않고도 에이전트에게 전체 저장소(repository)를 한 번에 입력할 수 있음을 의미했습니다.

단계 1: 아키텍트(Architect) 초기화
시작하기 위해 새로운 Interactions API를 사용했습니다. 이 API는 상태 유지 워크플로우(stateful workflows)를 네이티브하게 처리하므로, 수동으로 대화 루프(conversation loops)를 작성할 필요가 없습니다. 저는 새로운 thinking_level 파라미터를 사용하여 에이전트를 구성했습니다. 이 파라미터는 모델이 실제 코드를 작성하기 전에 아키텍처를 계획하는 데 추가적인 연산 사이클(compute cycles)을 사용하도록 강제합니다.

import google.genai as genai

client = genai.Client(api_key="YOUR_API_KEY")

# 높은 추론 능력을 갖춘 에이전트 초기화
flash_agent = client.agents.create(
    model="gemini-3.5-flash",
    name="MonolithExtractor",
    instructions=(
        "당신은 수석 소프트웨어 아키텍트입니다. 당신의 목표는 "
        "거대한 모놀리식(monolithic) 코드베이스를 분석하고, 도메인 경계를 식별하며, "
        "밀접하게 결합된 모듈을 격리된 마이크로서비스(microservices)로 추출하는 것입니다. "
        "항상 기존 비즈니스 로직을 보존하는 것을 최우선으로 합니다."
    ),
    thinking_level="high"
)

print("Flash is online and ready to read code.")

단계 2: 의존성 트리(Dependency Tree) 매핑
에이전트가 프로젝트의 물리적 레이아웃을 이해하려면 방법이 필요합니다. 저는 에이전트의 도구(tool)로 작동하는 표준 Python 함수를 생성했습니다. 이 도구는 디렉토리를 스캔하고 서로 다른 파일들이 어떻게 서로를 임포트(import)하는지 매핑합니다. 이 도구를 모델에 직접 전달함으로써, Flash는 무엇을 리팩터링할지 결정하기 전에 전체 모놀리스(monolith)에 대한 신뢰할 수 있는 정신적 지도(mental map)를 구축할 수 있습니다.

import os

def generate_dependency_map(directory_path: str) -> dict:
    """
    저장소를 스캔하여 파일 임포트 및 의존성 맵을 반환합니다.
    """
    dependency_map = {}
    for root, dirs, files in os.walk(directory_path):
        for file in files:
            if file.endswith(".py") or file.endswith(".ts"):
                file_path = os.path.

join(root, file) # 실제 애플리케이션에서는 여기서 AST (Abstract Syntax Tree)를 파싱하여 임포트(import)를 찾아야 합니다.
                dependency_map[file_path] = f"Parsed dependencies for {file}"
                return {"status": "success", "dependencies": dependency_map}

# 도구를 Gemini 에이전트에 바인딩합니다.
flash_agent.add_tool(generate_dependency_map)

### 단계 3: 야수에게 먹이 주기 (Feeding the Beast)
에이전트가 파일 구조를 탐색하는 방법을 이해하고 나면, 이제 실제 로직을 처리해야 합니다. Gemini 3.5 Flash의 거대한 컨텍스트 윈도우 (Context Window) 덕분에, 저는 취약한 청킹 (Chunking) 스크립트를 작성할 필요가 없었습니다. 단순히 대상 디렉터리 경로를 전달하고 에이전트가 파일을 네이티브하게 읽도록 두었습니다. 에이전트는 먼저 의존성 도구를 사용한 다음, 코드를 읽어 결제 모듈 (Billing Module)을 어떻게 풀어낼지 파악합니다.

# 레거시 백엔드 저장소 경로
monolith_path = "/var/lib/legacy_backend_repo"

# 에이전트는 토큰 윈도우를 사용하여 디렉터리를 처리합니다.
response = flash_agent.chat(
    message=(
        f"{monolith_path}에 위치한 저장소를 분석하세요."
        "사용자 프로필 시스템에서 결제 모듈을 격리하세요."
        "결제를 위한 별도의 마이크로서비스 (Microservice) 구조를 생성하세요."
    )
)

print("Refactoring Plan:")
print(response.text)

### 단계 4: 풀 리퀘스트 (Pull Requests) 자동화
결합도가 높은 코드를 식별하는 것은 전투의 절반에 불과합니다. 진정으로 유용하려면, Flash가 새로운 마이크로서비스를 작성하고 리뷰를 위해 제출해야 합니다. 저는 GitHub 통합 도구를 추가했습니다. 에이전트가 리팩터링 계획을 확정하고 결합이 해제된 코드를 작성하면, 자동으로 해당 파일들을 새 브랜치에 푸시하고 저에게 리뷰를 요청합니다.

```python
def create_pull_request(branch_name: str, code_changes: dict, pr_notes: str) -> str:
    """
    추출된 마이크로서비스 코드를 브랜치에 푸시하고 GitHub PR을 생성합니다.
    """
    print(f"Creating new branch: {branch_name}")
    for filepath, content in code_changes.items():
        print(f"Writing updated logic to {filepath} ...")

) print ( f " PR 설명 초안 작성 중: { pr_notes } " ) return f " { branch_name } 브랜치에 Pull request가 성공적으로 오픈되었습니다. " # Flash에게 코드 커밋 권한 부여 flash_agent . add_tool ( create_pull_request ) 

Step 5: 프로덕션 환경으로 배포하기
로컬 스크립트를 실행하는 것은 개념 증명 (Proof of Concept, PoC) 단계에서는 훌륭합니다. 하지만 전체 리포지토리 (Repository)를 풀어내는 것은 지속적인 과정입니다. Google은 바로 이러한 종류의 에이전트 기반 워크로드 (Agentic workload)를 위한 오케스트레이션 플랫폼 (Orchestration platform)으로 Antigravity 2.0을 출시했습니다. 직접 서버나 크론 잡 (Cron jobs)을 관리하는 대신, 저는 로컬 에이전트를 Antigravity 워커 (Worker)로 감쌌습니다. 이제 Flash는 클라우드에서 동작합니다. 제가 GitHub 이슈 (Issue)에 extract_service 라벨을 달 때마다 백그라운드에서 자동으로 실행됩니다.

from google.antigravity import Orchestrator , AgentWorker

def deploy_flash_worker ():
    # Antigravity 오케스트레이션 환경 초기화
    orchestrator = Orchestrator ( project_name = " MonolithToMicro " )
    # GitHub 이벤트 트리거를 사용하여 에이전트를 클라우드 워커에 할당
    worker = AgentWorker (
        agent = flash_agent ,
        github_repo = " my-username/core-monolith " ,
        trigger = " on_issue_labeled:extract_service " 
    )
    orchestrator . add_worker ( worker )
    orchestrator . deploy ()

deploy_flash_worker ()

결과
Flash가 처음으로 Pull request를 오픈했을 때, 저는 믿기지 않는 마음으로 모니터를 바라보았습니다. 에이전트는 Stripe API 웹훅 (Webhooks)을 제 사용자 인증 로직 (User authentication logic)에서 성공적으로 분리해냈습니다. 새로운 디렉토리를 생성하고, 내부 임포트 경로 (Import paths)를 업데이트했으며, 새 서비스를 위한 깔끔한 설정 파일 (Setup file)을 작성했습니다. 처음부터 완벽했던 것은 아닙니다. 코드 리뷰 (Code review) 과정에서 환경 변수 (Environment variables)를 몇 개 수정해야 했습니다. 하지만 3주 동안 걸릴 지루한 수동 추적 작업을 약 45초 만에 완료했습니다. Gemini 3.5 Flash의 속도와 컨텍스트 크기 (Context size)를 활용함으로써, 저는 거대한 기술 부채 (Technical debt) 문제를 자동화된 백그라운드 프로세스로 전환했습니다. 1인 개발자로서 시간은 저의 가장 소중한 자산입니다. Flash 덕분에 저는 마침내 제 코드베이스를 두려워하는 것을 멈추고 새로운 기능을 만드는 일에 다시 집중할 수 있게 되었습니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0