본문 바로가기

내일배움캠프 안드로이드 3기

[TIL] 24.06.21 최종 프로젝트 중간 회고

1. 최종 프로젝트 시작 전

 

 5월 마지막 주를 기점으로 최종 프로젝트 주간에 진입했는데, 그 이후로는 기록을 거의 남기지 못했다. 그도 그럴 것이 배정된 6주를 온전하게 다 쓸 수 있는 것이 아니라, Play 스토어 배포를 위한 비공개 테스트 및 심사에 3주 정도가 소모되기 때문에 3주 만에 MVP(최소 기능 제품) 완성을 요구받았기 때문이다.

 이전에 최종 프로젝트 리더를 지원해둔 상태였는데, 위와 같은 스케줄을 뒤늦게 알게 돼서 꽤나 막막했다. 6주를 모두 개발에 사용해야 만족스러운 기능과 견고함이 보장될 것 같았는데, 3주 만에 기본적인 기능을 갖추고 스토어에 심사를 올리고 중간발표도 준비해야 했다. 엎친데 덮친 격으로 5/28~5/31 기간 동안 나는 예비군 훈련이 예정되어 있었다.

 

그래서 최종 프로젝트 주차 진입 전에, 팀원들을 모아 많은 부분을 진행시켜 두려고 애썼던 것 같다. TF와 QA, 개발(서비스, 코어)로 본인이 주로 담당하게 될 역할을 나누고, 앱 주제를 미리 생각해올 것을 당부했다. 팀 노션이나, 슬랙 등도 이 때 개설해뒀다.

 그리고 주말 간에, 혼자 github에서 project나 milestone, issue, 칸반보드 등에 익숙해지려고 이것저것 써보았다. 아무래도 비교적 긴 호흡으로, 기존보다 큰 규모의 프로젝트를 진행해야 했기 때문에 그런 도구들을 활용하는 것이 효율적일 것 같았다.

 

 이런식으로 데모 레포지토리를 작성해, 여러 가지를 테스트 해보고 실전 프로젝트에서 사용할 label이나 issue template도 이 때 거의 작성해두었다.

 

 이후에는, 적절한 주제를 선정하기 위해 노력했는데 구글이나 네이버의 통계 자료들을 보면서 소비 트렌드를 많이 찾아본 것 같다. 이왕 작업할 거, 수요가 조금이라도 있을 법한 앱을 만들어야 테스트 받기도 쉽겠다고 판단했기 때문이다. 거기에 내가 평소에 겪었던 불편이나 수요에서 몇 가지를 더 생각해 대강 키워드를 정리해뒀었다.

 

 

 

2. 첫째 주(5/27~6/2)

 최종 프로젝트 첫 날에 회의를 거쳐 제안했던 반려견 산책 도우미 앱이 채택됐고, 팀원들과 이를 구체화 시켰다. 깃 컨벤션이나 코딩 컨벤션, 팀 룰도 이 때 모두 확정했다. 또 Figma를 이용해 와이어 프레임을 만들고, 유저 플로우도 예상했다.

 

 나는 팀 작업에 있어서는 task를 구체화 시키고 이를 확실하게 나눠 할당해둬야, 인원들이 일을 효율적으로 할 수 있다고 생각한다. 그래서 먼저 나부터 최대한 프로젝트에 대해 깊게 생각해보고 흐름을 머릿 속에 넣었다. 다음으로는 매주 월요일에 깃 허브에 milestone을 작성하며 각자의 task를 인식하도록 하자고 제안했다.

 본인이 해야할 일이 얼마나 남았는지, 또 당장 어떤 게 우선순위가 높을지, 다른 팀원이 가진 task들과의 프로세스를 생각했을 때 선행되어야 할 것은 어떤 것인지 등 이런 부분들을 스스로 체크할 수 있기를 바라는 마음에서였다. 개발 실력과는 별개로 어떤 일 순서 선택이나 업무 메타 인지가 부족한 경우를 몇몇 봐왔기 때문이다.

Figma 디자인. 지금은 여러 차례 피드백을 받으며 풍성해졌지만, 처음엔 열심히 채워도 꽤나 초라했다

 

