🏃🏻 Others/Conference

우아콘 2025 참여 후기

dev.daisy 2025. 10. 28. 21:24

 

운 좋게 표를 양도받아 참여할 수 있었는데, 현장에서 느낀 생생한 에너지와 강연자들의 깊이 있는 이야기가 정말 인상적이였습니다. 컨퍼런스를 올 때마다 생각하는거지만, 아직 모르는 개념이 많고 배워야 할 건 정말 끝도 없다는 것을 다시 한 번 느꼈습니다. 대단한 분들 사이에서 강연을 들을 수 있어서 좋았고 스스로 동기부여가 많이 되는 경험이였습니다 :)

 

이번에 좋은 기회로 우아콘 2025 표를 양도받아서 참여할 수 있었습니다! 굿즈는 흰색 우아콘 티셔츠를 받았고, 행사장은 파르나스몰 5층에서 진행되어 굉장히 넓고 쾌적했습니다! 배민 캐릭터로 수박게임하기, 네컷사진 찍고 sns에 업로드하기 등 참여할 수 있는 행사도 함께 진행되었습니다.

 

특히 강연히 끝난 뒤 20분동안 '연사와의 대화' 세션에서 연사자들과 직접 대화할 수 있는 이벤트를 마련해주셨는데요, 유튜브로 듣지 않고 현장에 꼭 오고 싶었던 이유가 이런 멘토링 기회였기 때문에 가능한 매 세션마다 열심히 참여해보았습니다! 정말 다양한 이야기를 들었지만 가장 인상깊었던건 배민이 웹뷰라는 것이였습니다...!


세션은 다음과 같았는데, 저는 프론트엔드 세션만 참여했습니다.

  1. "어드민스튜디오" 웹 에디터 설계하기: 스키마 기반 렌더링, 데이터 연동과 인프라까지 - 김요욱, 이재원
  2. 로그 회귀 테스트 구축으로 데이터 기반 비즈니스 지키기 - 유동식
  3. 우아한 디버깅 툴: QA 이슈 해결에 필요한 데이터를 쉽게 주고, 받자 - 홍영준
  4. 장보기 / 쇼핑 가게 홈 성능 최적화 고군분투기: 웹 전환 과정에서의 경험과 교훈 - 우희제
  5. 당연해진 디자인시스템, 그 다음 이야기: AST와 MCP로 여는 미래 - 권현아, 이상철


세션 1. "어드민스튜디오" 웹 에디터 설계하기: 스키마 기반 렌더링, 데이터 연동과 인프라까지 - 김요욱, 이재원

왜 만들었나?

많은 서비스에서 어드민은 고객 서비스보다 후순위로 밀리는 경우가 많습니다. 그래서 종종 완성도나 사용성보다는 빠른 개발 속도가 우선시됩니다. 하지만 그 결과, 기능 추가나 수정이 어려워지고, 사용자 러닝 커브가 높아지며 결국 유지보수의 사각지대가 생기게 됩니다.

이 문제를 해결하며 “어드민은 왜 꼭 개발자가 만들어야 할까? 누구나 쉽게 만들 수 있는 표준화된 어드민 에디터가 있다면 어떨까?” 라는 생각을 했고, 누구나 빠르고 자유롭게 일관된 품질로 어드민을 만들 수 있는 에디터를 만들자는 목표를 가지고 개발하셨다고 합니다.

아키텍처 설계

에디터 시스템은 크게 세 가지 축으로 나뉩니다.

  • Editor: 블록 구성 및 편집 영역
  • Viewer: 실제 어드민 화면 렌더링
  • Server: 프로젝트 정의 및 버저닝 관리

1️⃣  정의하고 해석하기: Studio DSL & Block Renderer

1) Studio DSL (Domain Specific Language)

어드민의 구조와 동작 방식을 정의하는 JSON 기반 언어입니다. 각 블록의 형태, 이벤트, 연관 관계를 정의하며 데이터만 수정해도 어드민이 바로 변경됩니다.

 

