애플리케이션 개발

달릴시간

WHY

지금 뛸지, 조금 기다릴지 더 쉽게 판단할 수 없을까? 좋은 러닝 시간은 맑거나 선선한 시간과 달랐습니다. 공기질과 열 부담처럼 성격이 다른 신호를 함께 봐야 했습니다.

HOW

건강 리스크와 체감·퍼포먼스 부담을 나눠 보았습니다. 여러 수치를 그대로 나열하지 않고, 지금 뛰어도 되는지 혹은 기다리는 게 나은지를 시간대별 판단으로 묶었습니다.

WHAT

Running Condition Score 기반의 러닝 판단 앱을 만들고 있습니다. 시간대별 조건과 판단 이유를 함께 보여주고, 홈 화면과 아이콘까지 ‘지금 달릴 시간인가’를 먼저 읽게 다듬고 있습니다.

2026-05-11

뛰고 돌아와서야, 몇 시간만 기다릴 걸 알았다

러닝을 마치고 나서야 그 시간의 초미세먼지가 좋지 않았다는 걸 알았다. 뛰는 동안에는 크게 이상하지 않았다. 더 아쉬운 건 몇 시간만 기다렸다면 조건이 나아질 수 있었다는 점이었다.

지친 듯 천천히 달리는 캐릭터 애니메이션

뛰고 나서야 “아, 오늘은 좀 기다릴 걸” 싶어지는 순간. GIF via

GIPHY / Zhot

.

그때의 불편은 단순히 정보를 확인하지 않았다는 문제가 아니었다. 러닝 전에 앱을 몇 개 더 열어볼 수도 있고, 미세먼지 수치를 따로 볼 수도 있다. 하지만 실제로 알고 싶었던 건 수치 하나하나가 아니었다.

오늘 몇 시쯤 달리는 게 가장 좋을까?

이 질문이 달릴시간의 출발점에 가까웠다. 오늘 달릴지 말지, 달린다면 지금이 나은지 조금 기다리는 게 나은지, 나중으로 미루면 실제로 더 좋은 조건이 되는지 알고 싶었다.

몸이 바로 말해주지 않는 위험이 있었다

러닝 조건을 어렵게 만드는 요소들은 서로 성격이 달랐다. 초미세먼지처럼 몸으로 바로 느끼기 어렵지만 주의 깊게 봐야 하는 요소가 있고, 습도나 WBGT처럼 같은 페이스를 더 무겁게 만드는 요소도 있다. 바람은 페이스와 피로도에 영향을 주고, UV는 퍼포먼스보다 노출 부담에 가깝다.

그래서 이 요소들을 모두 같은 방식으로 보면 이상해진다. 어떤 요소는 조금만 나빠도 조심해야 하고, 어떤 요소는 다른 조건과 함께 볼 때 부담이 커진다. 러너에게 필요한 판단은 단순 평균이 아니라, 공기질처럼 주의가 필요한 조건과 체감·퍼포먼스 부담을 구분해서 읽는 쪽에 더 가까웠다.

달릴시간이 만들고 싶었던 것도 바로 그 지점이었다. 환경 수치를 많이 보여주는 앱이 아니라, 러너가 오늘의 실행 타이밍을 더 쉽게 판단하도록 돕는 앱. 지금 뛰어도 되는지, 조금 기다리는 게 나은지, 오늘 중 언제가 더 나은지를 먼저 읽게 하는 앱이었다.

점수보다 먼저 “몇 시?”를 물었다

Running Condition Score는 그 질문을 다루기 위한 하나의 표현 방식이었다. 숫자 하나로 모든 것을 단순화하려는 게 아니라, 여러 환경 조건을 러너의 판단 단위로 다시 묶어보려는 시도였다.

처음부터 완성된 알고리즘이 있었던 것은 아니다. 오히려 반대였다. 어떤 요소를 주의 신호로 볼지, 어떤 요소를 체감 부담으로 볼지, 어떤 조건에서는 조심해야 한다고 말해야 할지 계속 나눠 봐야 했다.

이 프로젝트의 첫 질문은 그래서 “좋은 날씨를 어떻게 보여줄까”가 아니었다. 더 정확히는, 러너가 앱을 열었을 때 이런 답을 먼저 받을 수 있느냐였다.

지금 달려도 괜찮은가.
아니면 조금 기다리는 편이 나은가.

달릴시간은 좋은 날씨를 보여주기 위해 시작한 앱이 아니었다. 러닝을 마친 뒤 “조금만 기다릴 걸”이라고 말하는 시간을 줄이기 위해 시작했다.

현재 위치 기준 RCS와 오늘의 러닝 가이드를 보여주는 달릴시간 홈 화면

달릴시간의 첫 화면은 여러 수치를 나열하기보다, 지금 달릴지 조금 기다릴지를 먼저 판단하게 만드는 방향으로 잡았다.

2026-05-11

날씨를 평균냈더니, 위험이 사라졌다

평균은 깨끗했다. 답은 위험했다.

초미세먼지가 높은 날이었다. 기온은 괜찮고 바람도 나쁘지 않았다. 모든 값을 점수로 바꿔 평균을 냈더니 “달리기 좋음”에 가까운 숫자가 나왔다. 계산은 틀리지 않았다. 그런데 그 숫자를 믿고 밖으로 나가라고 말할 수는 없었다.

숫자를 한 줄로 세우는 순간, 서로 다른 위험이 같은 표정을 짓기 시작했다.

복잡한 계산 앞에서 혼란스러워하는 캐릭터 애니메이션

다 같은 숫자로 바꿨다고 해서 바로 평균낼 수 있는 건 아니었다. GIF via

GIPHY / GifGari

.

브레이크와 승차감은 평균낼 수 없다

러닝 조건은 모두 같은 신호가 아니었다. 초미세먼지는 뛰는 동안 바로 힘들게 느껴지지 않아도 주의해야 한다. 습도와 WBGT는 몸이 느끼는 부담에 더 가깝고, 바람은 페이스와 피로도를 흔든다. UV는 퍼포먼스보다 노출 부담에 가깝다.

이들을 똑같이 깎는 것은 자동차의 브레이크와 승차감을 한 점수로 평균내는 것과 비슷했다. 승차감이 좋아도 브레이크가 고장 났다면 “대체로 괜찮은 차”라고 말할 수 없다. 반대로 보조 신호까지 모두 강하게 깎으면, 조심해서 달릴 수 있는 시간도 사라진다.

그래서 달릴시간의 점수는 예쁜 평균값보다 일관되고 설명 가능한 판단이어야 했다. 어떤 요소는 점수를 직접 크게 제한하고, 어떤 요소는 보조적으로만 반영하고, 어떤 요소는 점수보다 설명에서 더 잘 다뤄야 했다.

요소앱에서 본 역할처리 방향
초미세먼지 PM2.5체감이 약해도 주의가 필요한 공기질 신호주요 기준으로 강하게 반영
PM10독립 주지표보다는 보조 공기질 신호modifier로 반영
WBGT / 열 부담같은 페이스를 더 힘들게 만드는 신호열 스트레스 판단에 반영
UV / 바람 / 습도상황에 따라 부담을 키우는 보조 신호단독으로 과하게 무너뜨리지 않음
강수 / 천둥실행 가능성과 안전 문제강한 제한 또는 blocker

이 구분이 없으면 앱은 숫자를 많이 계산해도 러너에게는 덜 믿기는 답을 줄 수 있었다.

WBGT와 초미세먼지를 서로 다른 부담으로 설명하는 달릴시간 안내 화면

달릴시간은 모든 환경 지표를 똑같이 깎지 않고, 러너가 대처할 수 있는 부담과 피하기 어려운 부담을 나눠 설명한다.

초미세먼지에는 점수의 천장을 만들었다

