수면측정 SDK
안녕하세요. 에이슬립(Asleep)에서 소프트웨어 품질을 담당하고 있는 이지원입니다. 에이슬립은 10년간 소프트웨어 품질 분야에 몸담으면서 경험했던 일반적인 B2C/B2B 성향의 웹 앱 서비스와는 다르게 품질 측면에서 도전적인 과제들이 산재한 조직인데요.
소프트웨어 품질 측면에서 다양한 과제들이 눈앞에 놓여있지만 조직이 성장하는 방향에 맞춰 단기적인 해결책보단 중장기적으로 어떠한 시스템이 내재화되었을 때의 이점을 보다 중요시 여기며 일정 수준의 높은 품질과 개발 속도를 유지하고자 백엔드 분야를 기반으로 기술적인 레벨에서의 도전들을 이어나가고 있습니다.
이번 글에서는 에이슬립 프로덕트의 기술적인 배경을 시작으로 Sound AI라는 기술을 E2E Layer에서 어떻게 보다 효과적이고 효율적으로 검증할 수 있을지에 대해 24년 7월 에이슬립 복귀 이후 그동안 해왔던 모든 고민의 과정과 결과를 압축하면서 결과적으로 클라우드 대신 온프레미스 인프라 운영을 택한 이유를 담아보려 합니다.
에이슬립의 Sound AI는 스마트워치나 몸에 부착하는 센서 없이 오직 '숨소리'만으로 수면을 측정하고 분석하는 AI 기술입니다. 스마트폰이나 마이크가 탑재된 기기를 통해 자는 동안의 호흡음을 분석하여 수면 단계, 코골이, 수면 무호흡 등을 파악합니다.
숨소리가 얇고 약간 불규칙한 얕은 수면, 숨소리가 굵고 크며 매우 규칙적인 리듬을 보이는 깊은 수면, 몸은 자고 있지만 뇌는 깨어 있는 상태로 숨소리는 명확하지만 리듬이 매우 불규칙한 렘수면 등과 같은 수면 단계들을 호흡 패턴 변화를 분석하여 현재의 수면 단계를 정확히 판별하고 있습니다.
에이슬립에서는 이러한 Sound AI 기술을 SDK와 앱 등으로 제품화시킨 프로덕트에 대한 품질 보증을 해야 하는데요. 그 과정에서 Sound AI 기술을 검증하기 위해서는 필연적으로 장시간 수면 측정 테스트가 필요하고 AI 모델의 이상 동작을 파악하기 위해 실제 수면 음원이 재생된 공간에서 테스트가 진행되어야 수면 리포트에 수면 단계가 표시됩니다.
따라서 사용자에게 가장 중요한 코어 기능을 테스트하기 위해서는 장시간 측정 테스트 환경과 오디오 재생 환경 두 가지를 반드시 충족해야만 E2E Test Layer에서의 검증에 대한 결과 신뢰성이 일정 수준 보장되었다고 할 수 있습니다.
앞서 소개한 Sound AI 기술을 고객 또는 내부 프로덕트에서 보다 쉽고 간편하게 활용하기 위해 만들어진 SleepTrack API와 Mobile SDK의 검증과 이를 기반으로 만들어진 웹 앱 서비스를 검증하는 역할이 에이슬립 품질에서 중요한 영역 중 하나인데요.
SleepTrack API는 스마트폰으로 수집된 사운드 데이터를 에이슬립의 AI 기술로 분석하여 사용자의 수면 단계를 실시간으로 추적하고 수면 중 발생하는 사운드(예: 코골이, 등)를 감지합니다. 측정이 완료된 후에는 사용자의 지난밤 수면 데이터를 바탕으로 총 수면 시간, 수면 점수, 각 수면 단계 비율, 수면 효율, 등 다양한 지표를 포함한 수면 리포트를 제공합니다.
SDK는 앱에서 API를 쉽게 활용할 수 있도록 스마트폰의 마이크를 통해 수집된 오디오 데이터를 자동으로 처리합니다. 이 과정에서 수집된 데이터를 분석 가능한 형태로 변환한 후 주기적으로 서버에 업로드합니다. SDK를 사용하면 클라이언트 앱에서 간단히 수면 측정 함수를 호출하는 것만으로도 수면 측정 기능을 구현할 수 있습니다.
대시보드에서는 로그인한 계정의 API Key를 이용해 측정한 수면 데이터를 시각적으로 확인할 수 있습니다. 클라이언트 앱에 리포트 UI를 작성하기 전에 테스트 환경에서 진행한 수면 측정이 정상적으로 이루어졌는지 대시보드를 통해 쉽게 확인할 수 있습니다.
에이슬립 API와 SDK를 활용하여 개발에 들어가기 전에 수면 측정 플로우를 이해하는 것은 효율적인 개발과 문제 해결을 위해 필수적입니다. 일반적인 수면 측정 플로우는 다음과 같습니다.
첫 번째는 SDK를 초기화하는 단계입니다. 새로운 사용자의 아이디를 생성하거나 열려있는 이전 수면 측정 세션을 종료합니다.
두 번째는 측정 단계인데요. 오디오 녹음을 시작하고 주기적으로 멜 스펙트로그램으로 변화하여 서버로 업로드하는 단계입니다. 이 과정을 통해 실시간 수면 상태를 추적할 수 있습니다. 수면 측정이 시작되면 SDK는 클라이언트 앱에서 사용되어 사용자의 사운드 데이터를 수집하고 이를 30초 간격으로 서버에 업로드합니다. 업로드된 데이터는 AI 서버에서 5분 간격으로 비동기적으로 분석되며, 분석이 완료된 결과는 등록된 callback URL을 통해 클라이언트의 백엔드 서버로 실시간 전송됩니다. 5분 이후 첫 번째 분석이 시작되기 때문에 최소 5분 이상 측정해야 수면 분석 결과를 받아볼 수 있습니다.
마지막으로 수면 분석 결과를 확인하는 단계인 리포트 단계에서는 수면 측정 세션을 종료하고 서버에서 수면 분석이 완료된 시점부터 수면 지표(Stat Object)를 확인할 수 있습니다.
또한 QA가 알아야 할 사항으로는 유효 세션과 무효 세션의 개념이 있는데요. 유효 세션이란 충분한 사운드 데이터를 업로드하여 AI 수면 분석이 진행되어 유효한 수면 데이터를 제공할 수 있는 세션을 뜻합니다. 수면 분석이 이루어지기 위한 최소 조건은 아래와 같습니다.
수면 분석을 위해서는 최소 5분 이상의 연속된 사운드 데이터가 필요합니다. (해당 조건을 만족하지 못할 경우, peculiarities == TOO_SHORT_FOR_ANALYSIS)
전체 수면 세션 중 70% 이상의 구간의 사운드 데이터가 정상적으로 업로드되어야 합니다. (해당 조건을 만족하지 못할 경우, peculiarities == TOO_MANY_DEFECTS_IN_SLEEP_STAGES)
이렇듯 에이슬립의 기술이 활용된 프로덕트에 대한 품질 보증을 위해서는 각 프로덕트의 요구사항을 기반으로 Sound AI 기술을 활용한 SleepTrack API와 Mobile SDK의 개념과 수면 측정 플로우에 대한 이해가 선행되어야 합니다. 그렇지 않으면 실제로 내부 로직에 버그가 있어도 UI로는 정확한 확인이 어려운 경우가 많고 클라이언트 사이드 이슈인지 서버 사이드 이슈인지 판단이 어려울 수 있기에 API와 SDK의 스펙을 이해하고 이를 기반으로 만들어진 프로덕트의 요구사항이 무엇인지, E2E Layer의 클라이언트와 서버 사이드에서 QA가 검증해야 할 항목들은 무엇인지에 대해 파악하는 과정이 중요합니다.
과거 B2C 성향의 프로덕트도 존재했지만 26년 1월 기준으로 조직이 나아가야 할 방향과 집중 필요한 방향이 명확해졌고 2026년은 두 개의 목적을 성공시킬 수 있도록 전사 리소스를 집중하고 있습니다. 더 많은 것을 시도했던 과거와는 달리 이제는 반드시 성공시킬 것만 남기는 회사로 전사 공감대를 형성했고 앞으로의 방향을 단순화하여 구성원 모두가 같은 기준으로 판단하고 움직이기 위해 두 개의 목적을 내부적으로 선언하게 되었습니다.
즉 지금 하고 있는 일이 두 가지 목적을 가속하는지 아니면 분산시키는지가 우선순위의 판단 기준이 되었고 이에 맞춰 소프트웨어 품질 방향을 보다 뾰족하게 만들어가야 하는 시점이 찾아왔습니다. 선택과 집중을 위해 Medical과 Wellness 프로덕트에 집중하게 되었고 현재까지는 1인 QA 환경에서 리소스가 충분치 않아 Medical 영역의 프로덕트에 집중함과 동시에 두 영역의 기본이 되는 에이슬립 API와 SDK 또한 중요 프로덕트로 관리하고 있습니다.
Medical 영역에서는 현재 그리고 가까운 미래를 포함하면 2가지 App/Web 프로덕트가 존재하며 API/SDK까지 포함하면 크게 4가지 프로덕트에 대한 QA 활동이 필요한 상황입니다. 어떻게 보면 Medical 영역의 2가지 App/Web 내부 프로덕트는 API/SDK를 가져다 쓰는 내부 고객사의 입장이기 때문에 기본적으로 API/SDK 동작이 보장되어야 App/Web 프로덕트의 코어 기능에 문제가 없음을 증명할 수 있고, API/SDK 동작이 보장되어도 App/Web 프로덕트에서의 클라이언트 사이드와 서버 사이드의 엣지 케이스를 대응하지 못한다면 결국 사용자 입장에서는 에이슬립 프로덕트를 사용하는 가치를 느낄 수 없기 때문에 서로 다른 성향의 제품을 다각도로 해석하고 분석하는 과정이 필요했습니다.
이 과정에서 제가 추구하는 품질 방향은 아래와 같습니다.
1. 빠른 개발 속도를 유지하면서도 일정 수준의 품질을 유지한다.
2. 장애는 반드시 발생한다. 사용자보다 빠르게 발견하고 대응하는 프로세스와 시스템이 필요하다. 프로덕션 환경에서의 24시간 전수검사 상시 모니터링을 활용한 서비스 장애의 선제적 대응을 진행한다.
3. 출시 전 스테이징 환경에서 진행되는 전수검사와 신규 스펙에 대한 QA 프로세스를 가속화시킨다.
4. 배포 전/후 테스트에서 사람 개입을 최소화시키고 빠른 피드백 루프를 통해 검증 프로세스를 일관성 있고 신뢰성 있게 보장한다.
위 4가지를 1인 QA 환경에서 달성하기 위해 그동안 경험하고 학습했던 모든 기술적인 활동을 진행하고 있습니다.
클라우드 테스트 인프라를 도입하면 여러모로 이점이 많은데요. 특히 대규모 병렬 테스팅을 보다 쉽게 진행할 수 있고 인프라 관리를 클라우드 업체에서 관리하기 때문에 오직 클라이언트 사이드 영역에만 집중 가능한 환경이 갖춰집니다.
이로 인해 개인적으로 웹과 모바일 서비스 모두 클라우드 테스트 인프라를 도입하는 걸 선호하고 테스트 환경을 온프레미스로 자체 구축해서 진행하는 방식을 선호하지 않습니다. 만약 개발 조직에서 온프레미스로 운영해야 하는 맥락이 존재한다면 가능한(대규모 Selenium, Appium 레거시가 없다면) Selenium과 Appium을 추상화시킨 프레임워크를 활용하고 디자인 패턴을 적극 활용하며 대규모 병렬 분산 테스팅을 지원하기 위해 설계된 그리드 아키텍처를 도입하는 것이 기술적으로 타당하다고 생각합니다. 보다 상세한 맥락은 과거 경험에 의해 작성했던 모바일 대규모 병렬 테스팅, 에이슬립에서 이어가다를 참고해 주세요.
클라우드 테스트 인프라 도입을 선호하는 점과 테스트에 필요한 클라이언트 사이드의 초기 설계 또한 클라우드 인프라에 맞춰서 구조화시키는 것을 선호하다 보니 브라우저스택, 람다테스트, 소스랩, AWS 디바이스팜과 같은 여러 클라우드 환경을 검토했고 과거 실무 경험이 있었던 브라우저스택과 람다테스트 중에서 최종적으로 람다테스트 도입을 결정하게 되었습니다. 내부적으로 여러 검토 기준을 세웠었고 결과적으로 브라우저스택 같은 경우 에이슬립 규모 대비 오버엔지니어링에 가까운 기능을 포함하고 있는 점과 더불어 목적 달성 대비 비용면에서 효율적이지 못했습니다.
람다테스트 도입을 통해 웹 프로덕트 같은 경우 람다테스트 클라우드 인프라 구조에 맞춰서 클라이언트 사이드를 구조화시키고 E2E 테스트 레이어 검증에 필요한 테스트 스위트와 CICD 파이프라인을 구성하게 되었는데요.
repository_dispatch를 통한 배포 후 자동 테스트 파이프라인을 구성했고 수동 개입 없이 5분 이내로 장애 발견 여부를 감지하고 150개 이상의 전수검사를 통해 배포의 안정성을 사람 개입 없이 지속적으로 보장하고 있습니다. 보다 자세한 사항은 내가 추구하는 배포 후 E2E 테스트 모니터링 전략을 참고해 주세요.
웹 프로덕트 같은 경우 업데이트 주기에 맞춰서 지속적으로 테스트 스위트를 개선하고 개발하는 유지보수만 진행하면 되므로 큰 문제가 없지만 모바일 프로덕트는 상황이 좀 달랐는데요. 앞서 Sound AI 기술을 소개할 때 언급했던 장시간 측정 테스트 환경과 오디오 재생 환경을 클라우드 테스트 인프라에서는 충족시킬 수 없었기 때문입니다. 또한 장시간 기기 사용 시 기기 연결이 끊기거나 허용 가능한 세션 시간에 제한이 있다 보니 수면측정 SDK의 검증에 필요한 테스트 요구사항을 충족시킬 수 없었습니다.
그럼에도 불구하고 온프레미스로 전환하지 않고 모바일 테스트 또한 클라우드 인프라에서 어떻게든 SDK 요구사항을 충족시킬만한 최적의 방법을 찾고자 노력했는데요. 클라우드 서비스들에서 베타 기능으로 제공하는 오디오 인젝션 기능에 대한 PoC를 통해 클라우드 인프라에 API를 활용하여 오디오를 업로드하고 이를 테스트 중에 재생하는 플로우를 검토하긴 했지만 그 과정에서도 여러 기술적인 이슈와 더불어 커뮤니케이션 이슈가 발생하곤 했습니다.
그중에서 몇 가지 일화를 소개하자면 오디오 인젝션 기능이 가이드 문서에 맞게 동작하지 않자 주말 밤낮으로 문제 원인을 분석하여 기능 자체에 버그가 있다고 공유했으나 오디오 인젝션 시 발생하는 500 에러에 대해 2021년 1월에 Deprecate 된 WebdriverIO v5로의 다운그레이드를 해결책으로 제시했습니다.
현재 발생하는 500 에러는 클라이언트 사이드의 문제가 아님을 업무 외 시간을 통해 클라우드 서비스 기술팀에게 지속 증명 했으나, 인젝션 코드 사용 위치를 변경하거나 문법이 잘못된 것이 아니냐는 등의 부적절한 답변을 5일 내내 지속했습니다.
수년간 WebdriverIO를 활용하며 릴리스 노트를 트래킹 하고 있던 저로서는 납득이 안 가는 해결책이었습니다. WebdriverIO는 v8부터 동기식 → 비동기식으로 아키텍처가 완전히 변경되었고 당시 v9가 Stable 버전이므로 v5로의 회귀는 최신 WebdriverIO/Appium 생태계를 전혀 이해하지 못한 제안이라 판단되었습니다. 이로 인해 현시점에서 v5로의 마이그레이션은 최악의 선택이라며 기술적으로 강도 높은 비판을 했던 일이 있었습니다.
오디오 인젝션 기능이 WebdriverIO v9 또는 최소한 v8조차 지원하지 않는다면 그 자체로 심각한 문제이고 프로덕션 레벨의 유료 기능이라 볼 수 없으며 현재 v5를 사용하는 WebdriverIO 사용자는 거의 없을 것이라며 오디오 인젝션 기능을 내부적으로 철저히 테스트한 후 사용자에게 공개하는 것이 더 나을 것이라는 의견을 전달했고 결국 플랜 업그레이드 의사를 철회하자 Lead Customer Success Architect가 개입하여 v9 호환성 유지를 약속받은 당일, v9에서 오디오 인젝션 사용이 가능했던 일화가 있었습니다.
이후 클라우드 인프라에서 오디오 인젝션을 활용한 수면측정 SDK 검증 PoC를 진행했으나 오디오 인젝션 동작 방식이 SDK 검증을 할 수 있는 방식으로 설계되어있지 않았습니다. 결과적으로 모바일 프로덕트에서는 클라우드 인프라 운영을 중단하게 되었고 온프레미스 환경을 자체 구축하기로 결정하게 되었습니다. 그 과정에서 클라이언트 사이드 또한 온프레미스 병렬 테스팅 구조에 맞춰서 재설계를 진행했습니다.
온프레미스 테스트 환경 구성에 필요한 소프트웨어와 물리적인 환경에 대한 요구사항을 정리하고 하나씩 구축해 나갔습니다.
첫 번째로 사무실에 안드로이드와 아이폰 디바이스를 상시 충전 상태로 만들고 수동 테스트와 기기 관리 필요시 효율적으로 작업하기 위한 디바이스팜을 구성했습니다. 디바이스팜 근처에 오디오 재생을 할 수 있도록 메인 머신과 스피커를 연결했고 추후 전수검사 모니터링 스케쥴링이 시작될 때 Appium 세션이 실행되는 동안 의도한 시점에 오디오를 재생하고 중단할 수 있도록 구성했습니다.
두 번째로 온프레미스 대규모 모바일 병렬 테스팅에 필요한 전체적인 기술 스택은 가장 이해도가 높은 Node.js 기반의 WebdriverIO와 Appium Devicefarm 생태계를 활용하여 장시간 측정이 가능하도록 클라이언트와 서버사이드를 구성했습니다. 디바이스팜 서버는 보안을 위해 Authentication을 적용했고 클라이언트가 테스트 실행 요청을 보낼 때 onPrepare에서 API 요청을 통해 서버의 기기 상태를 초기화시킨 후 Appium이 동작할 수 있도록 처리했습니다. 이렇게 함으로써 항상 일관된 실행 결과를 보장할 수 있게 되었습니다.
세 번째로 디바이스팜 기기들을 관리하고 클라이언트와 서버 역할을 동시에 수행할 메인 머신 세팅 및 고정 IP를 부여하고 컴퓨팅 자원 모니터링 가능토록 구성했습니다. 또한 메인 머신에서 안드로이드와 아이폰 기기를 관리하고 있기 때문에 무선 연결이 끊길 경우 자동으로 연결하는 과정을 초기 세팅 이후 주기적으로 진행하여 사람 개입 없이 상시 연결을 보장하도록 했고, 매일 밤 10시부터 다음날 오전 6시까지 스케쥴링 실행을 통해 사람 개입 없이 매일 측정 테스트가 진행되도록 했습니다. 초기 계획은 10대 이상 단일 머신에서 병렬로 실행할 경우 메모리와 CPU에 부하가 있을 거라 판단하여 메인 머신과 서브 머신으로 분리하여 메인 머신에서는 Appium 서버 역할만 수행하도록 허브-노드 구조로 구성할 계획이었습니다. 하지만 컴퓨팅 리소스 모니터링 결과, 클라이언트와 서버 역할 모두 수행함에도 현재 규모에서는 문제가 없어서 메인 머신 1대에 허브-노드 역할 모두 수행하도록 구성했습니다.
마지막으로 테스트 스위트 개발을 진행하는 클라이언트 환경에서 원격으로 메인 서버에 접근하고 디바이스팜 서버에 테스트 실행 요청이 가능하도록 프레임워크 레벨에서의 환경 구성을 진행했습니다.
24시간 365일 상시 테스트 모니터링 시스템을 위한 최종 구조입니다. 해당 구조를 기반으로 사람 개입 없는 테스트 자동화 프로세스와 모니터링 인프라를 갖추게 되었습니다. 올해 가능하다면 병렬 테스트 대수를 50대 가까이 확장할 계획이고, 50대를 적절히 분배하여 전체 프로덕트에 대한 회귀 검증과 프로덕션 환경 모니터링을 보다 높은 테스트 커버리지를 유지하면서 진행할 계획입니다.
그동안의 과정을 글로 압축하다 보니 모든 과정이 문제없이 잘 진행된 것처럼 보이지만 실제로 다양한 문제가 발생했고 해결하는 과정이 필요했습니다.
특히 안드로이드와 아이폰 기기의 충전 상태를 유지하면서 무선으로 메인 머신과 연결할 경우 상시 연결 가능한 환경을 구축해야 하고 지금처럼 메인 머신 1대를 허브-노드 구조로 설계할 경우 각 테스트 요구사항을 달성하면서도 컴퓨팅 자원을 잘 관리할 수 있도록 CPU와 메모리 관점에서 최적화가 필요합니다.
또한 디바이스팜 DB에 쌓이는 테스트 데이터들도 주기적으로 정리가 필요하며 메인 머신의 시스템 데이터가 너무 많이 쌓이게 되면 런타임 환경에서 Appium 실행이 중단되므로 이점 또한 고려해야 합니다. 그리고 메인 서버에 문제가 발생할 경우 서버 재부팅 혹은 메인 서버에서 실행되고 있는 여러 스크립트들 관리가 필요하므로 언제 어디서든 클라이언트 환경에서 메인 서버에 접근할 수 있도록 조치하는 작업이 필요합니다.
가장 중요한 건 장시간 테스트가 진행되는 동안 사람 개입 없이 완전 자동 테스트 프로세스가 진행되기 위해선 기기와 메인서버의 컴퓨팅 자원을 상시 모니터링 할 수 있는 환경이 필요하고 최초 구축 이후에는 모든 자동화 운영 과정에서 필요한 운영 리소스를 최소화하는 형태로 구축하는 것이 중요합니다. 실제로 에이슬립 테스트 인프라는 더 이상 제가 개입하지 않아도 24시간 자동으로 문제 발생 시 복구 및 실행과 결과 리포팅을 진행하고 있습니다. 테스트 자동화 운영에 인력 리소스가 계속 들어가는 형태로 설계 및 구축할 경우 사실상 테스트 자동화의 활용 가치를 극대화시키기 어렵고 제가 추구하는 품질 방향을 달성하기 위한 4가지 사항들을 충족시키기 어려웠습니다.
대부분의 환경에서는 온프레미스 인프라를 직접 구축하고 운영하는 것보다 클라우드 인프라를 활용하여 클라이언트 사이드에만 집중하는 방향이 여러 관점에서 효율적이고 기술적으로도 타당했던 경우가 많았습니다. 병렬 테스트 구성과 더불어 테스트 매니지먼트 자체에 대한 인프라도 함께 제공하기 때문에 대규모 테스트 커버리지를 적절한 디자인 패턴을 활용하여 잘 설계만 하고 서버 사이드로 요청만 보내는 방향이기 때문입니다.
하지만 수면분석 SDK 동작 특성과 더불어 에이슬립만이 가지고 있는 다소 까다로운 테스트 요구사항을 충족시키고 테스트 커버리지를 확장하기 위해서는 클라우드 인프라 도입으로는 해결할 수 없는 기술적인 문제들이 많았습니다. 더불어 잘 설계된 허브-노드 구조로 온프레미스 환경을 구축할 경우 내부 프로덕트에 맞춰서 커스텀한 테스트 환경을 구축할 수 있고 외부 서비스에 의존하는 형태가 아니기 때문에 내부 자산을 적극 활용 가능하며 새로운 테스트 요구사항이 생길 시 보다 빠르게 대응할 수 있습니다.
조직 상황과 구성에 따라 온프레미스 보단 클라우드 인프라를 도입하고 테스트 프로세스를 가속화시키는 방향이 더 나은 경우가 많겠지만 에이슬립처럼 특수한 테스트 요구사항이 있고 이러한 문제를 클라우드 도입으로 해결이 어려운 경우엔 내부 프로덕트의 요구사항을 충족시킬 수 있는 온프레미스 환경을 직접 구축해 가는 것도 좋은 방향이라 생각합니다.
이 글이 비슷한 문제를 해결해야 하는 분들께 도움이 되길 바라며 이만 글을 마치겠습니다. 읽어주셔서 감사합니다.