그러나 JSON은 함수(핸들러)를 직접 담을 수 없기 때문에, string-based dispatch 방식을 도입해 이벤트를 문자열 기반으로 매핑했습니다.

DSL으로 관리하면 좋은점은?

  1. 간결함: 필요한 정보만 담은 단순하고 간결한 데이터 형태를 만들 수 있습니다. 따라서 쉽게 보일러 플레이트를 제거할 수 있습니다.
  2. 효율성: 코드보다 작은 데이터를 저장하고 통신하기 때문에 저장하고 배포하면 빌드 없이 바로 반영이 가능합니다.
  3. 관리 용이성: 컴포넌트 버전 업데이트 시 기존 정의의 변경이 불필요하기 때문에 리팩토링이나 성능 최적화 후에도 각 서비스에 쉽게 반영할 수 있습니다.

2) Block Renderer

JSON → Component로 변환하는 렌더링 모듈입니다. 각 블록은 APIConfig를 통해 필요한 API 요청을 수행하고, 응답을 기반으로 동적으로 UI를 구성합니다.


2️⃣  상호작용 영역 구성하기: 렌더링과 인터랙션의 분리

에디터에서 드래그 앤 드롭과 같은 상호작용은 필수적이였지만 에디터 화면과 뷰어 화면이 같다는 것을 보장하지 못했고, 많은 내용을 렌더링하는 페이지를 드래그할 때 비싼 리렌더링이 발생하면 성능이 급격히 저하되기 때문에,이를 해결하기 위해 렌더링 레이어와 인터랙션 레이어를 분리했습니다.

  • Rendering Layer: 실제 블록이 그려지는 화면
  • Interaction Layer: 마우스 이벤트, 드래그 동작을 처리하는 별도 영역

이때 인터랙션 레이어는 각 요소의 위치를 실시간으로 파악해야 합니다. 이를 위해 블록의 위치 데이터를 캐싱하는 스토어를 만들고, 각 블록을 Wrapper 컴포넌트로 감싸 위치 정보를 저장하도록 설계했습니다.

 

이 구조 위에서 Event Bus 패턴을 적용했다고 하셨는데요, 컴포넌트 간 직접 참조 없이 이벤트로 통신하며 UI 레이어 간 결합도를 낮춰 확장성을 확보했습니다. 이 부분도 처음 들어보는 디자인 패턴이라 흥미롭게 느껴졌습니다.


3️⃣  API 연결의 표준화: Open API Specification (OAS)

에디터에서 각 블록은 다양한 API를 불러와야 합니다. 하지만 문제는 API마다 형태가 제각각이라는 점이었습니다. 이를 해결하기 위해 Open API Specification(OAS) 을 도입했습니다.

 

OAS는 Swagger로부터 시작된 표준 문서 형식으로, API 구조를 문서화하여 자동화와 안정성을 확보합니다. 이를 통해 에디터는 API를 검색 → 선택 → 즉시 연동할 수 있는 구조로 발전했습니다.


4️⃣  데이터 저장 레이어 확인하기

(1) Zustand로 현재 편집 상태 관리

현재 편집 상태를 전역으로 관리합니다. Single Source of Truth 원칙 아래 선택적 구독을 적용하여 불필요한 리렌더링을 최소화했습니다.

(2)  IndexedDB + TanStack Query 어댑터로 임시 저장 기능 구현

브라우저 로컬에서 객체를 비동기 저장할 수 있는 IndexedDB를 선택했습니다. LocalStorage보다 대용량 데이터에 적합하며, TanStack Query 어댑터를 통해 캐싱, 구조화, 리패칭을 통합했습니다.

임시 복구 플로우
: 임시 데이터가 존재하면 사용자에게 복구 여부를 묻고, 없을 경우 서버의 최신 데이터를 기반으로 초기화합니다.

(3) Server Versioning으로 서버 데이터 영구 저장