특히 초미세먼지는 따로 다뤄야 했다. 달리면서 바로 체감되지 않을 수 있다는 점 때문에 더 그렇다. 몸이 괜찮다고 느끼는 것과 실제 노출 부담가 낮다는 것은 같지 않다.

그래서 RCS v1에서는 PM2.5를 primary factor로 두고, 일정 구간 이상에서는 하루 점수의 상한을 제한하는 guardrail을 뒀다.

PM2.5가 하루 절반 이상 지속될 때의 day score 상한
25-35  → 최대 69
35-50  → 최대 54
50+    → 최대 39

좋은 두 시간이 나쁜 하루를 세탁하지 못하게 만든 셈이다. 이 상한은 두 가지를 막기 위한 장치였다.

  • 짧은 좋은 시간대 하나 때문에 하루 전체가 지나치게 좋아 보이는 것
  • 종일 애매하게 나쁜 공기질이 “그럭저럭 괜찮음”처럼 포장되는 것

달릴시간이 알려주고 싶은 것은 “가장 좋은 숫자 하나”가 아니라, 오늘 남은 시간 안에서 실제로 달릴 만한 선택지가 있는지였다.

“오늘 좋다”는 말에는 길이가 필요했다

또 하나의 문제는 시간대였다. 한두 시간만 조건이 좋아도 오늘의 best time은 있을 수 있다. 하지만 그 짧은 구간 하나 때문에 하루 전체를 좋게 말하면 안 된다.

그래서 day score는 단순 평균이 아니라 세 가지를 함께 보도록 잡았다.

best 2-hour rolling average      55%
remaining-hour coverage >= 70    25%
median remaining-hour score      20%

완벽한 정답은 아니었다. 당시 앱이 가져야 할 첫 번째 판단 기준이었다. 반짝 좋은 구간은 추천하되, 그 한 조각으로 하루 전체를 포장하지 않으려는 시도였다.

같은 60점도 이유가 달랐다

RCS를 만들면서 계속 조심해야 했던 것은 숫자가 모든 설명을 대신하게 만드는 일이었다. 점수는 빠르게 읽히는 입구가 될 수 있지만, 사용자가 믿으려면 왜 그런 점수가 나왔는지도 이어져야 한다.

그래서 Home hero에는 점수와 한 줄 해석이 필요했고, 그 아래에는 Best Time과 상세 근거가 필요했다. 어떤 날은 PM2.5가 핵심 이유가 되고, 어떤 날은 열 부담이나 강수 가능성이 더 중요해진다. 점수 하나는 같아도 이유는 다를 수 있다.

달릴시간의 두 번째 고민은 여기 있었다.

같은 60점이라도, 왜 60점인지 설명할 수 있어야 했다.

이 지점에서 앱은 단순히 숫자를 계산하는 쪽에서 벗어나기 시작했다. 공기질처럼 주의가 필요한 조건과 체감 부담을 나눠 보고, 시간대별로 다시 묶고, 그 결과를 사용자가 읽을 수 있는 말로 바꾸는 일이 필요해졌다.

달릴시간에 필요했던 것은 평균을 잘 내는 계산기가 아니었다. 위험을 다른 좋은 조건 속에 숨기지 않는 계산이었다.

2026-05-11

코드는 복구했다. 무엇을 믿어야 하는지는 복구되지 않았다

임시 폴더가 사라졌다. 그 안에는 달릴시간의 코드와 판단 기록 일부가 있었다.

파일을 잃었으니 파일을 복구하면 된다고 생각하기 쉽다. 실제로 더 오래 걸린 것은 따로 있었다. 되살아난 여러 버전 가운데 무엇이 지금의 앱인지, 어느 판단부터 다시 이어가야 하는지 알 수 없었다.

지도는 찾았는데 “현재 위치” 표시가 지워진 셈이었다.

파일을 열지 못해 당황하는 컴퓨터 애니메이션

파일 하나가 아니라 이어가던 기준 자체가 흐려지는 순간. GIF via

GIPHY / WizArt

.

복구된 코드가 현재 코드는 아니었다

처음에는 당연히 복구가 먼저라고 생각하기 쉽다. 하지만 실제로는 파일을 되살리는 일만으로는 충분하지 않았다. 이전 후보가 어떤 판단을 했는지, 현재 앱이 어느 빌드를 기준으로 움직이는지, 사용자가 보게 될 화면이 어느 흐름의 결과물인지가 함께 정리되어야 했다.

그래서 질문은 “어떻게 빨리 다시 만들까?”에서 조금 바뀌었다.

무엇을 현재 truth로 볼 것인가?
무엇은 archive로만 남길 것인가?
어떤 판단은 다시 검증한 뒤에만 가져올 것인가?

이 구분이 없으면 같은 기능을 다시 만들어도, 다음 QA에서 또 다른 기준을 보고 판단하게 된다. 특히 달릴시간처럼 점수·화면·설명·릴리즈 빌드가 함께 맞아야 하는 앱에서는 이 차이가 작지 않았다.

한 작업 공간에 두 개의 시간을 섞지 않았다

이후에는 본선 개발과 PM reset 흐름을 분리해서 보기 시작했다. 하나는 실제 앱을 앞으로 밀고 가는 자리였고, 다른 하나는 사라진 판단과 남은 근거를 다시 읽어 현재 기준을 재구성하는 자리였다.

절차가 늘어난 것처럼 보였지만 실제로는 반대였다. 본선 개발 안에서 복구와 검증과 기록을 모두 섞어두면, 무엇이 제품 결정이고 무엇이 임시 수습인지 금방 흐려졌다.

그래서 달릴시간에서는 한동안 다음과 같은 구분이 필요했다.

  • 현재 사용자가 보게 될 앱 기준
  • 후보 모델을 실험하는 기준
  • 과거 기록을 다시 읽는 기준
  • 출시나 QA에서만 쓰는 기준

이 구분을 세우고 나서야, 다음 기능을 붙이는 일이 조금 덜 불안해졌다.

코드는 결론만 남겼다

이 경험은 제품 자체의 기능은 아니지만, 이후 작업 방식에는 꽤 큰 영향을 줬다. 달릴시간은 단순한 화면 앱이 아니라 판단 모델을 계속 조정해야 하는 앱이었다. 그렇다면 코드만큼이나 “왜 이 판단을 했는지”도 함께 남아 있어야 했다.

특히 러닝 조건 점수처럼 미세한 보정이 쌓이는 영역에서는, 과거 결정을 잃어버리면 같은 논의를 반복하기 쉽다. PM2.5를 얼마나 강하게 볼지, WBGT를 언제부터 기본 기준으로 볼지, 바람과 강수를 어디까지 제한할지 같은 질문은 코드보다 판단의 맥락이 더 중요할 때가 많았다.

이후의 달릴시간 작업은 조금 느려졌고 더 명시적이 됐다. 기능을 붙이기 전에 현재 truth, 바꾸는 판단, 채택 근거, 보류한 후보부터 적었다. WBGT도 계산식보다 역할을 먼저 정했다.

코드가 사라진 날, 달릴시간은 파일 복구법보다 기준을 남기는 법을 먼저 배웠다.

2026-05-11

27도는 같았다. 몸이 받은 더위는 달랐다

온도계는 둘 다 27도를 가리켰다. 한 번의 러닝은 버틸 만했고, 다른 한 번은 같은 페이스가 유난히 무거웠다.

습도, 바람, 햇볕, 복사열이 몸이 받는 부담을 바꿨다. “덥다”를 숫자로 보여주는 것과 “지금 달릴지 조금 기다릴지”를 판단하는 일은 달랐다.

WBGT를 운영 근거로 설명하는 달릴시간 안내 화면

WBGT는 낯선 숫자로 앞세우기보다, 왜 더위 부담을 다르게 봐야 하는지 설명하는 근거로 들어가야 했다.