업무 분배를 위해 필요한 작업부터 하나하나 고민했었다
그렇게 작성했던 milestone. 처음 작성했던 것이라 구체적이지 못한 부분도 몇 보인다

 

 

 

 

 첫 날 이후로는, 나와 부 리더님 둘 다 예비군으로 자리를 비워야 했다. 그나마 나는 동미참 훈련이라 훈련이 끝나는 대로 zep에 접속해서 팀원들과 진척도를 공유하고 task를 조정했다. 그리고 나는 코어 개발이 주 담당이었기 때문에, 비즈니스 로직과 사용될 entity 디자인에 시간을 많이 할애했다. 대학교 때 데이터베이스 수업을 들을 때 사용했던 UML 다이어그램을 오랜만에 사용하기도 했다.

 기본적으로 data-domain-presentation 레이어를 채택하는 클린 아키텍처이고, 최대한 있을 수 있는 케이스들을 예상해서 usecase들을 설계했다. 그리고 팀원분들에게 필요한 기능 명세를 부탁드렸다.

 

 

 저런식으로 명세를 받아, 내가 구현하지 못한 것은 추가하고 db 스키마에 맞춰 수정해야할 부분은 수정해서 적용 후에 피드백 드렸다.

 예비군을 하면서도 쉬는 시간에 틈틈이 진행되는 걸 확인하고, 앱 구조를 디자인하고 새벽까지 작업해서 domain이랑 data 레이어에 필요한 코드들을 모두 작성했다... 이렇게 했지만서도, 결국에는 훈련 받는 시간에는 자리를 비워야 했기에 내 생각만큼은 진척이 되지 않았다. 계속 함께 있으면서 진척도를 계속 확인하고 즉각적인 피드백을 줄 수 있었다면 좀 다르지 않았을까 하는 아쉬움이 있다.


2. 둘째 주(6/3~6/9)

 훈련이 끝난 둘째 주부터 본격적인 스퍼트를 내기 시작할 수 있었다. 팀원들도 담당한 핵심 task들을 작성하기 시작했고, 나도 튜터님들께 여러 번 여쭤보면서 로직의 구조나 entity 및 db 스키마 디자인의 결함들을 수정했다. 특히 원래라면 서버에서 처리되어야 할 로직들(획득한 산책 데이터들로 얻을 수 있는 스탬프를 판정한다든지)을 클라이언트 상에서 처리해야 했기 때문에, 그 부분들을 작성하느라 시간을 많이 썼다.

 또 처음에는 파이어 베이스가 아니라 내부 db에서 sql 기반으로 데이터들을 저장하려고 했기 때문에 정규화 조건을 모두 달성하고 있는지 신경을 많이 썼고, 나중에 파이어베이스로 이식하게 되면서도 정규화가 깨지지 않도록 노력했다. 

 저렇게 작업을 하다보니 마치 백엔드을 개발하는 듯한 느낌도 들었다.

 

 이 때, 팀원들이 핵심 로직 구현에서 딜레이가 생기는 경우가 많았는데, 그런 부분을 함께 해결하면서 전반적인 task 관리도 해야하고, 프로젝트 관련해서 작성하거나 제출할 것도 많아 정말 힘들었다. 그 와중에 내 맡은 부분은 맡은 부분대로 했어야 하니 밤 늦게까지 작업할 때도 많았다. 

 

3. 셋째 주(6/10~6/16)

 중간 발표가 얼마 남지 않은 상황이었으나, 프로젝트 내에 견고하지 못한 코드들이 많이 보였다. 진작 완성되어서 안정성까지 보장되었어야 할 기능들이 아직 완성조차 되지 않은 부분도 많았다. 제 때 플레이 스토어에 비공개 테스트를 올리고, 중간 발표까지 준비하려면 작업을 하나하나 피드백 하고 기다릴 시간이 없었다.

 그래서 이 주간에는 팀원들이 막혀있는 로직을 내가 직접 짜서 답지로 주는 경우도 많았다. 되도록이면 그러지 않아야 한다고 생각하는데, 어쨌든 프로젝트에는 정해진 데드라인들이 있고 그걸 준수하는게 더 중요하다고 생각해서 달리 방도가 없었다. 

 

 물론 위와 별개로 내가 맡은 부분 자체도 이 때가 가장 어렵고 많았던 것 같다.

 