서버에서는 프로젝트 버저닝을 위해 Content-Addressable 저장 방식(snapshot=commit)을 채택했습니다. DSL은 Definition(정의 조각)과 Version(조각의 모음)으로 분리되어 관리됩니다.

느낀 점

단순한 에디터 프로젝트가 될 수 있었지만, 어드민 개발의 패러다임을 코드 중심에서 데이터 중심으로 전환하는 과정이 인상깊었습니다. 특히 DSL을 사용해 어드민을 데이터로 정의하고, Layer 분리로 UX 성능을 확보하면서 OAS로 API 통합 구조를 세우고 IndexedDBZustand로 안정적인 편집을 가능하게 한 점이 정말 멋지다고 생각되었습니다.

세션 2. 로그 회귀 테스트 구축으로 데이터 기반 비즈니스 지키기 - 유동식

 

이번 세션은 실제 배민의 장애 사례에서 발생한 자동화 테스트 구축 과정을 말씀해주셔서 흥미로웠습니다. 먼저 '스냅샷 테스트'를 처음 들어봐서 한 번 찾아보았는데, 미리 알고 들으면 좋았을 것 같습니다!

스냅샷 테스트는 어떤 코드의 출력 결과(렌더링 결과, 객체, JSON 등)를 저장해두고, 나중에 다시 실행했을 때 이전 결과와 달라졌는지 자동으로 비교하는 테스트 방식입니다. 결과물이 변했는지를 체크하는 회귀(Regression) 테스트의 한 종류입니다.

UI 테스트에서 흔히 사용되지만, 이번 케이스에서는 로그 데이터 형태 검증용으로 응용했습니다. 즉, 각 API 호출 시 발생해야 하는 로그 형태를 스냅샷으로 저장해두고, 테스트 실행 시 현재 결과와 비교하여 “이전과 다른 로그 구조가 발생했는가”를 판단합니다.

이렇게 하면 로그 필드 추가, 키 이름 변경, 누락 등의 변화를 즉시 탐지할 수 있습니다.

문제의 시작

어느 날 배민 상품 추천 영역의 로그가 쌓이지 않는 현상이 발견되었고, 분석해보니 단순한 오류가 아니라 로그 API 자체가 호출되지 않았던 문제라는 것을 확인했습니다.

 

단순한 통계 누락이 아니라, 추천 모델의 데이터 품질, 노출 효과 측정, 광고 효율 등 비즈니스 전반에 영향을 주는 근본적인 장애였기 때문에, 이 사건을 계기로 “로그 수집 로직이 의도치 않게 깨지지 않았는가”를 사전에 감지할 수 있는 체계가 필요하다는 결론에 도달했다고 합니다.

 

로그 누락 문제의 원인은 코드 수정, API 응답 지연, 혹은 의존 모듈 변경 등 다양한 요인에 의해 발생할 수 있지만, 공통된 문제는 “로그 로직의 변화를 사람의 눈으로 검수하기 어렵다”는 것이였습니다.

 

로그의 종류는 수백, 수천 개에 달하며, 그중 일부만이라도 누락되면 데이터 분석 전체의 신뢰성이 흔들립니다. 따라서 단순한 단위 테스트나 QA 검수 수준이 아닌 회귀 테스트(regression test) 자동화 체계가 필요했습니다.

 

모킹 전략: 모듈 모킹 vs API 모킹

테스트 자동화의 핵심은 실제 환경과 최대한 유사하게 테스트하면서도, 의존성을 최소화하는 것입니다. 이를 위해 두 가지 접근을 검토했습니다.

1️⃣ 모듈 모킹 (Module Mocking)

  • 각 API를 직접 모듈 단위로 모킹하는 방식
  • 코드 구조와 결합도가 높음
  • 테스트를 위해 실제 모듈의 경로와 로직을 깊게 이해해야 함

장점: 세밀한 단위 제어 가능

단점: API가 변경되면 테스트 코드도 함께 수정해야 함

→ 유지보수 비용이 높고, 테스트 환경 격리가 어려움

 