기온 하나로 빠진 더위를 WBGT가 채웠다

WBGT는 Wet Bulb Globe Temperature의 약자로, 단순 기온보다 열 부담을 더 입체적으로 보려는 지표다. 야외 활동과 스포츠 환경에서 열 스트레스 판단에 참고되는 이유도 여기에 있다. 달릴시간에서는 이 지표를 그대로 권위처럼 가져오고 싶었던 것은 아니었다. 다만 러너에게 필요한 질문은 분명했다.

오늘 몇 시가 덜 위험하고,
덜 힘들고,
그래도 달릴 만한 시간인가?

기온 하나만 보면 이 질문에 답하기 어려웠다. 습도와 바람, 햇볕의 영향이 빠지면 실제 러닝 부담과 앱의 판단이 어긋날 가능성이 컸다. 그래서 WBGT는 더위를 더 잘 설명하기 위한 후보가 되었다.

낯선 지표를 정확해 보인다는 이유로 켜지 않았다

그렇다고 WBGT를 바로 기본값으로 넣을 수는 없었다. 우선 데이터가 문제였다. 모든 지역에서 바로 쓸 수 있는 신뢰도 높은 직접 WBGT 데이터가 있는 것은 아니었고, 앱이 이미 쓰고 있던 Open-Meteo 기반 입력값으로 모델링할 수 있는 범위와 한계를 따져야 했다.

또 하나는 설명의 문제였다. 사용자는 WBGT라는 단어를 처음 볼 수 있다. 앱이 갑자기 낯선 지표를 앞세우면 “정확해 보인다”보다 “이게 뭐지?”가 먼저 올 수 있다. 그래서 내부 모델에서는 열 부담을 더 잘 보되, 화면에서는 러너가 이해할 수 있는 문장과 근거로 풀어야 했다.

이때 기준은 세 가지였다.

  • 기존 입력값으로 계산 가능한가
  • 기존 점수 모델을 과하게 흔들지 않는가
  • 사용자가 납득할 수 있는 언어로 설명 가능한가

WBGT는 이 기준을 통과해야 했다. 지표를 추가하는 것보다 중요한 것은, 지표가 앱의 판단을 더 믿을 만하게 만드는지였다.

환경 지표를 러너가 대응할 수 있는 부담과 어려운 부담으로 나누는 달릴시간 안내 화면

화면에서는 모든 지표를 같은 감점으로 다루지 않고, 러너가 실제로 대응할 수 있는 부담인지까지 함께 설명해야 했다.

WBGT보다 먼저 러너가 이해할 문장이 필요했다

결국 WBGT는 단순히 점수 하나를 더하는 일이 아니었다. 홈 화면, 일별 상세, 정보 시트, 법적 고지, QA 기준까지 이어지는 사용자가 근거를 읽을 수 있는 화면의 문제였다. 앱 안에서 “WBGT를 보고 있다”고 말하려면, 실제 화면의 근거도 그 방향으로 정렬되어야 했다.

그래서 이후 작업은 WBGT v2를 후보로 붙이고, 실제 위치 기준으로 확인하고, Daily detail과 Home hero가 같은 근거를 말하도록 맞추는 방향으로 이어졌다. 이 과정에서 낡은 기온/체감 중심 설명이 남아 있으면 오히려 신뢰가 깨졌다.

달릴시간이 WBGT를 넣은 것은 과학적인 이름을 하나 더 보여주기 위해서가 아니었다. 기온 하나로 설명되지 않는 더위를 인정하고, 러너에게 조금 덜 틀린 시간을 말하기 위해서였다.

2026-05-11

60점은 맞았다. 왜 60점인지는 없었다

60점이 나왔다. PM2.5 때문인지, 열 부담 때문인지, 비 때문인지는 보이지 않았다.

점수는 빠르게 읽혔지만 다음 행동까지 말해주지 못했다. 달릴시간은 숫자를 더 정교하게 만드는 대신, 같은 화면 안에서 왜 지금이 좋거나 왜 기다려야 하는지 설명하기 시작했다.

현재 RCS와 러닝 가이드를 함께 보여주는 달릴시간 홈 화면

홈 화면은 점수만 보여주는 표면이 아니라, 지금 판단과 그 이유로 들어가는 입구가 되어야 했다.

같은 60점이 서로 다른 행동을 요구했다

예를 들어 같은 60점이라도 이유는 다를 수 있다. 어떤 날은 초미세먼지가 높아서 조심해야 하고, 어떤 날은 WBGT가 높아서 열 부담이 크고, 어떤 날은 비나 바람 때문에 실행 가능성이 떨어진다. 숫자만 보면 비슷하지만 사용자가 취해야 할 행동은 달라질 수 있다.

그래서 홈 화면에는 점수와 캐릭터만 둘 수 없었다. 지금 뛰어도 되는지, 기다리면 나아지는지, 어떤 근거로 그렇게 말하는지를 함께 보여줘야 했다. 홈은 점수판에서 판단의 이유를 읽는 화면으로 바뀌었다.

이때 정리한 방향은 비교적 단순했다.

1. 지금 바로 읽을 수 있는 결론
2. 그 결론을 만든 핵심 근거
3. 시간이 지나면 달라지는지 보는 다음 행동

이 구조가 있어야 사용자는 앱의 판단을 그대로 외우는 대신, 자기 상황에 맞춰 받아들일 수 있다.

Home과 Daily detail의 언어를 맞췄다

또 하나의 문제는 화면 사이의 일관성이었다. 홈에서는 WBGT와 PM을 중심으로 말하는데, 상세 화면에 들어가면 다시 낡은 기온·체감 중심 설명이 나오면 사용자는 금방 헷갈린다. 앱 내부에서는 새 판단 모델을 쓰고 있는데, 화면 일부가 예전 언어를 계속 말하는 상태가 되는 것이다.

그래서 Daily detail도 Home hero와 같은 근거 모델을 말하도록 맞췄다. WBGT, PM2.5, PM10, UV, 습도, 바람이 서로 다른 역할로 읽히고, 사용자가 특정 시간대를 눌렀을 때도 같은 판단 구조가 이어지도록 했다.

Daily Detail에서 시간대 점수와 근거를 함께 보여주는 달릴시간 화면

상세 화면에서도 홈과 같은 근거를 말해야, 사용자는 점수보다 판단 구조를 믿을 수 있었다.

이 작업은 UI 문구 수정처럼 보일 수 있지만, 실제로는 신뢰를 맞추는 일이었다. 같은 앱 안에서 서로 다른 기준이 말하면, 사용자는 어느 쪽을 믿어야 하는지 모르게 된다.

신뢰 표면이 QA 기준도 바꿨다

점수와 이유를 맞추기 시작하자 QA 기준도 달라졌다. 화면이 보인다는 것만으로는 충분하지 않았다. 실제 위치에서 Home, Daily detail, 정보 시트, 모델 입력값이 같은 방향을 가리키는지 확인해야 했다. 오래된 빌드나 중간 후보가 섞이면, 잘못된 화면을 보고 맞다고 판단할 수도 있었다.

그래서 달릴시간의 후반 작업은 기능 추가보다 기준 맞추기에 가까웠다. 어떤 빌드가 현재 기준인지, 어떤 후보가 release default인지, 어떤 화면이 아직 legacy 설명을 갖고 있는지 하나씩 확인했다.

점수는 판단의 시작점일 뿐이었다. Home과 Daily detail이 같은 이유를 말하고 실제 위치의 입력값까지 같은 방향을 가리킬 때 비로소 숫자가 제품의 언어가 됐다. 60점을 믿게 만든 것은 60이라는 숫자가 아니라, 그 뒤에서 한목소리로 말하는 화면들이었다.

2026-05-11

가장 예쁜 아이콘은 홈화면에서 사라졌다

