다음 분기에 5개월 일하기 vs. 지금 5시간 논의하기

DB를 다루는 당신이 절대 잊으면 안 되는 3가지

Chan
DelightRoom
12 min readApr 10, 2024

--

누구나 한 번쯤은 해봤을 삽질

엑셀이나 노션에서 여러 테이블을 합치거나 내용을 옮기다가 삽질한 적 있으신 분?! 🙋

저부터 고백하자면, 수도 없이 경험한 것 같습니다. 팀에서 보고서 템플릿을 바꿔서 예전 내용을 옮겨야 할 때, 고객사 별로 같은 문서에 내용만 다르게 사용하고 있었는데 하나 수정하면 다른 곳도 다 일일이 바꿔줘야 할 때… 사용하는 툴에 따라 이런 일이 매우 적을 수는 있지만, 그래도 최소 한 번쯤은 이런 경험을 하셨을 거예요.

모바일/웹 서비스에서도 이 엑셀같은 존재가 있으니, 바로 데이터베이스(Database, DB)입니다. 유저 혹은 서비스 자체에 대한 여러 데이터가 쭉쭉 쌓이는 곳이지요. 엑셀과 마찬가지로, DB에서도 값을 추가하거나 아예 새로운 구조로 바꿔야 하는 경우가 꽤나 자주 있습니다.

이럴 때 어떻게 하면 삽질을 덜 할 수 있을까요?

280시간이 남긴 교훈

Wake up 스쿼드에서는 유저의 알람, 수면 모드 사용 기록을 서버에 저장하는 “동기화” 기능을 준비하고 있습니다. 클라우드 저장, 백업 같은 이름으로 익숙하실 텐데요, 앱을 재설치하거나 기기를 변경해도 과거 기록을 그대로 받아올 수 있도록 하는 것이 이 기능의 목표입니다.

동기화 기능을 준비하기 위해, 새해 첫 3개 스프린트 동안 앱 내 DB에 대한 대대적인 업데이트 작업을 진행했습니다. 비유하자면 지금까지 쓰던 엑셀 파일을 새로운 스프레드시트로 모조리 옮겨가는 작업이라고 이해하시면 됩니다.

그.런.데! 이 준비 과정에만 Android, iOS 양 플랫폼에서 도합 280시간 정도의 시간이 소요되었습니다. 이를 한 명의 개발자의 리소스로 환산하면 약 9개 스프린트, 즉 5개월에 달하는 시간이었어요.

작업이 큰 만큼 DB를 어떻게 바꿀지, 왜 그래야 하는지에 대한 많은 논의가 있었습니다. 그런데 논의보다 더 어려운 것은 ‘어디서부터 어떻게 논의를 시작하지?’ 시작점을 잡는 것이었어요. 모든 작업이 끝나고 지난 논의들을 돌아보니 딱 3가지 체크리스트로 정리되었습니다.

  1. 제품의 OOO 확인하기
  2. OOO인 상황 상상해보기
  3. 제품이 사용되는 OOO 확인하기

각각 생생하고 따끈따끈한 사례와 함께, 논의를 시작하기 좋은 질문들을 소개해드릴게요. DB를 처음 설계하거나 변경, 개선하려 하신다면 이 세 가지만 꼭 기억하시길 바랍니다. 지금 잠깐 5시간 머리 싸매고 논의하면 미래의 5개월을 아끼실 수 있을 거예요.

첫째, 제품의 OOO 확인하기

👀 힌트: 1년 뒤 우리 제품의 모습은?

답을 맞추실 수 있도록, 이번 프로젝트에서 겪은 예시부터 보여드릴게요. 😉

첫 번째 체크리스트에 대한 사례는 바로 알람 기록 쪽에서 나왔습니다. 기존에는 하나의 알람에 대해 울리고 해제되기까지의 기록이 같은 행에 기록되고 있었어요. 알람이 울리면 새로운 행이 생기면서 울린 시각이 기록되고, 이후 스누즈를 하거나 해제함에 따라 그 행이 업데이트되는 방식이었죠.

그런데, 개발자 분들과의 논의 자리에서 이런 질문이 나왔습니다.

“나중에 어떤 값이 또 추가될 수 있나요?”

