대규모 A/B 테스트의 인시던트를 최소화하다

코드 리뷰 자동화를 통한 A 로직의 변경 감지

쿠팡 엔지니어링
Coupang Engineering Blog
7 min readAug 3, 2022

--

By Ohmer (Liangwei) He

본 포스트는 영문으로도 제공됩니다.

쿠팡 앱이 어떻게 현재의 모습을 갖추게 되었나 생각해본 적 있으신가요? 사실 대답은 놀랄 만큼 단순합니다. 바로 A/B 테스트입니다. 쿠팡에서는 매일 수백 개의 A/B 테스트를 수행되고 있으며, 애플리케이션의 모든 기능 요소를 철저히 테스트하여 고객 경험 향상을 도모하고 있습니다. 쿠팡에서 A/B 테스트는 비즈니스 이슈에 대한 의사 결정 과정의 핵심으로, 개인의 의견이나 촉에 의존하지 않는 실증적 접근방식을 뒷받침 합니다.

그렇다면 A/B 테스트란 정확히 무엇일까요? A/B 테스트는 하나의 대조군과 하나 이상의 실험군으로 구성된 실험을 지칭합니다. 대조군에 속하는 사용자는 대다수 쿠팡 사용자와 동일한 디폴트 기능, 즉, A 로직을 보게 됩니다. 반면 실험군의 사용자는 신규 기능, 또는 B 로직을 테스트하려는 목적으로 변형된 실험용 기능(treatment)에 노출되며 해당 기능에 대한 사용자 반응은 지표로 측정됩니다. A/B 테스트를 통해 특정 기능에 대한 사용자 수용도를 측정하고 이를 바탕으로 쿠팡에 대한 사용자의 경험을 최적화할 수 있습니다. 쿠팡에서는 자체 실험 플랫폼에서 지표를 커스터마이징해, A/B 테스트를 수행하고 있습니다. 쿠팡의 실험 플랫폼에 대해 더 자세히 알고 싶다면, 이전 포스트를 확인하세요.

이번 포스트에서는 A/B 테스트를 대규모로 실시했을 때 발생하는 이슈와 에러의 최소화, 그리고 엔지니어링 효율성의 극대화를 위해, A/B 테스트에 앞서 진행되는 코드 리뷰 프로세스의 일부분을 자동화하게 된 이야기를 해보겠습니다.

목차

· 이슈
· 기술적 구현
개요
AST 비교
동작 분석
· 마무리

이슈

쿠팡 엔지니어의 가장 중요한 책임 중 하나는 동시 다발적으로 진행되는 수백 개의 A/B 테스트로 인해 일어날 수 있는 문제를 최소화하고, 앱의 안정성을 보장하는 것입니다. 하지만 최대한 노력해도 A/B 테스트 관련 사고는 완벽히 방지할 수 없기 마련입니다.

특정 A/B 테스트 때문에 사고가 발생하면, 일단 B 로직을 롤백하고 모든 사용자를 A 로직으로 되돌립니다. 하지만 말처럼 쉬운 일은 아닙니다. 내부 조사 결과, 모바일 애플리케이션과 관련해 발생한 기술적 사고(technical incident) 중 80%가 A/B 테스트 때문이었고, A 로직으로 되돌리는 방법으로는 사고를 해결할 수 없었습니다. A 로직과 B 로직이 A/B 조건 판단을 통해 제대로 분리되지 않아, B 로직의 해제 역시 A 로직에 예상치 못한 변경을 초래하기 때문이었습니다.

대부분의 에러는 애초에 방지할 수 있는, 의도치 않은 실수에 의해 유발되었습니다. 이러한 단순 오류가 코드 리뷰를 통과한 게 문제가 아니냐고 할 수 있지만, 각 코드 변경이 A 로직에 영향을 주는지 아닌지 파악하는 일은 직접 하기에는 어렵고 시간이 많이 걸릴 수 밖에 없는 일입니다. 게다가 쿠팡 엔지니어들은 매주 A/B 테스트를 위해 기능마다 수십 가지의 버전을 개발하고 배포해야 합니다. 모든 에러를 잡아내는 데에 물리적인 한계가 존재했습니다.