후보 보드에서는 어두운 아이콘이 가장 완성돼 보였다. 실제 아이폰 홈에 올리자 다른 앱 사이로 사라졌다.

아이콘은 단독 이미지가 아니라 매일 손가락이 찾는 배포 표면이었다. 질문을 “가장 예쁜가?”에서 “많은 앱 사이에서 바로 보이는가?”로 바꿨다.

달릴시간 최신 아이콘 후보 비교 보드

후보들을 나란히 놓고 보면 완성도 차이가 보였지만, 이것만으로는 실제 선택을 끝낼 수 없었다.

갤러리의 그림과 홈화면의 아이콘은 달랐다

아이콘 후보를 만드는 과정에서는 여러 방향을 시험했다. 신발과 시계 조합, 추상적인 속도/시간 마크, 러너가 시계 링 안에 들어간 형태, 어두운 네이비/틸 계열의 프리미엄한 버전, 손목의 빛이나 러너의 자세를 강조한 버전까지 있었다.

그중 일부는 단독 이미지로 보면 더 그럴듯했다. 하지만 앱 아이콘은 갤러리에 걸리는 이미지가 아니라, 사용자의 홈화면에 놓이는 작은 표면이다. 크기가 줄어들고, 다른 앱과 섞이고, 배경이 밝거나 어두워질 때도 살아남아야 했다.

그래서 판단 기준은 조금씩 바뀌었다.

브랜드 톤과 잘 맞는가
→ 작은 크기에서도 러너와 시간이 읽히는가
→ 실제 홈화면에서 눈에 들어오는가

이 변화가 중요했다. 달릴시간은 사용자가 “오늘 몇 시에 달릴까?”를 떠올릴 때 바로 열어야 하는 앱이다. 그렇다면 아이콘도 조용히 예쁜 것보다, 순간적으로 찾기 쉬운 쪽이 더 맞았다.

홈화면이 후보 보드의 순위를 뒤집었다

결정적인 장면은 실제 아이폰 홈화면에 후보를 올려놓고 본 순간이었다. 어두운 후보는 앱 내부 UI와는 잘 어울렸지만, 홈화면에서는 생각보다 묻혔다. 특히 다크 배경이나 다른 강한 앱 아이콘 사이에서는 존재감이 약했다.

반대로 밝은 피치 계열 배경의 러너 아이콘은 조금 덜 프리미엄해 보일 수는 있었지만, 훨씬 빨리 보였다. 러너가 있고, 손목 쪽 빛이 있고, “달릴 시간”을 확인하는 느낌도 더 직접적이었다.

달릴시간 아이콘 후보를 실제 아이폰 홈화면 라이트 배경에서 확인한 스크린샷

최종 판단은 후보 보드가 아니라 실제 홈화면 위에서 더 선명해졌다.

취향보다 찾는 순간을 기준으로 골랐다

이 과정에서 배운 것은 간단했다. 아이콘은 브랜드 자산이지만 동시에 배포 표면이다. 앱을 설치한 사람이 매번 찾고 누르는 위치에 놓이기 때문에, 단독 이미지의 완성도만으로는 부족했다.

그래서 최종 선택은 “가장 멋진 아이콘”이라기보다 “테스터가 실제로 찾기 쉬운 아이콘”에 가까웠다. 어두운 버전이 더 정제되어 보이는 순간도 있었지만, 달릴시간의 첫 외부 테스트 기준에서는 밝은 러너 아이콘이 더 맞았다.

달릴시간은 날씨를 많이 보여주는 앱이 아니라 러너가 지금 실행할지 판단하게 돕는 앱이다. 아이콘도 설명보다 먼저 그 행동을 불러야 했다. 가장 멋진 후보 대신, 달릴 시간을 떠올린 순간 가장 먼저 찾을 수 있는 후보를 골랐다.

2026-05-14

제주에는 비가 왔다. 앱은 달리기 좋다고 했다

제주에는 비가 꽤 왔다. 달릴시간의 현재 점수와 하루 흐름은 너무 괜찮아 보였다.

비 점수를 더 깎기 전에 확인할 것이 있었다. 앱이 지금 이 위치의 날씨를 제대로 보고 있는가였다. 틀린 입력에 정교한 감점을 얹어도 답은 틀린 채로 남는다.

비를 피해 달리는 캐릭터 애니메이션

비가 오는데 앱이 괜찮다고 말하는 순간, 문제는 점수보다 신뢰가 된다. GIF via

GIPHY / Eddsworld

.

점수보다 데이터 출처를 먼저 의심했다

처음에는 강수 감점을 더 키우거나, 비가 올 때 점수 상한을 더 낮추면 될 것처럼 보였다. 물론 그런 정책도 필요하다. 하지만 그보다 앞에 있는 질문이 있었다.

앱은 지금 어떤 데이터를 보고 “달려도 괜찮다”고 말하고 있는가?

기존 구조에서 Open-Meteo는 중요한 기본 데이터였다. 전 세계 위치를 다룰 수 있고, 다른 출처가 불안정할 때 대체 데이터로도 유용했다. 하지만 한국에서 먼저 쓰는 러닝 앱이라면 현재 비와 가까운 시간대 예보, 미세먼지 관측값은 한국에서 제공되는 출처를 먼저 봐야 했다.

그래서 방향은 점수 공식을 조금 고치는 쪽에서, 데이터 출처를 다시 세우는 쪽으로 이동했다.

한국 위치에는 한국 데이터를 앞에 뒀다

새 구조에서는 한국 위치에 대해 기상청과 AirKorea를 더 앞에 두었다. 기상청 초단기실황과 초단기예보는 지금부터 가까운 시간대의 비, 바람, 습도, 낙뢰 같은 신호를 본다. AirKorea는 가까운 측정소의 PM2.5와 PM10을 본다. Open-Meteo는 없애지 않고, 대체 데이터와 UV/WBGT 보조 데이터로 남겼다.

한국 위치의 러닝 판단
→ 기상청: 현재/근접 시간대 비와 바람
→ AirKorea: 측정소 기반 미세먼지
→ Open-Meteo: 대체 데이터 + UV/WBGT 보조
→ Running Condition Score

핵심은 데이터를 더 많이 붙이는 것이 아니었다. “오늘 달려도 되는가”라는 질문에 더 가까운 데이터를 먼저 보게 만드는 일이었다.

데이터앱에서 맡은 역할
기상청 초단기실황지금 비가 실제로 오는지 확인한다
기상청 초단기예보앞으로 몇 시간의 강수와 바람을 보강한다
AirKorea 측정소국내 PM2.5 / PM10 값을 우선 반영한다
Open-Meteo해외 위치, 장애 상황, UV/WBGT 보조로 남긴다

이렇게 바꾸고 나서야 Running Condition Score(RCS)는 단순한 계산식이 아니라, 출처가 있는 판단에 가까워졌다.

19개 지역이 현재성·거리 문제를 드러냈다

데이터 출처를 바꿨다고 바로 끝난 것은 아니었다. 실제로 한국 여러 지역에서 데이터가 어떻게 들어오는지 확인해야 했다. 제주, 서울·경기, 미세먼지 민감 지역, 남부·동해안·산간·섬 지역까지 19개 위치를 샘플링했다.

구현 과정에서는 AI를 코드 작성 속도를 높이는 보조 도구로도 썼지만, 더 유용했던 지점은 예외 케이스를 빨리 넓혀보는 일이었다. 어떤 지역에서 측정소가 멀어질 수 있는지, 과거 데이터가 현재처럼 섞일 여지는 없는지, 화면에서는 그 불확실성을 어디까지 드러내야 하는지를 반복해서 점검했다.