이 질문이 나온 이유는, 이대로라면 나중에 알람 기록에 새로운 데이터를 추가하고 싶을 때 또! DB Migration을 진행해야 하기 때문이었어요. 예를 들어 지금은 횟수로만 집계되는 스누즈에 대해 스누즈한 시점을 기록하기로 한다면, 지금 테이블에 새로운 칼럼을 추가해야 하죠.

그런데 또 그 다음에 미션 성공, 실패 타이밍을 저장하고 싶어진다면요…? 또 또 DB Migration을 진행해야 합니다.

그렇다고 앞으로 추가될 데이터를 지금 당장 확정해서 미리 테이블 구조를 변경하는 것에는 무리가 있었어요. 제품은 유저와 유기적으로 소통하면서 바뀌어 나가는데, 미래를 100% 확신할 수는 없거든요.

오케이! 그렇다면 지금 필요한 것은 두 가지네요.

  1. ‘미래에 필요한 대로 구조가 정해진 테이블’이 아니라, ‘미래의 필요에 쉽게 대응할 수 있는 유연한 테이블
  2. 대신 지금 구조처럼 하나의 알람이 울리고 해제되기까지 한 세트로 묶이는 것은 유지해야 합니다.

이 요구 사항에 맞추어 새롭게 테이블 구조를 짰습니다. 알람 관련된 기록들을 대등한 관계로 두고, 같은 알람에서 발생한 것이라면 같은 “울림 ID” 값을 갖도록 설계했어요. 이렇게요!

이쯤에서 정답을 공개해볼까요. 답은 바로 “제품의 [ 로드맵 ] 확인하기”입니다.

제품/서비스이든 여러분이 개인적으로 관리하고 있는 테이블이든, 처음 만든 그대로 있지 않을 거예요. 앞으로의 전략과 방향성이 있을 것입니다. DB 구조를 바꾸고 이전 내용을 고대로 옮겨오는 것은 매우 많은 리소스를 필요로 하는 만큼, 앞으로 나아가려 하는 지점을 확인하고 그에 대응할 수 있는 구조로 설계하시는 것이 중요하답니다. 제품의 로드맵, 즉 어떤 기능들이 예정되어 있는지 확인하면 나중에 아차차!! 하고 후회하는 일을 예방하실 수 있을 거예요.

  • ☑️ 앞으로 {이런이런 기능}을 추가하게 될 수도 있는데 문제 없을까?
  • ☑️ 반대로, {이런 기능}은 빼버릴 수도 있는데 이 칼럼이 없어져도 괜찮을까?
  • ☑️ 나중에 로드맵이 바뀌어도 지장이 적은 방법은 없을까?

🍯 꿀팁: 앞으로의 로드맵이 명확하지 않다면, 비슷한 서비스에는 어떤 데이터가 있는지 구경해보세요!

둘째, OOO인 상황을 상상해보자!

👀 힌트: 이 데이터를 하루 1000개, 매일 10년씩 쌓는다면?

두 번째 사례는 수면 쪽에서 나왔습니다. 수면 모드를 사용하면 저장되는 수면 단계와 코골이 데이터에 대한 것이었는데요. 기존에는 매 1분마다 당시 시각과 수면 단계가 기록되고 있었습니다.

이번 논의의 불씨는 서버 비용을 산정하다가 나왔습니다. 수면 데이터가 1분마다 쌓이다 보니, 지금은 기능이 출시된 지 얼마 되지 않아 크기가 작지만 이대로 가면 엄청난 규모가 될 수 있었어요. 예를 들어 만약 한 명의 유저가 매일 8시간씩 수면 모드를 사용한다면, 그대로 10년이 지난다면? 180만 개 행이 됩니다. 만약 230만 DAU가 모두 이만큼씩 사용한다면…? 아찔하지요?

여기서의 문제는 단순히 데이터 양이 많다!가 아니었습니다. 다르게 구성하면 같은 데이터를 더 작은 양으로 담을 수 있다는 것, 즉 현재 데이터에 낭비가 있을 수 있다는 게 진짜 문제였죠. 연속된 시간에 수면 단계나 코골이 분류값이 같다면, 하나의 행으로 표현할 수 있으니까요.

물론 이렇게 구현된 데에는 목적이 있었습니다. 수면 관련 기능은 갓 배포된 따끈따끈한 기능이다 보니, 원본 데이터의 가공 기준을 조정하기 위해 원본 그대로 저장해둔 것이었습니다. 다행히 이 시점에는 그 기준이 어느 정도 안정화되어 원본이 아닌 가공 상태로 저장해도 되는 상태였어요.