2️⃣ API 모킹 (채택된 방식)

  • 실제 API 호출 자체를 테스트 러너 레벨에서 가로채는 방식
  • 코드 내부의 흐름과 상관없이 테스트 실행 시점에 모킹 로직이 호출됨
  • API 구조나 응답 형태가 변경되더라도 테스트 코드에 영향이 거의 없음

장점:

  • 테스트 코드와 비즈니스 로직이 분리되어 유지보수성이 높음
  • 테스트 러너에서 바로 실행 가능 (CI/CD 파이프라인 연동 용이)
  • 테스트 독립성 확보: 실제 API 서버와 완전히 분리 가능

결과:

  • 로그 API의 응답을 모킹하고, 예상된 로그 구조를 스냅샷으로 비교
  • 덕분에 새로운 코드 배포 시 로그 구조가 변하면 즉시 테스트에서 감지 가능

“사람이 직접 검수하지 않아도 된다”

이 접근법을 통해, 다음의 세 가지 효과를 얻었습니다.

  • 로그 구조 변경 감지 자동화
  • 신규 기능 추가 시 회귀 안정성 확보
  • QA 의존도 감소

무엇보다 테스트가 사람의 의도를 대신 검증하게 되었다는 점이 가장 큰 변화였습니다.

 

느낀 점

이번 경험은 단순히 누락된 로그 문제를 해결하는 데서 그치지 않고, 사람이 직접 확인해야만 하는 영역을 코드로 치환할 수 있을까? 라는 근본적인 질문을 던지고 스냅샷 기반 회귀 테스트 자동화로 정답을 찾아나가는 과정이 인상깊었습니다. 당연한 것을 당연하게 생각하지 않고, 사소한 불편함도 자동화를 통해 해결해나가는 개발자가 되어야겠다고 생각했습니다.

세션 3. 우아한 디버깅 툴: QA 이슈 해결에 필요한 데이터를 쉽게 주고, 받자 - 홍영준

왜 만들었을까?

모바일 웹뷰 디버깅은 다음과 같은 한계를 갖고 있었습니다.

  1. 동일한 재현이 어렵다 - 기기, OS, 앱 버전이 달라 재현 불가합니다.
  2. 데이터 접근성이 낮다 - PC에 연결해 Chrome Inspector로 봐야합니다.
  3. 로컬 테스트 제약 - 로컬 코드를 디바이스에서 직접 돌리기 어렵습니다.

기존 QA 프로세스는 다음과 같은 순서로 진행되었는데요,

  • QA 담당자가 테스트 중 오류 발생
  • Charles나 화면 녹화로 상황 재현
  • 다시 주문 플로우 반복 후 영상 저장
  • 영상을 PC로 옮겨 개발자에게 전달
  • 개발자는 로그가 없어 원인 파악 불가
  • 서버 개발자에게 API 로그 요청
  • 회원 ID를 요청하고 응답을 기다림

결국 QA → FE → BE 간 컨텍스트 스위칭이 반복되며,한 건의 이슈를 해결하는 데 긴 시간이 소요된다는 문제가 있었습니다.

 

모바일 웹 뷰 환경에서 디버깅하는 단계가 엄청나게 복잡하고, 같은 문제를 재현하기 위해서 QA 담당자가 여러 단계를 거치고 디바이스 환경이 다르기 때문에 개발자가 바로 원인을 파악하기 어렵다는 문제가 있었습니다. 따라서 '직접 재현하지 않고 QA 시점에서 원인을 바로 파악할 수 있다면 어떨까?' 하는 질문에서 우아한 디버깅 툴이 탄생했습니다.

우아한 디버깅 툴이란?

이 도구는 간단히 말하면, ‘과거의 이슈 상황과 연결된 개발자 도구’입니다. 모바일 베타 앱 내 웹뷰 환경에서 QA가 테스트 중 문제를 발견하면, 기록방을 생성해 그 순간의 모든 데이터를 그대로 저장합니다.