대부분은 기상청과 AirKorea 조합으로 잘 들어왔다. 하지만 검증을 하면서 두 가지가 보였다.

  1. 과거 시간대 데이터가 현재처럼 보이면 실제 현재값과 다르게 읽힐 수 있었다.
  2. 섬이나 산간 지역에서는 가까운 AirKorea 측정소가 10km 이상 떨어질 수 있었다.

이건 단순한 버그라기보다, 사용자가 앱을 어떻게 믿게 되는가의 문제였다. 데이터가 맞아도 오래된 row가 현재처럼 보이면 신뢰가 깨진다. 측정소가 멀리 있는데 그 사실을 숨기면, 앱은 모르는 것을 아는 척하는 셈이 된다.

모르는 거리는 조용히 드러냈다

그래서 후속 작업은 화려하지 않았다. 과거 시간대 데이터가 현재나 미래 판단처럼 섞이지 않도록 현재 시간 이후만 보게 정리했다. AirKorea 측정소가 멀어지는 경우에는 조용한 신뢰 노트를 둘 수 있게 했다.

이 변화가 크지 않아 보일 수도 있다. 하지만 달릴시간 같은 앱에서는 이런 작은 경계가 중요하다. 점수 하나가 높아도, 사용자가 “이 앱이 지금 내 상황을 제대로 보고 있나?”라고 느끼면 판단은 바로 흔들린다.

결국 이번에 바뀐 것은 날씨 데이터 목록만이 아니었다. 달릴시간이 신뢰를 다루는 방식이었다.

좋은 러닝 시간은 공식 하나로 나오지 않는다. 어떤 데이터를 먼저 보고, 얼마나 최신인지 확인하고, 지역적으로 얼마나 가까운지 의심하고, 부족한 부분은 부족하다고 남기는 일까지 포함된다.

“오늘 달려도 될까?”는 단순한 질문이었다. 그 질문에 단순한 척 답하지 않기 위해 생각보다 많은 신뢰 구조가 필요했다.

2026-05-16

달린 뒤의 기록보다, 나가기 전의 시간이 먼저였다

미세먼지, 더위, 습도, 바람, 비를 함께 보는 앱. 기능은 맞았고 제품은 잘 보이지 않았다.

러너가 달리기 전에 조건을 보는 이유는 위험을 피하기 위해서만이 아니다. 같은 노력을 더 좋은 시간에 쓰고 싶기 때문이다. 홈페이지 문구도 날씨 기능보다 그 선택을 먼저 말해야 했다.

러너에게 중요한 것은 달린 뒤의 기록만이 아니라, 달리기 전에 어떤 조건을 선택했는가이기도 했다.

러너가 이미 믿는 훈련 언어 옆에 놓았다

러너는 기록을 위해 훈련한다. 인터벌을 하고, LSD를 하고, Zone 2를 보고, 카본화를 신고, 컨디션을 관리한다. 이 단어들은 러너에게 이미 가치가 있다.

그래서 달릴시간을 설명할 때도 “날씨 데이터를 분석합니다”라고만 말하면 안 된다고 봤다. 러너가 이미 중요하게 여기는 것들 옆에 달릴시간을 놓아야 했다. 그래야 “언제 달릴지”도 훈련과 기록 사이에 있는 중요한 판단으로 읽힐 수 있었다.

인터벌 훈련만큼 달릴시간이 중요하다는 식으로 러너의 익숙한 언어 옆에 달릴시간을 놓은 히어로 카피

히어로의 키워드는 고정하지 않고 바뀌도록 만들었다. 인터벌 훈련, LSD 훈련, 카본화처럼 러너가 익숙하게 받아들이는 항목이 먼저 나오고, 그 다음에 “달릴시간이 중요합니다”가 이어진다.

LSD 훈련과 달릴시간을 같은 문장 구조 안에 놓은 히어로 카피

이건 단순한 카피 장치가 아니었다. 기능을 만든 뒤, 그 기능을 러너가 자기 언어로 받아들일 수 있게 번역하는 작업에 가까웠다.

기록 앱이 시작되기 전의 질문을 맡았다

달리고 나면 기록 앱을 본다. 거리, 페이스, 시간, 루트, 심박, 구간 기록이 남는다. 그 데이터는 중요하다. 내가 어떻게 뛰었는지, 다음에는 무엇을 바꿔야 할지 알려준다.

하지만 기록 앱은 대부분 달린 뒤의 이야기를 보여준다. 정작 나가기 전에는 아직 기록이 없다. 그때 필요한 질문은 조금 다르다.

오늘 나가도 괜찮을까?
조금 기다리면 더 나을까?
같은 훈련이라면 어느 시간대가 덜 힘들까?

달릴시간이 들어가야 할 자리는 바로 그 앞이었다. 달린 뒤를 평가하는 앱이 아니라, 달리기 전에 오늘의 조건을 먼저 고르는 앱. 이 차이가 보이자 홈페이지와 앱스토어 문구도 달라져야 했다.

환경은 기록 밖의 배경이 아니었다

기록은 실력만으로 나오지 않는다. 같은 러너, 같은 코스, 같은 훈련이어도 환경이 다르면 몸이 받아들이는 부담이 달라진다. 습도가 높으면 같은 페이스도 더 무겁고, 바람이 강하면 유지하던 속도가 흔들린다. 미세먼지와 더위는 기록뿐 아니라 건강 부담까지 바꾼다.

같은 러너와 같은 훈련이라도 환경 조건에 따라 기록과 회복 부담이 달라질 수 있음을 보여준 설명 섹션

그래서 달릴시간은 날씨앱도, 기록앱도 아닌 자리를 잡아야 했다. 날씨앱처럼 수치를 많이 보여주는 것이 아니라, 그 수치를 러너가 실행할 수 있는 타이밍으로 바꾸는 앱. 기록앱처럼 달린 뒤를 분석하는 것이 아니라, 달리기 전에 조건을 고르게 돕는 앱.

이렇게 정리하고 나서야 제품의 문장이 조금 선명해졌다.

기록 앱은 달린 뒤를 보여준다.
달릴시간은 달리기 전에 조건을 고르게 돕는다.

이 기준은 이후 RCS 프로모션 계산기와 공유 카드에도 이어졌다. RCS를 먼저 설명하지 않고 러너가 자기 기록으로 이해할 장면을 먼저 만들었다. 기록 앱은 달린 뒤를 남긴다. 달릴시간은 그 기록이 시작되기 전의 시간을 고른다.

2026-05-17

사용자는 X 하나를 눌렀다. 앱은 그날의 날씨를 기억해야 했다

제주에는 비가 왔다. 달릴시간은 달리기 괜찮은 조건처럼 보였다.

비 점수를 더 깎으면 될 것 같았다. 하지만 그날만 고치면 다음 오판은 또 처음부터 시작한다. 사용자가 “안 맞아요”라고 말했을 때, 앱이 무슨 근거로 그 판단을 했는지 되돌릴 수 없었기 때문이다.

의견은 짧다. 원인은 길다.

러너에게는 세 글자만 받았다

처음 필요한 것은 가벼운 입력이었다. 러너가 앱을 열고 현재 판단을 본 뒤, 그 판단이 지금 체감과 맞는지만 빠르게 알려줄 수 있어야 했다.

그래서 피드백은 세 가지 선택으로 줄였다.

O 맞아요
△ 애매해요
X 안 맞아요

메시지는 선택 사항으로 두었다. 베타 테스트에서 중요한 것은 긴 설명을 받는 일이 아니라, 어느 조건에서 판단이 어긋났는지 반복해서 볼 수 있는 구조였다.

하지만 사용자는 가볍게 말하고, 무거운 기억은 앱이 맡아야 했다. “안 맞아요”만 남으면 그때 앱이 무엇을 보고 있었는지 알 수 없었다.

X 옆에 그 순간의 세계를 붙였다

