싸피 9기 자율프로젝트 회고록
💾프로젝트 회고
싸피에서 진행했던 4번의 프로젝트 중 가장 힘들었던 프로젝트였다. 원래는 백엔드 포지션으로 들어갔지만, 갤럭시 워치를 사용하는 아이디어가 나오게 되었고 누군가는 워치 어플을 담당해야 했다. 프론트는 3명으로 고정이었고 백엔드에서 워치 담당자가 필요했는데 새로운 도전을 해보고싶었기에 내가 담당하게 되었다. 결과는 나름 성공적으로 마무리 되었다. 그러나 지금 돌이켜보면 아쉬웠던 점이 안드로이드 구조를 잡는 데 오래 걸렸다는 점이 아쉬웠다. 그리고 프론트가 리액트 네이티브가 아니라 같은 안드로이드였으면 더 다양한 기능을 추가해볼 수 있을 것 같다는 생각도 들었다.
하지만 이번 프로젝트를 통해 증명해냈다고 생각한다.
새로운 기술에 빠르게 적응하고 나름 성공적인 결과를 도출할 수 있다는 것.
이거 하나만으로도 나는 많은 걸 배우고 얻어갔다고 생각한다.
기획
기획에서 걱정이 제일 많았었다. 워치를 혼자 담당하게 됐는데 자바로 할지, 코틀린을 새로 배워서 할지도 제대로 못정했고 이번에는 7주가 아닌 6주 프로젝트를 하면서 더더욱 어깨가 무거워질 수 밖에 없었다.
팀원들이 워치에서 다양한 아이디어를 쏟아냈을 때 물론 아이디어가 많아서 좋기도 했지만 한 편으로는 "언제 적응하고, 언제 저걸 다 적용하지?'"라는 막막함이 존재했다. 그래도 일단 모든 아이디어를 최대한 수용해놓고, 나중에 시간이 부족하면 아이디어를 삭제하거나 수정하는 방향으로 나가기로 결정했다.
그 결과 기획 단계에서는 만들기만 한다면(?) 정말로 1등을 노릴 수 있을만한 디자인과 기획안이 완성되었다.
설계
이번 프로젝트에는 초반에 DB 설계와 API 명세서 설계에 거의 참여하지 못했다.
안드로이드 개발을 처음 시작하다보니 강의를 듣고 책을 보며 예제코드를 따라치기에 바빴었다. 특히 모바일이 아닌 Wear OS를 개발해야 했어서 많은 구글링을 했지만 적당한 강의나 블로그 글이 보이지 않았다.
하지만 같은 안드로이드 스튜디오에서 개발되기 때문에 모바일 코드를 그대로 적용하면서 화면에 스탑워치 어플을 클론 코딩으로 만들었을 때 기분은 굉장히 짜릿했다.
2주정도 지나고 어느정도 안드로이드 구조에 적응이 되었을 때, 내가 필요했던 달리기 데이터, 인증번호 등 서버 요청에 필요한 API를 문서에 적어놓고 디자인에 대해서도 참여하기 시작했다.
Wear OS는 내장 DB로 SQLite를 사용했기에 따로 ERD를 만들지는 않았었다. 지금 생각하면 Room 라이브러리를 통해 Entity, DTO등 구조를 만드는데 얘도 따로 ERD를 만들었으면 더 편리했을 것이라 생각한다.(그 당시에는 바빠서 필요할 때마다 바로바로 만들었었다)
개발
개발에서 어려웠던 점이 정말 많았던 프로젝트였다.
첫 번째로 안드로이드 스튜디오에서 실물 기기 갤럭시워치를 연동하는 방법이었다.
많은 블로그 글들이 워치에 ADB를 켜고 노트북과 워치를 같은 Wifi 환경에서 connect를 하면 된다고 설명했었다. 물론 이 방법은 Wear OS 4가 나오기 전인 2023년 7월 전까지는 가능했다.
위 방법으로 대략 6시간 넘게 삽질을 했었고 gpt, 스택오버플로우, OKKY, 영어 구글링 전부 찾아봤었지만 전부 동일한 내용이었다. 6시간이 조금 넘었을 때 한 줄기 빛을 발견했다. XDA라는 커뮤니티에서 동일한 증상을 발견했고, 댓글로는 Wear OS 4로 넘어가면서 안드로이드 13을 기반으로 하기에 connect 전에 페어링을 진행해줘야 한다는 내용을 발견했다. 바로 적용하니 연결이 정상적으로 됐었다.
위 내용은 여기에 내용을 정리해두었다.
두 번째로 센서 데이터, 위치 데이터, 속도 데이터를 전부 가져와서 1초마다 리스트를 생성 -> 달리기 종료되면 해당 리스트를 MongoDB로 전송해야 한다는 점이었다.
센서 데이터는 SensorManager를 이용해서 심박수, 발걸음 센서를 가져올 수 있었다.
위치 데이터는 기존에는 단순 LocationManager로 이전 위치와의 차이로 이동 거리를 가져왔었다. 그러나 적용하고 GPS가 부정확하고 많이 튀는 경우를 발견했었다. 또한 안드로이드 개발자 문서에서 FusedLocationProvider 사용을 권장하고 있었기에 코드를 바꾸었다. FusedLocationProvider는 자기장 센서, 가속도 센서, 자이로스코프등 다양한 메타데이터를 활용해서 위치를 예측한다. 근데 바꾸고 나서 딱히 정확도가 많이 상승했다고 느끼지는 못했다.
그래서 로직을 받아오는 순서를 변경하기로 결정했다.
기존에는 위치를 먼저 받아오고 이후에 속도를 받아왔다. 둘이 독립적으로 돌았기에 이전 위치와 차이가 난다면 이동 거리, 속도를 바로 리스트에 저장했다.
그러나 이럴 경우 문제점이 위치가 튀어서 갑자기 100m가 이동했으면 속도는 100m/s로 저장된다는 문제가 있었다.
그래서 순서를 바꿔서 if (speed >= 0.3 && speed < 10) 속도를 먼저 판단하고 조건에 해당되면 위치를 받아오게 만들었다. 이렇게 만들면 갑자기 너무 큰 값으로 튀거나, 0.3보다 낮은 경우는 멈춤으로 판단할 수 있었다.
이렇게 센서, 속도, 위치에 대한 정보를 1초마다 저장하도록 구현했다.
세 번째로 1초마다 리스트에 저장하는데 시스템 오차로 인해 70~100초마다 1초가 더해지는 문제가 발생했다.
초기 설계는 startTime = System.currentTimeMillis(); 를 통해 초기 시간을 저장해놓고
1초마다 System.currentTimeMillis() - startTime 를 통해서 현재의 시간을 구하는 방식으로 구현했었다.
postDelayed를 통해 1초마다 재반복 시키기 때문에 이론상 1초씩 늘어나야 정상인데 DB에 총 1200초가 저장됐다고 치면 리스트가 10~50개정도 부족해지는 문제가 발생했다.
리스트가 부족하면 상대방과의 초마다 비교가 불가능해져서 치명적인 문제였기 때문에 시급한 해결이 필요했다.
여기서 해결했던 방법은 초기값을 nanoTime으로 불러오고, 매 초 반복할때마다 정수로 1씩 더해줘서 시간을 계산하게 만들었다. ms나 ns로 보는 것이 아니라 정수로 1씩 더하기때문에 시간이 쌓여서 1초가 더해지는 문제를 없앨 수 있었다.
이 문제에 대한 내용은 여기에 기록되어있다.
정말 짧은 시간내에 많은 투자와 시도를 겪었던 프로젝트였다.
나도 처음에는 해낼 줄 몰랐으나, 반에서 1등까지 간 걸 보니 진짜 열심히 했나보다...(대견)