그리하여, 슬립 스쿼드와의 논의 끝에 수면 단계와 코골이 테이블의 구조를 바꾸게 되었어요. 앞선 예시 화면의 6개 행이 단 3개 행으로 줄어들게 됩니다. 수면 단계가 10분마다 바뀐다면 1/10로, 30분마다 바뀐다면 1/30으로 줄어들게 되었죠!

두 번째 체크리스트의 정답은 “[ 극단적 ]인 상황을 상상해보자!”입니다. 일반적인 상황에는 문제가 없어 보이더라도, 극단적인 양, 극단적인 시간을 가정해보면 현재 어느 부분에 비효율이 있는지 눈에 보일 거예요. 이렇게 극단적인 상황을 상상하여 지금의 구조를 최대한 효율화 해두면, 앞으로 DB 구조를 유지보수 해나가는 과정에서 생길 문제가 줄어들어 전체적인 비용이 줄어들게 될 것입니다.

극단적인 상황을 상상해보기 위한 질문 리스트!

  • ☑️ 이 기능을 10,000명의 유저가 하루에 1,000번 10년 내내 사용한다면?
  • ☑️ 지금 저장하고 있는 데이터의 목적인 무엇이지? 꼭 필요한가?
  • ☑️ 지금 저장하고 있는 데이터 중 하나로 통합할 수 있는 것은 없을까?

셋째, 제품이 사용되는 OOO 확인하기

👀힌트: 새로운 OS로 확장한다면? 웹/앱을 연결한다면?

지금까지 알라미는 서버보다는 클라이언트 내에서의 동작을 중심으로 발전해 왔습니다. 알람을 울린다는 것 자체가 OS(운영체제)와 긴밀히 통신해야 했기 때문인데요. 그러다 보니 핵심 정책은 공유하되, 세부적인 로직은 안드로이드와 iOS 각 OS에 최적화되어 있었습니다.

세 번째 사례는 이 배경에서 탄생했습니다. 바로 동일 기능인 “미션”에 대한 OS 별 이름 차이였어요.

지금까지는 양 OS에서 사용하는 DB 이름이 달라도 아무런 문제가 없었습니다. 동기화 기능을 배포하는 현 시점에도, 아직 양 플랫폼 각각 다른 로그인 방식이 붙어 있기 때문에 당장도 문제가 없어요. 하지만! 언젠가 안드로이드에 애플 로그인을, 아이폰에 구글 로그인을 붙인다면? 그러면 안드로이드 기기에서 올린 데이터를 아이폰에서 읽을 수 있어야겠죠.

지금 이대로라면 나중에 기능이 발전되었을 때 과거 데이터에 대해 또또또 Migration 작업을 진행해야 합니다. 해서 이참에 이름값도 완전히 통일하기로 했어요. 작업 비용이 거의 추가되지 않았거든요.

어떤 이름값을 통일했냐고요? 예를 들면, 기존에 “메모리 미션”을 지칭하는 값이 안드로이드에서는 memory, iOS에서는 memorygame 으로 달랐습니다. 처음 기능이 만들어졌을 때 ‘메모리 게임’이라는 이름으로 출시되었다 보니 이런 차이가 생긴 거였죠. 이번 작업에서 memory라는 이름으로 iOS 쪽에서 수정을 진행했습니다.

자 그런데… 아이러니하게도, DB Migration 작업을 유저에게 배포한 뒤 이 통일 작업이 얼마나 중요한지 절절히 깨닫게 됩니다. 배포 첫 주에 “미션 화면이 보이지 않는다”는 버그 리포트가 쇄도하기 시작했어요. 순간 쎄-한 느낌이 들더군요. 버그 리포트를 조사해보니 메모리 미션을 사용한 유저들에게서 발생하고 있었고, 원인은 DB Migration 과정에서 메모리 미션 이름에 대한 변수를 바꾼 것 때문이었습니다. 그 이름이 단순히 저장할 때만 쓰이는 게 아니라, 알람 해제 화면을 띄울 때에도 쓰이고 있었던 것이에요. 하루만에 원인 파악 후 수정 업데이트까지 완료했지만, 아찔한 순간이었습니다.