그래서 피드백에는 사용자의 선택만 붙이지 않았다. 앱이 그 순간 보고 있던 조건도 함께 묶었다.

러닝 판단 피드백 화면은 선택을 가볍게 두고, 현재 위치의 점수와 판단 문구를 함께 보여준다.

  • 플랫폼과 앱 버전
  • 선택한 위치와 좌표 기준
  • Running Condition Score와 상태
  • 화면에 보인 판단 문구
  • 날씨와 공기질 데이터의 주요 값
  • 사용자가 남긴 선택값과 선택 메시지

한 행에는 두 개의 판단이 남았다. 특정 시간과 위치에서 앱이 본 세계와 러너가 느낀 세계였다.

구글 시트는 이 단계에서 가장 가벼운 저장소였다. 처음부터 거대한 분석 시스템을 만들기보다, 베타 단계에서 빠르게 행을 보고 문제 유형을 나누는 편이 더 맞았다.

테스트 제출 로그는 사용자의 선택과 당시 점수, 위치 기준, 상태를 한 행으로 묶어 남긴다.

대부분 테스트 데이터였지만, 이 화면은 구조를 확인하기에 충분했다. 피드백은 메모 한 줄이 아니라, 나중에 “왜 그 판단이 맞거나 틀렸다고 느꼈는지” 다시 추적할 수 있는 단서가 되어야 했다.

피드백 기능이 제품의 주인공이 되지 않게 했다

기술적으로는 홈 화면 안에 피드백 카드를 바로 넣을 수 있었다. 실제로 그 방식이 가장 빨리 확인하기 쉬웠다. 하지만 화면을 보고 나니 문제가 보였다.

달릴시간의 홈은 러너가 “지금 나가도 될까?”를 판단하는 자리다. 그 자리에 피드백 카드가 너무 강하게 들어오면, 앱이 제품이라기보다 내부 QA 도구처럼 보였다.

그래서 피드백 경로를 둘로 나눴다.

  1. 사용자가 원할 때 들어갈 수 있는 설정 → 러닝 판단 피드백
  2. 홈에서는 조건이 맞을 때만 조심스럽게 나타나는 바텀 시트

수동 경로는 항상 열어두고, 홈의 질문은 자주 보이지 않게 했다. 기본 지연 시간과 쿨다운을 두고, 점수가 낮거나 주의 문구가 있거나 비 관련 문장이 있는 순간처럼 피드백 가치가 높은 상황에서만 더 빨리 묻도록 했다.

많이 묻는 대신 물어도 되는 순간을 골랐다

피드백을 잘 받으려면 많이 물어보면 된다고 생각하기 쉽다. 하지만 러너가 앱을 여는 이유는 피드백을 주기 위해서가 아니다. 오늘 뛸지, 조금 기다릴지 판단하기 위해서다.

그래서 피드백은 판단을 방해하지 않아야 했다. 현재 조건을 읽고 나서야 묻고, 한 번 닫으면 일정 시간 동안 다시 묻지 않게 했다. 제출한 뒤에도 며칠 동안은 반복해서 묻지 않는다.

이 조정은 작아 보이지만 중요했다. 피드백 기능은 앱을 개선하기 위해 필요하지만, 사용자가 느끼는 제품의 중심을 빼앗으면 안 된다.

추적도 필요한 흐름만 남겼다

이벤트 트래킹도 같은 기준으로 봤다. 베타 단계에서는 실제로 예보가 로드되는지, 결제 흐름이 열리는지, 피드백이 제출되는지 확인해야 한다. 하지만 모든 행동을 넓게 자동 수집하거나 세션을 다시 보는 방식은 달릴시간에 맞지 않았다.

달릴시간은 위치와 컨디션을 다루는 앱이다. 그래서 분석은 더 조심스러워야 했다. 필요한 이벤트만 직접 남기고, 민감한 값은 공개 콘텐츠나 운영 기록에서 드러나지 않도록 구분했다.

PostHog는 그래서 “사용자를 추적하는 도구”라기보다, 베타에서 핵심 흐름이 실제로 지나갔는지 확인하는 제한적인 장치에 가까웠다. 구글 시트는 피드백의 맥락을 보는 도구였고, 이벤트 트래킹은 흐름이 작동하는지를 보는 도구였다.

PostHog에는 자동 수집이 아니라 필요한 흐름만 직접 보낸 이벤트가 남는다.

의견함이 아니라 학습 루프

러닝 조건을 점수로 만드는 일은 한 번에 끝나지 않는다. 실제 러너가 보고, 뛰어보고, 다르게 느끼는 순간이 쌓여야 한다. 그때 중요한 것은 피드백을 많이 받는 일이 아니라, 나중에 다시 고칠 수 있는 형태로 받는 일이다.

달릴시간의 피드백 구조는 그 기준을 세우기 위한 첫 번째 장치였다.

사용자는 가볍게 말한다.
앱은 그 순간의 조건을 함께 남긴다.
그리고 다음 판단은 그 기록을 보고 다시 조정된다.

사용자의 X는 실패 표시가 아니었다. 달릴시간이 다음에는 조금 덜 틀리기 위한 좌표였다.

2026-05-19

RCS를 설명하지 않았다. 내 페이스부터 넣게 했다

RCS가 높습니다. 처음 보는 러너에게 남는 것은 의미보다 낯선 약어였다.

Running Condition Score는 기온, WBGT, 미세먼지, 바람, 비를 러닝 관점의 0–100으로 묶는다. 하지만 러너가 궁금한 것은 정의가 아니라 그 점수가 자기 달리기에 어떤 차이를 만들 수 있는지였다.

그래서 프로모션 사이트의 질문을 바꿨다.

RCS가 무엇인지 설명하기 전에,
그날 조건이 달랐다면 내 페이스가 얼마나 달라질 수 있었는지 보여주자.

약어보다 익숙한 기록을 먼저 받았다

입력 화면은 러너가 이미 알고 있는 값에서 시작했다. 그날의 RCS, 거리, 페이스. 여기에 비교할 조건을 넣으면, 같은 실력일 때 페이스가 어느 정도 달라질 수 있는지 계산해준다.

두 가지 달리기 조건을 넣고 페이스 차이를 확인하는 RCS 프로모션 입력 화면

이 구조는 광고 문구보다 직접적이었다. “달릴시간이 좋아요”라고 말하는 대신, 러너가 자기 기록을 넣고 “아, 조건이 다르면 이런 차이로 느껴질 수 있구나”라고 생각하게 만든다.

물론 조심해야 할 선도 있었다. 달릴시간은 기록을 보장하는 앱이 아니다. 좋은 조건이 기록에 영향을 줄 수는 있지만, 개인의 기록은 훈련, 수면, 코스, 컨디션, 보급, 장비, 전략 같은 여러 요소에서 나온다. 그래서 결과는 예측이 아니라 참고 시나리오여야 했다.

기록을 맞히는 계산기가 아니라, 조건 차이를 자기 기록으로 읽어보는 장치에 가깝게 만들자.

궁금해진 뒤에야 RCS를 설명했다

RCS 설명은 없애지 않았다. 다만 처음부터 앞세우지는 않았다. 러너가 페이스 차이를 먼저 보고 나면, 그 다음에는 “그럼 RCS가 뭔데?”라는 질문이 자연스럽게 생긴다. 그때 설명이 들어가야 했다.

기온, WBGT, 미세먼지, 바람 같은 조건을 RCS 하나로 묶어 설명한 섹션

여기서도 핵심은 숫자의 권위를 키우는 것이 아니었다. RCS는 복잡한 환경 데이터를 러너가 읽을 수 있는 하나의 판단 단위로 낮추는 장치다. 기온이 같아도 습도와 바람, 햇볕이 다르면 몸이 받는 부담은 달라진다. 미세먼지가 높으면 페이스보다 노출 시간을 먼저 봐야 할 수도 있다.