백그라운드에서 동작하는 산책 로직

 먼저 앱의 핵심 로직인 산책 로직을 작성해야 했다. 유저가 산책을 하면서 앱에서 벗어난다고 해도, 산책 정보 수집을 계속 진행되는 것이 일반적으로 기대되는 UX이기 때문에 산책 로직은 백그라운드 에서 동작시켜야 했다.

 

출처 Android Developers

 

 공식 문서에서 제안하는 백그라운드 작업 의사 결정 flow를 참고해서 선택했는데, 결론부터 말하자면 Foreground Service를 채택했다. 위에도 말했듯이 앱이 백그라운드에 있어도 지속되어야 하는 작업이고, 상대적으로 긴 시간동안 동작하며, 적절한 대체 API를 찾지 못했기 때문이다. 그리고 앱이 다시 화면에 노출되었을 때, 산책 중이던 데이터를 계속 반영해서 보여줄 수 있어야 하기 때문에 onStart() 시점에 Service가 실행 중이라면 bind 처리하고 onStop() 시점에 unbind 처리하도록 했다.

 이 밖에도 백그라운드에서 위치를 수집하는 것은 보안 상, 위험한 작업에 속하기 때문에 관련된 안드로이드 보안 정책에 맞춰 섬세한 처리도 해줘야 했다. 이와 관련해서는 다음에 이 때의 경험을 바탕으로 포스트를 따로 남겨볼 생각이다.

 실제 위치 정보를 이용해 좌표를 저장하고(나중에 산책 경로를 지도에 표시하기 위함), 산책 거리와 시간을 측정하는 부분은 구글에서 제공하는 FusedLocationProvider와 코루틴을 이용해 손쉽게 구현할 수 있었다.

 

Firebase를 이용해 Authentication 처리를 하고 있을 때, 이메일 인증과 회원탈퇴 로직 

 이 부분도 Firebase에 의존해서 Authentication 처리를 하다보니 꽤 까다로웠다. Firebase에서 이메일 인증을 지원하긴 하는데, 가입된 유저에 대한 이메일 인증만을 지원하고 있다. 그래서 기대했던 프로세스인 회원 가입 시에 이메일 인증 요구 프로세스는 직관적이고 말끔하게 구현하기 힘들었다. 이 부분은 관련 UseCase를 모두 작성한 이후에, 팀원 분께는 회원 가입 프로세스를 여러 단계로 나누어서 가입과 이메일 인증 처리를 분리해서 처리하게끔 요청드렸다.

 

 회원 탈퇴에 관해서도, 서버 코드를 직접 작성하는게 아니다보니 Firebase sdk에서 제공하는 회원탈퇴만 실행하면 해당 유저가 만들어둔 원격 DB 데이터들은 그대로 남아 있는 상태가 되었다. 이는 너무 찝찝해서 내 성격 상 그대로 둘 수가 없었다. 별 수 없이 클라이언트 상에서, 탈퇴처리 시에 uid를 이용해 해당 uid로 레퍼런싱 할 수 있는 Storage와 Firestore 내의 서브트리들을 모두 검색해 하나하나 삭제하도록 처리했다. Firestore에서 document 삭제 작업은 하위 문서들이 존재하지 않아야 가능하기 때문에, 정말 하나하나 탐색하는 과정을 거쳐야만 했다...

 

스탬프 획득 조건 달성 판별 로직

 2주차부터 고민하던 거였고, 3주차에 완성하게 되었다. 유저가 산책을 끝냈을 때 어떤 스탬프를 획득할 수 있을지 검사하는 로직이었는데, 본래 서버단에서 처리되어야 할 로직이라고 생각하지만 역시나 Firebase를 이용해는 상황이라 클라이언트에서 구현해야 했다.

 이 때는 추후에 스탬프 종류가 많아졌을 때를 상정해서 퍼포먼스에 주안점을 두고 코드를 작성했다. 스탬프는 특정 기간 당 획득할 수 있는 수가 제한되어 있었고(보통 주 1회), 획득 조건도 다양했기 때문에(n일 연속 산책, 하루에 n km 이상 산책, 일주일 내에 n km 이상 산책 등) 로직을 세심하게 작성해야 했다.

 중복된 스탬프 처리를 염두에 두고 HashMap을 이용한다든지, 특정 기준 정렬을 보장받을 수 있는 데이터셋에 대해서는 이진 탐색을 활용하는 등 기본적인 자료구조와 알고리즘들을 적극적으로 활용했다.

 

