안녕하세요 주간SaaS 입니다.
오늘은 Airbnb가 LLM을 활용하여 1.5년 걸릴것으로 예상했던 코드 마이그레이션을 6주만에 끝낸 사례를 소개 합니다.
이 사례는 SaaS 엔지니어링 측면에서 좋은 인사이트를 제공합니다. SaaS에서 고객에게 Deep Customization을 로우코드/노코드 형태로 제공하는 경우뿐만 아니라, Airbnb처럼 레거시 코드를 마이그레이션하는 경우에도 LLM의 강력한 자동화 능력을 활용할 수 있다는 점을 보여줍니다. 여러분들의 생각은 어떠신지 궁금합니다.
Airbnb는 최근 대규모 LLM(Large Language Model) 기반 코드 마이그레이션을 성공적으로 완료하여 약 3,500개의 React 컴포넌트 테스트 파일을 Enzyme에서 React Testing Library(RTL)로 업데이트했습니다. 원래는 수작업으로 1.5년의 엔지니어링 시간이 소요될 것으로 예상했지만, 최첨단 모델과 강력한 자동화 기술을 결합하여 단 6주 만에 전체 마이그레이션을 완료했습니다.
이번 블로그 포스트에서는 Enzyme에서 RTL로 마이그레이션하면서 직면했던 고유한 과제, LLM이 이러한 유형의 문제를 해결하는 데 탁월한 이유, 그리고 LLM 기반 마이그레이션을 대규모로 실행하기 위해 마이그레이션 도구를 어떻게 구성했는지 자세히 살펴보겠습니다.
배경
2020년, Airbnb는 모든 새로운 React 컴포넌트 테스트 개발에 React Testing Library(RTL)를 도입하면서 Enzyme에서 벗어나기 시작했습니다. Enzyme은 2015년부터 우리에게 유용했지만, 초기 버전의 React를 위해 설계되었고, 프레임워크가 컴포넌트 내부 구조에 깊숙이 접근하는 방식은 더 이상 최신 React 테스트 방식과 일치하지 않았습니다.
그러나 이러한 프레임워크 간의 근본적인 차이 때문에 단순히 하나를 다른 것으로 쉽게 교체할 수 없었습니다(차이점에 대한 자세한 내용은 여기 참조). 또한 Enzyme 파일을 삭제할 수도 없었습니다. 분석 결과 코드 커버리지에 상당한 격차가 발생할 것으로 나타났기 때문입니다. 이 마이그레이션을 완료하려면 원래 테스트의 의도와 코드 커버리지를 유지하면서 테스트 파일을 Enzyme에서 RTL로 리팩토링하는 자동화된 방법이 필요했습니다.
어떻게 진행했나
2023년 중반, Airbnb 해커톤 팀은 대규모 언어 모델이 단 며칠 만에 수백 개의 Enzyme 파일을 RTL로 성공적으로 변환할 수 있음을 입증했습니다.
이 유망한 결과를 바탕으로 2024년에 우리는 LLM 기반 마이그레이션을 위한 확장 가능한 파이프라인을 개발했습니다. 마이그레이션을 병렬화할 수 있는 개별적인 파일 단위 단계로 나누고, 구성 가능한 재시도 루프를 만들었으며, 추가 컨텍스트를 사용하여 프롬프트를 크게 확장했습니다. 마지막으로, 복잡한 파일의 롱테일(long tail) 문제를 해결하기 위해 광범위한 프롬프트 튜닝을 수행했습니다. (🐶 *자동화 하기에는 복잡하고 특이한 소수 파일("롱테일") 문제 해결을 위해, 개별 파일에 집중하기보다 전체 파일에 공통적으로 적용 가능한 프롬프트 개선을 먼저 시도하여 자동화 성공률을 높이는 전략을 선택한것 같습니다)
1. 파일 검증 및 리팩토링 단계
마이그레이션을 일련의 자동화된 검증 및 리팩토링 단계로 나누는 것으로 시작했습니다. 마치 생산 파이프라인처럼 생각하면 됩니다. 각 파일은 검증 단계를 거치고, 검사가 실패하면 LLM을 사용하여 수정합니다.
이 흐름을 상태 머신처럼 모델링하여 이전 상태의 검증이 통과된 후에만 파일을 다음 상태로 이동했습니다.
이 단계별 접근 방식은 자동화 파이프라인의 진행 상황을 추적하고, 특정 단계의 실패율을 개선하고, 필요에 따라 파일 또는 단계를 다시 실행할 수 있었습니다. 또한 단계별 접근 방식은 수백 개의 파일에 대해 동시에 마이그레이션을 실행하는 것을 간단하게 만듬으로써 간단한 파일을 빠르게 마이그레이션하고 마이그레이션 후반에 롱테일 파일(*🐶복잡하고 특이한 소수의 파일)을 해결하는 데 매우 중요했습니다.
2. 재시도 루프 및 동적 프롬프팅(Dynamic Prompting)
마이그레이션 초기에 파일당 마이그레이션 성공률을 높이기 위해 다양한 프롬프트 엔지니어링 전략을 실험했습니다. 그러나 단계별 접근 방식을 기반으로 했을 때, 결과를 개선하는 가장 효과적인 방법은 단순히 무차별 대입(brute force)이었습니다. 즉, 단계가 통과되거나 제한에 도달할 때까지 여러 번 재시도하는 것입니다. 각 재시도에 대해 동적 프롬프트를 사용하도록 단계를 업데이트하여 검증 오류와 파일의 최신 버전을 LLM에 제공하고, 각 단계를 구성 가능한 횟수까지 실행하는 루프 러너를 구축했습니다.
이 간단한 재시도 루프를 통해 간단한 수준에서 중간 수준의 복잡성을 가진 많은 테스트 파일을 성공적으로 마이그레이션할 수 있었습니다. 일부는 몇 번의 재시도 후에 성공적으로 완료되었고, 대부분은 10번의 시도 내에 완료되었습니다.
3. 컨텍스트 증가하기
특정 복잡성 수준까지의 테스트 파일의 경우 재시도 횟수를 늘리는 것만으로도 효과가 있었습니다. 그러나 복잡한 테스트 상태 설정 또는 과도한 간접 참조가 있는 파일을 처리하기 위해 가능한 한 많은 관련 컨텍스트를 프롬프트에 포함하는 것이 가장 좋은 방법임을 알았습니다.
마이그레이션이 끝날 무렵, 프롬프트는 40,000개에서 100,000개 사이의 토큰으로 확장되어 최대 50개의 관련 파일, 수많은 수동으로 작성된 퓨샷(few-shot) 예제, 그리고 동일한 프로젝트 내에서 기존의 잘 작성되고 통과하는 테스트 파일의 예제를 가져왔습니다.
각 프롬프트에는 다음이 포함되었습니다.
- 테스트 대상 컴포넌트의 소스 코드
- 마이그레이션하려는 테스트 파일
- 단계별 검증 실패
- 동일한 디렉토리의 관련 테스트 (팀별 패턴 유지)
- 일반적인 마이그레이션 지침 및 일반적인 해결 방법
실제로는 다음과 같은 모습이었습니다.
이 풍부한 컨텍스트 접근 방식은 이러한 더 복잡한 파일에 매우 효과적이었습니다. LLM은 팀별 패턴, 일반적인 테스트 접근 방식 및 코드베이스의 전체 아키텍처를 더 잘 이해할 수 있었습니다.
이 단계에서 프롬프트 엔지니어링을 수행했지만, 주요 성공 요인은 프롬프트를 완벽하게 만드는 것보다 올바른 관련 파일을 선택하는 것(근처 파일 찾기, 동일한 프로젝트에서 좋은 예제 파일 찾기, 컴포넌트와 관련된 파일에 대한 종속성 필터링 등)이라는 점에 주목해야 합니다.
재시도 및 풍부한 컨텍스트를 사용하여 마이그레이션 스크립트를 구축하고 테스트한 후 첫 번째 대량 실행을 실행했을 때 대상 파일의 75%를 단 4시간 만에 성공적으로 마이그레이션했습니다.
4. 75%에서 97%로: 체계적인 개선
75%의 성공률은 정말 흥미로웠지만, 여전히 900개에 가까운 파일이 단계별 검증 기준에 실패했습니다. 이 롱테일을 해결하려면 나머지 파일이 어디에서 막히는지 이해하고 이러한 문제를 해결하기 위해 마이그레이션 스크립트를 개선하는 체계적인 방법이 필요했습니다. 또한 가장 어려운 마이그레이션 사례에 갇히지 않고 나머지 파일을 적극적으로 해결하기 위해 광범위한 접근 방식을 취하고 싶었습니다.
이를 위해 마이그레이션 도구에 두 가지 기능을 구축했습니다.
첫째, 스크립트가 직면한 일반적인 문제를 파악할 수 있도록 각 마이그레이션 단계의 상태를 기록하기 위해 자동으로 생성된 주석으로 파일에 스탬프를 찍어주는 간단한 시스템을 구축했습니다. 다음은 해당 코드 주석의 모습입니다.
둘째, 특정 단계에서 막힌 단일 파일 또는 경로 패턴을 쉽게 다시 실행할 수 있는 기능을 추가했습니다.
이러한 두 가지 기능을 사용하여 프롬프트와 도구를 개선하기 위한 피드백 루프를 빠르게 실행할 수 있었습니다.
- 나머지 실패한 파일을 모두 실행하여 LLM이 막히는 일반적인 문제 찾기
- 일반적인 문제를 보여주는 파일 샘플 (5~10개) 선택
- 해당 문제를 해결하기 위해 프롬프트 및 스크립트 업데이트
- 실패한 파일 샘플에 대해 다시 실행하여 수정 사항 검증
- 나머지 파일에 대해 다시 실행하여 반복
이 "샘플, 튜닝, 스윕" 루프를 4일 동안 실행한 후 완료된 파일이 전체 파일의 75%에서 97%로 증가했으며, 100개 미만의 파일이 남았습니다. 이 시점에서 이러한 롱테일 파일 중 많은 파일을 50~100번 재시도했으며 자동화를 통해 수정할 수 있는 한계에 도달한 것으로 보였습니다. 더 많은 튜닝에 투자하는 대신 나머지 파일을 수동으로 수정하기로 결정하여 (실패한) 리팩토링을 기준으로 해당 파일을 완료하는 데 걸리는 시간을 줄였습니다.
결과 및 영향
검증 및 리팩토링 파이프라인, 재시도 루프 및 확장된 컨텍스트를 통해 대상 파일의 75%를 4시간 만에 자동으로 마이그레이션할 수 있었습니다.
"샘플, 튜닝 및 스윕" 전략을 사용하여 4일 동안 프롬프트 및 스크립트를 개선한 후 원래 3,500개의 Enzyme 파일의 97%에 도달했습니다.
자동화를 통해 완료되지 않은 나머지 3%의 파일의 경우 스크립트는 수동 개입을 위한 훌륭한 기준을 제공하여 나머지 파일을 완료하는 데 1주일 더 걸렸습니다.
가장 중요한 것은 원래 테스트 의도와 전체 코드 커버리지를 유지하면서 Enzyme을 대체할 수 있었다는 것입니다. 또한 마이그레이션의 롱테일에 대한 높은 재시도 횟수에도 불구하고 LLM API 사용량과 6주간의 엔지니어링 시간을 포함한 총 비용은 원래 수동 마이그레이션 예상보다 훨씬 효율적인 것으로 입증되었습니다.
다음 단계
이 마이그레이션은 대규모 코드 변환에 대한 LLM의 힘을 강조합니다. 우리는 이 접근 방식을 확장하고, 더 정교한 마이그레이션 도구를 개발하고, 개발자 생산성을 향상시키기 위해 LLM 기반 자동화의 새로운 응용 프로그램을 탐색할 계획입니다.
개발자 도구의 미래를 만들어가는 데 도움을 주고 싶으십니까? 우리는 복잡한 문제를 대규모로 해결하는 것을 좋아하는 엔지니어를 채용하고 있습니다. 자세한 내용은 채용 페이지를 확인하십시오.
의견을 남겨주세요