그래서 저희는 에러 발생 방지 및 안정적이고 강력한 A/B 테스트가 가능하도록, 사전에 진행하는 코드 리뷰 프로세스에 A 로직의 변경을 감지하는 자동화 시스템을 설계하여 구현하게 되었습니다.

기술적 구현

쿠팡 코드 리뷰
그림 1. 풀 요청은 감지 솔루션인 CI 잡을 트리거하며, CI 잡에서 A 로직을 변경시킬 수 있는 코드에 주석을 단다.

A 로직 변경 감지 시스템은 풀 요청(Pull Request, PR)에 의해 트리거되는 방식으로 통합시켰습니다. 모바일 엔지니어가 PR을 제출하면, 감지 시스템에서 코드를 분석하고, A 로직을 변경시킬 가능성이 있는 코드 라인에 경고를 보냅니다(dispatch). 엔지니어와 리뷰어는 누구나 코드 리뷰 중 경고를 확인하고 적절히 수정할 수 있습니다. 통합 감지 시스템은 이러한 감지 프로세스의 자동화를 가능케 하여 엔지니어의 시간을 아끼고, 효율을 증대시키고, 인적 오류의 위험을 최소화하고 있습니다.

그렇다면 이 단순한 감지 시스템의 작동 원리는 어떻게 될까요? 다음 섹션에서는 감지 프로세스를 어떻게 정의하였는지, 그리고 그 배경에서는 어떤 작업이 이뤄지는지 알아보겠습니다.

개요

전체적인 감지 프로세스는 다음과 같은 4 단계로 구성됩니다.

  1. Git 수준의 코드 변경 감지하기. 시스템은 원본 코드와 수정 코드를 Git 수준에서 대조하여 변경된 코드 라인을 파악합니다. 변경된 코드 라인은 추가, 수정, 삭제 유형으로 분류됩니다.
  2. AST를 통해 코드 변경 비교하기. 이후 변경된 코드 라인을 AST, 또는 추상 구문 트리(abstract syntax tree, AST)를 사용해 비교합니다. AST에는 추가, 수정, 이동, 삭제의 4가지 노드 유형이 존재합니다. AST 파서를 사용해 각 노드를 1개의 유형으로 분류하고 각 노드를 대응 노드에 매핑합니다.
  3. 작업(operational)으로 인한 A로직의 변경 분석하기. 다음으로 시스템은 각 작업 유형에 대해 정의되어 있는 규칙을 기반으로 AST를 분석하고 노드에 있는 변경 사항이 기존 A 로직의 변경을 트리거하는지 판단합니다.
  4. A 로직에 변경을 가져올 수 있는 노드를 필터링한 후 알림을 보낼 사용자 선택하기. A 로직에 영향을 미칠 수 있는 노드를 태깅합니다. 코드에 가해진 작업들에는 복합적인 부모-자식 관계가 존재하기 때문에 A 로직에 직접적인 영향을 주지 않는 노드라도 자식 노드에서의 변경 내용 때문에 태깅되기도 합니다. 이러한 노드의 경우, A 로직 변경으로 이어지는 노드에 대해서만 사용자가 경고를 받도록 시스템이 합리적인 수준에서 자동화된 필터링을 수행합니다.
쿠팡 코드 변경 감지 프로세스
그림 2. 변경 감지 프로세스를 개략적으로 설명하는 도식

AST 비교