이런 차이를 매번 직접 해석하라고 하면 앱의 의미가 줄어든다. 달릴시간은 그 해석을 러너의 질문으로 바꾸려고 했다.

오늘 달려도 될까?
조금 기다리면 더 나을까?
이 기록은 조건의 영향을 얼마나 받았을까?

기록을 약속하지 않아야 계산을 믿을 수 있었다

프로모션 사이트를 만들면서 가장 경계한 것은 과장이다. “좋은 조건이면 기록이 오른다”는 메시지는 매력적이지만, 너무 쉽게 오해될 수 있다.

그래서 계산 결과는 하나의 확정값이 아니라 범위와 시나리오에 가깝게 다뤘다. “이 기록은 원래 이랬어야 한다”가 아니라, “그날 조건이 달랐다면 이런 차이를 참고해볼 수 있다”는 말이다.

선을 낮추자 제품의 자리가 더 선명해졌다. 달릴시간은 기록을 예언하지 않는다. 러너가 이미 가진 기록을 그날의 조건과 함께 다시 읽게 한다. RCS는 설명으로 이해된 게 아니라, 내 페이스를 넣어본 뒤 비로소 의미가 생겼다.

참고: Ely et al. (2007), El Helou et al. (2012), Marr & Ely (2010), Cusick et al. (2023), Nikolaidis et al. (2019), Weiss et al. (2024), WHO Air Quality Guidelines, NWS WBGT guidance.

2026-05-19

설명표는 정확했다. 아무도 공유하고 싶지 않았다

처음 결과 화면은 정확했다. 입력값, 비교 조건, 예상 범위를 차분히 보여줬다. 그리고 아무도 저장하고 싶지 않을 것처럼 보였다.

계산이 끝났는데 장면이 남지 않았다. RCS가 러너 사이의 대화가 되려면 결과표보다 자기 기록처럼 간직할 카드가 필요했다.

숫자를 설명하는 화면이 아니라, 러너가 자기 기록처럼 남길 수 있는 이미지가 필요했다.

숫자 앞에 스톱워치를 놓았다

결과 카드의 중심에는 스톱워치를 두었다. 페이스를 말하는 페이지라면, 숫자보다 먼저 기록의 상징이 보여야 했다. 그 아래에는 긴 설명 대신 한 문장을 남겼다.

더 좋은 조건에서 달리면 약 20초 빨라질 수 있어요.

물론 이 문장은 기록을 보장하는 말이 아니다. 입력한 조건을 바탕으로, 더 나은 RCS 시나리오에서는 어느 정도 차이를 참고해볼 수 있는지 보여주는 말이다. 그래서 카드 안에서도 “조건”과 “가능성”의 뉘앙스를 유지해야 했다.

스톱워치, 페이스 비교, QR을 담아 저장·공유할 수 있게 만든 달릴시간 결과 카드

카드 하단에는 “달리기 전, 달릴시간에서.”라는 짧은 문장과 QR을 붙였다. 결과 이미지만 돌면 제품과의 연결이 끊길 수 있기 때문이다. 러너가 이미지를 보고 “이게 뭔데?”라고 물었을 때, 바로 다시 달릴시간으로 이어지는 길이 필요했다.

제품 설명보다 자기 기록의 질문을 남겼다

이 작업을 하면서 가장 크게 바뀐 생각은 이것이었다. 필요한 기능을 만들고 내용을 채워 넣는 것만으로는 충분하지 않다. 러너가 이해하고 공감할 수 있는 말과 장면으로 다시 번역해야 한다.

RCS는 기술적으로는 점수다. 하지만 러너에게는 “오늘 내 페이스가 왜 이렇게 느껴졌는지”, “조금 기다렸다면 달라졌을지”를 생각하게 만드는 단서가 되어야 했다. 그래서 결과 카드는 기능의 출력물이 아니라, 러너가 자기 기록을 다시 이야기할 수 있는 작은 소재에 가까워졌다.

공유 버튼을 붙인 이유도 여기에 있었다. 달릴시간이 먼저 제품을 설명하는 것보다, 러너가 자기 기록을 두고 다른 러너에게 말을 거는 편이 더 자연스럽다.

그날 조건이 더 좋았다면,
내 페이스도 달라졌을까?

이 질문이 공유 카드 안에 남아 있으면, RCS는 낯선 점수가 아니라 대화의 출발점이 된다.

공유를 위해 기록을 과장하지 않았다

카드를 더 강하게 만들고 싶은 유혹도 있었다. “기록이 빨라진다”는 문장은 눈에 잘 띈다. 하지만 달릴시간이 지켜야 할 선은 그 반대쪽에 있었다.

기록을 약속하지 않기. 개인의 성과를 단정하지 않기. 대신 환경 조건이 달리기 체감과 실행 난이도에 영향을 줄 수 있다는 사실을, 러너가 자기 기록으로 다시 읽어볼 수 있게 만들기.

이 카드는 성과를 약속하는 광고가 아니라 조건을 다시 보게 하는 작은 기록이어야 했다. 계산기가 이해를 만들었다면, 카드는 그 이해가 러너의 사진첩과 대화 속에 남는 방식이었다.

2026-06-19

신청 버튼 뒤에 초대·설치·피드백이 남아 있었다

홈페이지에 테스터 신청 버튼을 붙였다. 이메일이 들어왔다. 아직 아무도 앱을 설치한 것은 아니었다.

신청과 사용 사이에는 플랫폼별 계정 등록, 초대, 설치 안내가 남아 있었다. 설치 뒤에는 앱의 판단이 러너의 체감과 맞았는지 돌아오는 길도 필요했다.

신청 버튼은 모집의 끝이 아니라 운영 루프의 입구였다.

이메일보다 플랫폼 계정이 먼저 필요했다

iOS와 Android는 테스트 방식이 다르다. iOS는 TestFlight 초대가 필요하고, Android는 Google Play 비공개 테스트 계정 등록이 필요하다. 특히 Android는 사용자가 실제 Play Store에 로그인한 Google 계정으로 등록되어야 설치 권한 문제가 줄어든다.

그래서 신청 폼에서 먼저 테스트할 기기를 고르게 했다. 선택한 플랫폼에 맞는 계정을 따로 받고, 설치 안내를 보낼 연락처도 구분했다.

테스터 신청 폼은 iOS와 Android를 먼저 고르게 하고, 플랫폼별 계정과 연락처를 따로 받도록 만들었다.

폼 상단에는 “먼저 써보실래요?”라는 초대 문장과 함께 계정을 받는 이유와 사용 목적을 적었다. 러너에게는 신청 화면이지만, 운영자에게는 플랫폼별 초대와 설치 안내의 출발점이었다.

신청 행을 다음 행동으로 바꿨다

신청이 Google Sheet에만 쌓이면 운영자가 놓치기 쉽다. 그래서 신청이 들어오면 Discord의 tester-signups 채널로 바로 알림이 오게 했다.

알림에는 닉네임, 계정, 유입 경로, 등록 시간이 함께 들어온다. 운영자는 이 정보를 보고 TestFlight나 Google Play 테스터 목록에 추가하고, 안내 메시지를 보낼 수 있다.

신청이 들어오면 운영 채널로 바로 알림이 오게 해서, 초대와 설치 안내로 이어질 수 있게 했다.

거창한 자동화가 필요했던 것은 아니다. 테스트 초반에는 신청자 한 명을 놓치는 일도 크다. 누가 어떤 플랫폼으로 신청했고, 다음에 어떤 초대와 안내가 필요한지 바로 확인할 수 있으면 됐다.

신청 → 플랫폼별 초대 → 설치 안내 → 사용 → 피드백

어느 한 단계에서 멈추면 신청자 수가 늘어도 실제 사용자는 늘지 않는다.