버그가 발생했으니 회고를 해보았죠. 다음엔 어떻게 하면 더 잘할 수 있을까? 1번은 테스트를 더 꼼꼼히 하는 것. 하지만 애초에 이 값을 이번에 왜 바꾸어야 했는가?에 대한 답은, OS 간 통일성 때문이었습니다. 애초에 통일되어 있었다면 없었을 일이고, 반대로 지금 양 OS에서 이름이 다른 값이 있다면 미래에도 발생할 수 있는 일이었죠. 오히려 0번 액션 아이템은 신규 기능을 만들 때 DB에 저장되는 값에 대해 양 OS 모두 같은 이름을 쓴다!가 되었습니다.

세 번째 체크리스트의 답은 “제품이 사용되는 [ 플랫폼 ] 확인하기” 입니다. 안드로이드, iOS뿐 아니라 제조사 별 OS, 웹/앱 간 호환, Watch/Pad OS 등 우리가 사용할 수 있는 운영 체제는 생각보다 많습니다. 서비스가 작을 때에는 DB 안에 들어가는 특정 값을 바꾸고 그것을 테스트하는 일이 크게 어렵지 않을 수 있습니다. 하지만 제품이 커지고 복잡도가 높아질수록, 우리가 지금 바꿀 이 값이 언제 어디에서 쓰일지 100% 확신하기 점점 어려워집니다. 기존 정책 조사에 따로 시간을 투자해야 한다는 의미이고, 잘 조사한다 한들 모든 것을 완벽히 테스트하기도 어렵고요.

최선은 배포 전에 값을 맞춰두는 겁니다. 지금 5분 논의해서 나중에 정책 파악, 디버깅, 수정하는 5시간을 아낄 수 있는 것이지요.

여기서의 체크리스트는 아주 단순합니다.

  • ☑️ 지원하는/지원할 플랫폼에 어떤 것이 있는가? 여러 플랫폼에서 같은 형식과 값을 쓰고 있는가?

🍯 꿀팁: Database에 사용할 칼럼 이름, 값 이름에 대해 원칙을 세워두면 이름 통일을 위한 논의 시간이 짧아지겠죠?

3개만 기억합시다

자 데이터베이스를 다룰 때 고려해야 할 3가지를 모두 말씀드렸는데요, 각각을 하나의 키워드로 표현하면 이와 같습니다.

  1. 제품의 방향성 확인하기 → 확장성
  2. 극단적인 상황 상상해보기 → 지속성
  3. 제품이 사용되는 플랫폼 확인하기 → 호환성

이 세 가지 모두 제품의 성장이라는 목적을 바라보고 있습니다. 시간이 지날수록 제품이 성장, 즉 곡선이 우상향할 수 있도록 하는 것. 그 곡선이 최대한 가파르게 올라갈 수 있도록 병목을 제거하는 것이 목적인 것이죠.

따라서 데이터베이스에 대한 논의가 애초에 왜 필요한가? 라고 누군가 묻는다면, 논리적으로 완벽한 구조를 짜기 위해서가 아니라

우리의 제품이 잘 성장할 수 있도록 기반을 다지기 위함입니다!

라고 답변할 수 있어야 합니다.

돌아올 수 없(을 정도로 어렵다)는 강

구글 시트에서 “모두 바꾸기”로 변경하듯이 DB 값을 몇 초만에 휘릭 바꿀 수 있으면 얼마나 좋을까요. 앗 잘못됐다 싶으면 ctrl + z로 복구하고요.

모바일 제품에서 돌이키는 것이 불가능한 문제가 어디있겠습니까마는, 돌이키기 어려운 문제가 있는 것은 확실합니다. 그만큼 신중하게 논의를 해야겠는데, 대체 무엇에 대해 어떻게 풀어나갈지 고민이 되곤 하죠. 그런 순간에 이 3개 키워드가 도움이 되길 바라봅니다.

알라미의 사례를 참고하여 여러분의 서비스에 대입해서 질문을 던져보세요. 논의에 뜨거운 불이 붙을 거예요 ❤️‍🔥

👇 이렇게 DB 설계를 두고 치열하게 논의하고 싶으시다면?

딜라이트룸의 다양한 채널들을 팔로우하고 빠르게 소식을 받아보세요!

--

--