예시를 통해 감지 프로세스를 좀 더 상세히 설명하겠습니다. 아래와 같은 변경 작업 AST에 해당하는 코드가 리뷰 대상입니다. 왼쪽의 AST는 원본 코드에 대한 것이고, 오른쪽은 변경된 코드로 PR 요청이 이루어진 상태입니다. 변경된 브랜치 파일에는 다음과 같은 변경 사항이 적용되어 있습니다.

  1. 이동 Movement: ‘I’ 노드를 이동하였습니다. 예를 들어, 코드 블록 내에 존재했던 표현식이 외부로 이동되었습니다.
  2. 수정 Modification: ‘M’ 노드가 수정되었습니다. 예를 들어, 새로운 메서드가 호출되었습니다.
  3. 삭제 Deletion: ‘Z’ 노드가 삭제되었습니다. 예를 들어, 코드 라인이 삭제되었습니다.
  4. 추가 Addition: ‘P’ 노드가 추가되었습니다. 예를 들어, 코드 라인이 추가되었습니다.
쿠팡 코드 변경 감지 프로세스
그림 3. 각 AST는 A 로직(좌) 브랜치, 그리고 B 로직(우)의 변경된 코드 동작을 나타낸다.

감지 시스템은 이러한 변경을 어떻게 4개의 작업 유형으로 분류할까요? 우선, 동등성과 유사성을 확인하는 대조 알고리즘을 사용해 원본 코드의 노드와 변경된 코드의 노드 사이의 관계를 매핑합니다.

원본 노드와 변경 노드가 동일하다면 코드 변경이 없었던 것으로 간주하고 분석 대상에서 제외됩니다. 원본 노드와 수정 노드가 동등하지만 부모 노드가 변경되었다면, 새로운 노드의 작업 유형은 이동으로 분류됩니다. 동등하지만 유사성이 확인된다면 수정 유형으로 분류됩니다. 원본 노드와 수정 모드 사이에 매핑 관계가 존재하지 않는다면 해당 노드는 삭제 또는 추가로 분류됩니다.

쿠팡 코드 변경 감지 프로세스
그림 4. 원본 및 수정 노드의 AST를 먼저 정렬시킨다(상단). 그리고 동등성과 유사성 대조 알고리즘을 사용해 관계를 매핑한다(하단).

알고리즘에 의한 대조 후 AST 트리는 아래의 그림 5와 같은 모습이 됩니다. 노란 하이라이트는 수정 작업을 의미하며 초록은 이동 작업을 의미합니다. A와 B 노드와 같이 직접적인 변경이 없었던 노드도 수정된 자식 노드 때문에 노랗게 표시된 것을 볼 수 있습니다. 빨강은 삭제, 청록은 추가를 의미합니다. 파랑은 변경이 없었음을 표시합니다.

쿠팡 코드 변경 감지 프로세스
그림 5. 작업 유형에 따라 표시된 원본 노드(좌)와 수정 노드(우)의 AST.

노드에 있는 변경 사항이 A로직의 변경을 초래할 가능성이 있으면 해당 노드를 태깅합니다. 이때 이루어지는 분석 과정은 다음 섹션에서 상세히 살펴보겠습니다. A 로직에 변경을 초래할 가능성이 있는 노드는 아래 그림에서 점선 동그라미로 표시되었습니다.

쿠팡 코드 변경 감지 프로세스
그림 6. 동그라미 표시된 노드는 A 로직에 영향을 줄 수 있는 변경이 확인됩니다. 이에 더해 직접적인 변경이 없었더라도 복합적인 부모-자식 관계 때문에 영향을 줄 수 있는 노드 역시 표시됩니다.

그림 6에서 볼 수 있듯이, 노드 A와 같이 직접적인 수정이 없었던 코드를 가리키는 노드라 하더라도 자식 노드에서 A 로직에 대한 영향이 감지된다면 동그라미로 표시됩니다. 양쪽 AST의 표시된 노드 전부를 사용자에게 알린다면 사용자는 혼란스럽고, 의미 없는 경고 메시지를 대량으로 받게 됩니다. 그렇기 때문에 그림 7에서 볼 수 있듯이 A 로직에 실질적인 영향을 미치는 노드만을 합리적인 수준에서 필터링하여 해당 작업에 대해서만 공지합니다.

쿠팡 코드 변경 감지 프로세스
그림 7. 노드를 필터링한 최종 AST. 사용자에게는 이를 기반으로 알림이 전송됩니다.