설치 뒤에는 러너의 판단이 돌아와야 했다

설치가 끝났다고 테스트가 끝나는 것도 아니었다. 달릴시간은 러닝 조건을 판단하는 앱이므로, 사용자가 그 판단을 어떻게 느꼈는지 다시 돌아와야 했다. “좋아요”나 “별로예요”만 받지 않고, 그 순간 앱이 보고 있던 조건을 함께 남긴 이유다.

앱에서 남긴 피드백은 feedback-manager 채널로 들어오게 했다. 플랫폼, 버전, 위치 라벨, 상태, RCS 점수, 사용자 평가, 메시지를 함께 확인할 수 있다.

앱 안에서 남긴 피드백은 당시 조건과 사용자의 체감 평가가 함께 운영 채널로 들어오도록 했다.

예를 들어 앱은 GOOD이라고 판단했지만 사용자는 “애매해요”라고 느낄 수 있다. 이때 앱이 틀렸다고 바로 단정할 수는 없다. 어떤 조건에서 사용자의 체감과 앱의 판단이 갈라졌는지 다시 봐야 한다.

이 피드백이 쌓이면 RCS를 조정할 때도 더 구체적인 질문을 할 수 있다.

  • 특정 날씨 요소를 너무 약하게 보고 있는가?
  • 위치나 시간대 데이터가 충분히 최신인가?
  • 앱 문구가 실제 체감보다 과하게 낙관적인가?
  • 사용자에게 더 설명해야 할 조건이 있는가?

이렇게 돌아온 피드백은 앱의 판단과 러너의 체감 사이를 다시 맞춰보는 재료가 됐다.

테스트 운영도 제품 경험이었다

베타 테스트는 앱을 열어두는 일만으로 굴러가지 않았다. 사용자가 들어오고, 설치하고, 써보고, 판단을 돌려줄 수 있어야 했다.

물론 아직 완전한 운영 자동화는 아니다. 초대와 안내에는 여전히 사람이 개입한다. 하지만 신청, 초대, 설치, 피드백이 한 흐름으로 연결되기 시작했다는 점이 중요했다.

신청 한 건이 플랫폼별 초대와 설치로 이어지고, 사용 뒤의 피드백이 다시 제품 판단으로 돌아올 때 테스트가 한 바퀴 돈다. 버튼은 러너를 모았다. 운영 루프는 그 러너가 실제로 앱을 쓰고 다음 판단을 바꾸게 했다.

2026-06-22

“일출·일몰도 있었으면” 한 줄이 19시의 의미를 바꿨다

“일출 일몰시간도 있었으면.”

테스터가 남긴 문장은 이게 전부였다. 앱의 점수는 맞았다. 그런데 19시가 햇볕이 줄어드는 때인지, 곧 어두워질 때인지는 따로 찾아봐야 했다.

테스터는 앱의 판단이 실제로는 괜찮았다고 말하면서, 일출·일몰 시간도 함께 보이면 좋겠다는 피드백을 남겼다.

요청대로 일출·일몰 시각만 한 줄 추가할 수도 있었다. 하지만 이 피드백이 드러낸 문제는 정보 하나가 빠졌다는 것보다 컸다. 달릴시간은 시간대별 점수를 보여주고 있었지만, 러너가 그 시간을 어떻게 느끼는지는 충분히 설명하지 못하고 있었다.

19시는 점수만으로 같은 시간이 아니었다

달릴시간은 온도, 습도, 비, 바람, 미세먼지 같은 조건을 묶어 “지금 뛰어도 괜찮은가”를 판단한다. 그래서 처음에는 일출·일몰을 날씨 옆에 붙는 부가 정보처럼 생각하기 쉬웠다.

하지만 러너가 시간을 고를 때는 해가 떠 있는지, 곧 어두워지는지, 시야가 얼마나 남아 있는지도 함께 본다. 특히 여름에는 같은 기온이라도 햇볕이 남아 있는 시간과 해가 넘어간 뒤의 체감이 다르다.

낮에는 기온이 조금 내려가도 햇볕 부담이 남아 있다. 반대로 일몰 직전이나 직후에는 더위 부담이 줄고, 아직 완전히 어둡지는 않아 비교적 부담 없이 나갈 수 있는 시간이 생긴다. 러너가 그 시간을 따로 확인해야 한다면, 앱이 이미 보여준 점수만으로는 충분하지 않은 셈이었다.

시간 카드에 해의 상태가 빠져 있었다

이전 화면도 시간대별 추천은 보여줬다. 18시, 19시, 20시처럼 남은 시간의 점수와 상태를 비교할 수 있었다.

기존 화면은 남은 시간대의 점수와 상태를 보여줬지만, 그 시간이 일몰 전인지 일몰 후인지는 따로 확인해야 했다.

문제는 그 시간대가 러너에게 어떤 시간인지 바로 읽히지 않았다는 점이다. 19시가 해가 넘어가는 시간이라면 단순히 18시 다음 카드가 아니다. 같은 점수라도 “지금 나가면 햇볕이 덜하겠다”거나 “조금 늦으면 시야를 더 신경 써야겠다”는 판단이 달라진다.

이 피드백은 러너가 시간표를 읽는 방식을 앱 안으로 가져오라는 신호에 가까웠다.

일몰을 보너스 대신 판단 맥락으로 넣었다

그렇다고 일몰 전후라고 무조건 점수를 올리면 안 된다. 비가 오거나, 미세먼지가 나쁘거나, 열 부담이 큰 날에는 해가 진다는 이유만으로 좋은 조건이 되지 않는다. 안전 리스크를 흐리면 달릴시간의 기본 판단이 약해진다.

그래서 점수 자체를 크게 바꾸지 않았다. 일출·일몰 시간을 데이터로 가져오고, 추천 시간 안에서 그 맥락을 설명하게 했다. 비슷하게 좋은 후보가 있을 때는 일몰에 가까운 시간을 더 자연스럽게 읽을 수 있게 하고, 화면에는 일몰, 일몰 후 같은 라벨을 붙였다.

반영 후 화면은 추천 시간 안에 일몰과 일몰 후 맥락을 함께 보여줘, 러너가 따로 확인하지 않고도 시간의 의미를 읽을 수 있게 했다.

이제 19시는 숫자만 적힌 시간 카드가 아니다. 러너에게는 햇볕 부담이 줄어드는 시간이고, 20시는 시야 확보를 조금 더 신경 써야 하는 시간으로 읽힌다. 앱이 같은 점수를 보여주더라도, 사용자는 그 시간의 실제 느낌을 더 잘 상상할 수 있다.

한 줄의 피드백이 추천의 단위를 바꿨다

바뀐 것은 기능 수보다 추천 시간을 읽는 방식이었다. 달릴시간이 보던 조건이 날씨 데이터에서 러너가 실제로 시간을 고르는 맥락까지 넓어졌다.

테스터 모집을 열면서 만든 피드백 흐름은 처음에는 운영 장치처럼 보였다. 누가 앱을 써봤는지, 판단이 맞았는지, 어떤 메시지를 남겼는지 놓치지 않기 위한 구조였다. 그런데 실제 피드백이 들어오자 그 흐름은 제품의 가치를 높이는 통로가 됐다.

러너는 “점수가 맞다/틀리다”만 말하지 않았다. 어떤 정보가 있어야 나갈 시간을 고를 수 있는지도 알려줬다. 그 말을 반영하자 19시는 점수 하나가 아니라, 햇볕과 시야까지 함께 판단할 수 있는 시간이 됐다.

달릴시간이 답해야 하는 것은 가장 높은 점수의 시각만이 아니었다. 19시가 러너에게 어떤 빛과 시야의 시간인지까지 보여줘야 했다. 숫자는 그대로였지만, 추천 시간은 비로소 장면이 됐다.