Activity간 이벤트 공유 문제

 아무래도 온전하게 SingleActivity로 앱을 구성하려니 팀원들에게 애로사항이 꽃 필 것 같아서, 필요하다면 Activity를 여러개 사용하는 방향으로 프로젝트를 진행했는데 그러다보니 Activity 간에 이벤트 전달하기가 조금 까다로웠다.

 특정 Activity의 처리 결과를, 호출한 Activity 혹은 Fragment로만 전달해주면 된다면 일도 아니지만, 어떤 작업의 종료가 Activity의 종료와 독립적이고 또 처리 결과를 받아야 할 화면이 많다면 난감해진다. 

 그래서 처음에는 Singleton으로 이벤트 처리를 담당하는 ViewModel을 만들어서 필요한 View들에 주입하는 방법을 사용했는데(일종의 Application의 ViewModel이 되는 격), AAC ViewModel의 설계 의도와는 벗어나는 패턴 같아서 다른 방법을 고민했다.

 이 부분은 튜터님과 함께 상의 했는데, 아예 이벤트 처리를 위한 클래스를 하나 새로 생성하길 권하셨다. 네트워크나 OS에서 종종 보던 구조인 Bus가 생각나서 SharedEventBus와 같은 식으로 이름을 명명했다. 이를 domain 레이어에 인터페이스로 만들고 presentation 레이어에서 구현체를 만들었고, Hilt를 통해 Singleton으로 필요한 곳들에 주입했다. 내부에서는 SharedFlow와 이벤트를 방출하는 메소드 등을 구성했고, 이를 이용해 반려견 정보가 변동되었을 때 반려견 정보를 노출하고 있던 화면들은 일제히 변화를 감지할 수 있게 되었다.

 

 이 외에도, View도 많이 손 보고, 프로젝트 내에 MVVM이 올바르지 않은 형태로 적용된 부분이 많고 예외처리도 미흡한 부분이 많아서 주말 새벽까지 리팩터링 했다. 중간 발표 날인 6월 17일 오전이 되어서야 얼추 끝낼 수 있었고, 사실 그마저도 성에 찰 정도로 리팩터링이 끝난 건 아니었다. 그렇게 변경한 부분들에 대해서는 팀원분들께 한번 간략하게 설명드려서 추후 진행에 차질이 없도록 했다.

 

4. 중간 발표와 그 이후(6/17~)

 그래도 발표까지 괜찮게 진행할 수 있었고, 이후엔 플레이 스토어에 올릴 MVP를 조금 더 손보기로 했다. 주로 버그 픽스와 안정성을 위한 예외처리, UI처리를 진행했다. 그렇게 6월 20일 경에 완성된 MVP를 플레이 스토어에 비공개 테스트를 위한 심사에 올려둔 상태이고, 이후 남은 2~3주 간은 비공개 테스트 과정에서 받는 피드백 대응과 시간 문제로 넣지 못했던 기능들을 추가할 생각이다.

 

 

 

 시간이 촉박하고, 혼자하는 프로젝트가 아니라서 힘든 부분이 엄청 많았지만 혼자 작업했다면 겪지 못했을 다양한 버그도 고쳐보고, 튜터님들의 의견을 여쭤보며 기술적 의사결정을 했던 부분들이 값졌던 것 같다. 또 리더 포지션으로서 내가 맡은 부분의 개발뿐만 아니라 프로젝트 자체의 프로세스와 완성을 계속 생각하면서, 프로젝트를 바라보는 시야가 넓어지는 경험이 되었다.

 아직 많이 부족하지만, 항상 무얼하든 정해진 기간 내에 어떻게든 일정 선 이상의 완성도로 해내려고 노력하고 있는데 아무래도 그 덕에 많이 성장한 것 같다. 남은 기간도 최대한 타이트하게 진행해서 좋은 결과물을 완성해내고 싶다.