A 로직의 변경 분석

이번 섹션에서는 감지 시스템이 작업 유형이 태깅된 각 노드를 어떻게 분석하여 A 로직에 대한 변경 여부를 판정하는지 설명하겠습니다. 그럼 추가 작업 유형이 태깅된 노드의 예시를 보겠습니다.

쿠팡 코드 변경 감지 프로세스
그림 8. 추가 작업 분석의 배경 로직에 대한 상세 도식.

추가 노드를 파싱할 시에는 우선 선언식(declaration)/표현식(expression) 구문 여부 기반으로 먼저 분류합니다. 선언식 구문에는 클래스 선언, 메서드 선언, 속성 선언 등이 있습니다. 새로운 선언이 기타 코드에서 호출되지 않는다면 A 로직에 영향을 줄 수 없고, A 로직 변경을 초래하지 않는 것으로 분류됩니다.

표현식 구문이 있는 노드의 경우, 조건부 표현식(conditional expression) 여부로 노드를 분류합니다. 조건부 표현식이 새 노드(Addition)와 관련된 판정을 내리는 경우, A 로직이 아닌 B 로직과 관련된 것으로 판단합니다. 물론 이는 일반적인 추정이고 실제 배포 환경에 따라 다르게 정의될 수 있습니다. 하지만, 조건부 표현식이 다른 노드와 관련된 판정을 내리는 경우, 새 노드는 A 로직에 영향을 미치는 것으로 태깅됩니다.

노드에 표현식 구문이 존재하지만 조건부 표현식이 아니면, 노드가 가리키는 코드는 B 로직의 조건문 안에 있는 것입니다. 예를 들어 표현문은 “if” 조건문 안에서 실행되거나, B 로직에서 호출되는 다른 조건문 안에서 실행되어야 합니다. 표현문이 그러한 조건문 안에 있지 않으면, 해당 노드는 A 로직 변경이 가능한 것으로 태깅됩니다.

이런 기본적인 로직은 추가 작업의 판정뿐만 아니라 다른 작업 유형에서도 마찬가지로 적용됩니다. 단, 이동 작업은 예외입니다. 이동 작업 관련해서는 실행 조건과 조건의 실행 경로가 이동 전후로 동일한지를 판단합니다. 저희의 감지 시스템은 다수의 실행 조건이 결합되어 있는 복잡한 로직 콤비네이션도 비교할 수 있습니다. 예를 들어 (a || b) && c 그리고 (a && c) || (b && c) 가 서로 같은 조건식인지 아닌지도 판정할 수 있습니다.

마무리

이 자동화된 코드 리뷰 도구를 적용한 후, A/B 테스트 코드에 대한 상태 검사가 확연히 증가한 것을 확인할 수 있었고, 결과적으로 코드 라인 1천 개당 규칙 위반이 22.6에서 16.5로 줄어들었습니다. 이는 기존에 비해 약 27% 감소한 수치입니다. 또한, 총체적으로 A 로직 변경이 30% 감소했습니다. 저희는 코드 리뷰 자동화를 통해, 고객 경험의 일관성이 A/B 테스트의 인시던트 때문에 나빠질 때마다 엔지니어들이 일관성을 이전 상태로 되돌리기 위해 허비했던 시간과 비용을 아낄 수 있게 되었습니다. 앞으로 이 단순하고도 효과적인 솔루션을 안드로이드 환경이 아닌, 백엔드와 iOS 개발 등에도 적용할 예정입니다.

쿠팡 같이 급성장하는 고객 기반을 둔 기업에서 모바일 애플리케이션의 안정성을 개선해 보고 싶으시다면, 현재 진행 중인 쿠팡의 채용 공고를 확인해 보세요.

--

--

쿠팡 엔지니어링
Coupang Engineering Blog

쿠팡의 엔지니어들은 매일 쿠팡 이커머스, 이츠, 플레이 서비스를 만들고 발전시켜 나갑니다. 그 과정과 결과를 이곳에 기록하고 공유합니다.