주요 기능

1. 기록방 (Record Room)

문제가 발생한 시점의 디버깅 환경을 그대로 재현합니다. 개발자는 마치 QA 담당자의 디바이스를 직접 조작하듯 이슈를 확인할 수 있습니다.

  • 마지막 화면 상태를 그대로 확인 가능
  • 이전 기록 더보기로 장바구니, 주문, 결제 등 이전 플로우까지 추적
  • DOM, Console 탭도 함께 저장되어 원인 파악 용이
  • API 요청을 cURL로 복사하거나 검색 가능
  • Session Replay 기능으로 실제 유저 행동 흐름 재생 가능

2. 티켓 생성

문제 발견 시 QA 담당자는 플로팅 버튼으로 바로 티켓을 생성할 수 있습니다. 슬랙봇이 자동으로 담당자에게 DM을 보내며, QA는 별도의 스크린샷이나 로그 전달 없이 상황만 간단히 작성하면 됩니다. 개발자는 링크를 클릭하면 바로 기록방으로 진입해 해당 시점의 로그, 화면, API 호출 내역을 모두 확인할 수 있습니다.

3. Network Rewrite

API 응답값을 손쉽게 수정하여 테스트할 수 있는 기능입니다. 기존에는 백엔드에 수정해달라고 요청하지 않고, FE가 독립적으로 QA 테스트를 할 수 있는 구조입니다.

  1. API 오류 발생 시 프론트 로직 확인
    → 에러 팝업이 정상적으로 노출되는지 검증
  2. 특정 환경 강제 시뮬레이션
    → “심야시간에만 예약배달 가능” 조건을 API 응답으로 강제 설정해 테스트

아키텍처: 수집 → 전송 → 저장 → 조회

1) 수집 (Collect)

원본 fetch를 감싸서 API 요청 / 응답을 가로채고 저장합니다. 이 데이터를 SDK에서 관리하며, 이슈 발생 시 한 번에 기록방으로 전송할 준비를 합니다.

2) 전송 (Send)

  • 웹소켓(WebSocket) 기반 실시간 전송
  • 기록방 생성 순간, 누적된 캐시 데이터를 일괄 업로드
  • CDP(Chrome DevTools Protocol) 을 활용해 콘솔/네트워크 데이터를 그대로 수집

3) 저장 (Store)

서버의 로컬 메모리에 저장 후 S3에 영구적으로 보관합니다. (재생용 세션 데이터 포함)

4) 조회 (View)

  • 페이지를 열면 WebSocket이 연결되며 기록 데이터가 활성화됩니다.
  • 필요 시 이전 화면의 정보까지 조회 가능합니다.
    → 주문서 이슈지만, 장바구니 단계의 로그가 필요할 때

이 구조를 통해 QA 시점의 모든 상호작용과 네트워크 흐름이 완전하게 복원됩니다.

제일 재미있게 들었던 세션이였습니다! 실제로 올 해 프로젝트를 운영하면서 유일한 프론트엔드 개발자로서 QA 시간마다 팀원들에게 "devtools 열고 화면녹화 해주세요!"를 수도 없이 외쳤던 경험이 있었고, 플로팅 버튼으로 바로 티켓을 생성해 해당 시점의 로그, 화면, API 호출 내역을 바로 확인할 수 있도록 구현할 수 있겠다는 생각조차 못했기 때문에 정말 혁신적인 아이템이라고 생각이 되었습니다. 로컬에서는 안 된다고 하시지만 저는 기기에서 같은 문제를 재현하는 방법을 몰라 시간을 허비했던 적이 많았는데, 이런 방법으로 해결할 수 있다니 해당 라이브러리가 상용화되면 정말 유용하게 사용할 것 같습니다.

 

'🏃🏻 Others > Conference' 카테고리의 다른 글

DAN25 (네이버 컨퍼런스) 참여 후기  (0) 2025.11.08
2025 FEConf 후기  (3) 2025.08.23