프로젝트/[앱] 플랭고

[해커톤 후기] 플랭고 앱 개발기

gmelon 2023. 1. 21. 23:15

9월 말부터 11월 초까지 충남대 SW중심대학 사업단에서 주최하는 해커톤인 ‘콜라톤’에 참가하여 계획 관리 & 기록앱을 개발하고 결과적으로 3등상인 우수상을 수상했다!

어떤 과정을 거쳐 기획 및 개발이 이뤄졌는지 또, 앞으로는 어떤 방향으로 프로젝트를 발전시켜나갈 지 간단히 기록해보고자 한다.

참여 계기

백엔드 공부를 해오면서 계속해서 강의만 듣고 예제 코드만 따라 치다보니 너무 지루하고 공부를 해도 계속 까먹는 것 같았다. 인프콘에서 영한님께서 공부만 해선 안 되고, 반드시 내 것으로 만들기 위해 직접 기술을 사용해보라고 하셨던 이야기도 계속 맴돌았다.

 

내가 가진 지식으로 내 서비스를 직접 만들어보고 싶다는 생각이 강하게 들던 와중에 마침 우리 학과 동아리에서 해커톤을 주최한다길래 며칠 고민하다가 (내가 가진 지식으로 뭔가 만들어낼 수 있을까? 남에게 피해 주지 않을까? 하는 두려움이 있었다) 냅다 지원해버렸다.

프로젝트 진행

기획 단계

콜라톤(콜라보레이션 + 해커톤)이라는 대회이름에서 유추할 수 있듯, 이 해커톤은 개발자들끼리만 모인 대회가 아니라 서로 다른 학과의 사람들이 모여 각자가 가진 기술과 능력을 조합해 무언가를 만들어보자! 하는 컨셉으로 개최된 대회이다. 우리는 경영학과와 식물자원학과 출신(?) 기획자 2명과 컴공 개발자 2명이 합쳐져 총 4명이서 팀을 이뤄 프로젝트를 진행했다.

 

해커톤에서 제시한 프로젝트 주제는 앱을 통해 일상의 불편함을 해결하는 것이었다. 우리는 3-4번의 아이디어 회의를 진행하면서 공통적으로 누군가와의 만남에서 계획을 세우는 것의 어려움에 공감하여 이러한 문제를 해결하는 앱을 개발하는 쪽으로 방향을 정했다. 나아가 SNS에 익숙한 세대를 겨냥해 계획마다 별도로 기록을 할 수 있게 하고, 그 기록을 이미지로 이쁘게 가공해 SNS에 공유할 수 있도록 하는 기능도 기획했다.

 

결론적으로 아래와 같은 애플리케이션의 기능 요구사항이 만들어졌다.

  • 계획 기능
    • 장소를 검색해 오늘의 계획에 추가할 수 있다.
    • 마땅히 갈 곳이 없는 경우 중심 주소를 입력하고 그것을 기반으로 새로운 장소를 추천받을 수 있다.
    • 일정 마다 간단한 메모를 적을 수 있다.
    • 이를 리스트로 한 눈에 볼 수 있게 하여 일정 중 계속해서 참고할 수 있게 한다.
  • 기록 기능
    • 각 일정 별로 간단한 해시태그를 남길 수 있다.
    • 각 일정 별로 긴 글 일기를 적을 수 있다.
  • 공유 기능
    • 계획 리스트, 기록 리스트, 긴 글 일기 모두 이미지로 가공해주는 기능을 제공한다.

내 백엔드는..?

내가 콜라톤에 참여했던 이유는 앞서도 이야기했듯 그동안 공부했던 백엔드 기술을 직접 만든 서비스에 적용해보고 싶어서이다. 하지만 막상 기획을 완료하고 요구사항을 적어놓고 보니 이정도면 백엔드 없이도 충분히 개발이 가능할 것 같았다. (백엔드를 추가하는게 별로 의미가 없어보였다.)

 

설상가상으로 개발 팀원 2명 중 한 명이 개발을 거의 진행할 수 없는 상황이라 만약 백엔드 구현까지 진행한다고 하면 혼자서 앱 프론트와 백엔드를 모두 개발하여 시간 내에 앱을 완성시켜야 하는 상황이었다.

 

그래서 우선 이번 해커톤에서는 백엔드 없이 프론트와 내장 DB로만 이루어진 버전으로 앱을 완성하고, 대회가 종료되고나서 로그인 기능, 친구의 계획 및 기록 보기 기능, 공유하기 기능 등 백엔드가 필요한 기능을 추가하면서 백엔드 기술을 적용하고 연습해보기로 결정하게 되었다.

인프런 Flutter 강의 벼락치기

우선 백엔드를 포기한다고 해도 어쨌거나 당장 혼자서 앱 프론트를 개발해야되는 상황에 처해버렸다. 앱 개발은 중학생 때 호기심에 열심히 남의 코드를 복붙해 만든 앱이 유일한 경험이었기 때문에 자연스레 낮은 초반 러닝 커브가 가장 중요한 스택 선택 조건이 되었다. 그러면서도 해커톤 이후에 실제로 앱을 마켓에 출시해보고 싶은 욕심도 있었어서 이왕이면 네이티브가 아닌 크로스 플랫폼 대상 빌드를 지원하는 스택을 선택하고자 했다.

 

커뮤니티나 공부할 자료가 많고 크로스 플랫폼을 지원하는 스택은 React Native와 Flutter가 거의 유일한 것 같았다. 이 중 위젯(Flutter에서 UI를 구성할 때 사용할 수 있는 일종의 컴포넌트) 기반으로 빠르게 앱을 만들어볼 수 있는 Flutter를 선택했다. 또한, Flutter는 매주 유튜브에 이주의 위젯 라는 이름으로 개발 시 사용가능한 위젯에 대한 간략한 소개 영상을 올려주기도 하는데 이런 점도 커뮤니티가 활발해 보여 Flutter를 선택하는데 도움을 주었다.

 

짧은 시간 내에 효과적으로 Flutter와 Dart를 익히기 위해 너무나 좋아하는 교육 플랫폼인 인프런에서 괜찮은 입문 강의를 듣기로 했다. 내가 원하는 강의는 1. 길지 않은 러닝 타임, 2. 입문부터 꼼꼼히 설명, 3. 적당한 응용 앱을 만들 수 있을 정도의 깊이는 가질 것 과 같은 조건이 있었는데 이러한 조건에 딱 들어맞는 강의를 인프런에서 찾을 수 있었다. 해당 강의 정보는 다음과 같다.

Flutter 강의 추천 - Flutter 앱 개발 완성

보면 알 수 있듯 커리큘럼이 정말 깔-끔한데 심지어 한 회차에 러닝 타임이 1시간씩 밖에 되지 않는다. 빠르게 기본을 익혀서 앱을 만들어내야 하는 현재 상황에 정말 딱 맞는 강의가 아닐 수 없었다. 이틀 정도에 걸쳐 강의를 모두 듣고 개발을 시작하게 되었다.

구현 과정

강의에서 제공하는 앱 예제를 따라 만들고 분석해보며 충분히 Flutter 기초에 대한 지식을 익혀두었기 때문에 앱 개발에 특별한 이슈는 없었다. 다만, 개발을 진행하며 몇 가지 고민됐던 부분을 어떻게 해결했는지 간략하게 적어보았다.

장소 검색 & 선택

앱이 제공하는 기능 중 장소를 검색하고, 계획 리스트에 등록하는 기능이 있다. 이 과정에서 카카오와 네이버의 API를 사용하게 되는데, 빠른 개발을 위해 직접 지도를 넣어 지도를 조작하며 장소를 탐색하는 방법은 포기하고 아래와 같이 step을 나누어 사용자에게 최대한 장소 선택에 필요한 정보를 제공하면서도 간단하고 빠르게 개발할 수 있도록 했다.

  1. 키워드를 통한 장소 검색
  2. 장소 선택 시 static map image를 표시해 실제 선택하고자 했던 장소가 맞는지 물어보기

네이버 API는 키워드로 검색한 장소에 대한 상세 정보가 부족하고, 카카오 API는 static map을 반환하는 api를 제공하지 않기에 어쩔 수 없이 우선 두 회사의 api를 섞어서 사용하게 되었다.

 

먼저 키워드를 통해 장소를 검색하는 step에서는 아래 카카오 api를 호출하는 코드를 통해 데이터를 불러와 SearchResult 객체를 생성해 반환하고,

사용자가 장소를 선택하게 되면 아래 네이버 api를 사용하는 함수에 SearchResult 를 전달해 내부의 x, y 좌표를 가지고 static map을 생성해 반환해준다.

결과적으로 앱은 아래와 같이 동작하게 된다.

장소 랜덤 추천

장소를 랜덤으로 추천해주는 기능은 플랭고 앱의 기획단계부터 핵심 기능 중 하나로 고려됐던 기능이다. 아예 계획이 없거나 하루 중 일부만 계획을 정해둔 사용자가 이 기능을 통해서 주변의 장소를 빠르게 추천받아 일정을 계획하는데 들어가는 불필요한 노력을 줄일 수 있다는 점이 우리가 생각했던 이 앱의 핵심 가치 중 하나였다.

 

이러한 요구사항을 받아들고,, 어떻게 구현하면 좋을까 고민하다가,, 크게 아래와 같은 방법들을 생각해냈다.

  1. 지도를 크롤링하는 배치 프로세스를 서버에 올려 특정 지역의 식당, 카페, 문화 시설들을 주기적으로 DB에 저장한다.
  2. 카카오에서 제공하는 카테고리로 장소 검색 API를 활용해 랜덤 검색을 구현한다.
  3. 우선,, 해커톤 데모만을 위해 빠르게 학교 근처 맛집만 수기로 작성해 DB에 밀어넣는다.

일정이 너무 촉박해서 3번으로 진행되기 일보직전이었는데 생각보다 카카오에서 제공하는 API의 카테고리 분류가 세부적이어서(카페, 식당, 문화시설, 관광명소, …) 결과적으론 2번안으로 진행하게 되었다.

 

아래 카카오 API 문서를 보면 카테고리 코드와 중심 좌표, 검색 반경을 지정할 수 있게 되어있다.

(출처 - kakao developers)

아래 코드처럼 사용자에게 검색하고자 하는 카테고리검색을 원하는 중심위치, 검색 반경을 입력받아 api를 호출한다. 그리고 반환 결과 내에서 랜덤으로 하나의 값을 선택해 반환하는 방식으로 랜덤 검색을 구현하였다.

다만, 이러한 방식에는 한 가지 문제가 있다. 다시 카카오 API 문서를 보자.

(출처 - kakao developers)

API 호출 시 한 번에 몇 개의 결과를 가져올 지 정할 수 있는데 기본값은 15이다. 따라서 한 번의 호출에 15개의 장소가 호출된다. 그 이후의 데이터를 조회하고 싶으면 쿼리 파라미터에 2, 3, … 과 같은 page 값을 입력해야 한다. 이러한 과정을 수행하지 않으면 사용하자 범위를 변경하든지 말든지 계속해서 특정 정렬 기준에 따른 15개의 장소 내에서 랜덤 추출을 진행하므로 제대로 된 랜덤 결과를 얻을 수 없다.

 

따라서 결과를 저장해 반환하는 SearchResult 에 결과의 개수 pageable_count 를 같이 저장하여 같은 검색 조건으로 2번 이상 랜덤 추천을 시도하는 경우 총 페이지 개수까지 고려한 진정한 의미의 랜덤 장소 추천을 수행할 수 있도록 했다.

이렇게 완성된 랜덤 추천 페이지는 아래와 같이 동작한다.

앱 내 데이터 저장

이 부분이 개발 과정에서 가장 아픈 손가락 같은 부분인데,, 우선 앞서 이야기했듯 해커톤 이후에 데이터 저장 관련 로직은 모두 백엔드로 이전하기로 마음먹고 개발을 진행하고 있었다. 따라서 flutter에서의 데이터 저장 및 조회 로직은 어차피 모두 api 호출로 변경될 것이라는 생각을 안고 개발을 진행했다. 결과적으로는 코드가 엉망이 되어버렸지만,, 나중에 꼭 백엔드와 통합해서 잘 개선해보고 싶다.

 

우선 플랭고 앱의 데이터는 대략적으로 아래와 같은 구조를 갖는다.

Day가 하루에 하나씩 생성되어 그 날에 생성된 Schedule(계획에 대한 정보를 관리)Diary(기록에 대한 정보를 관리)들을 갖는 방식이다. 위 3개의 도메인 클래스를 생성하고, DayService 라는 일종의 레포지토리 클래스가 데이터의 CRUD를 관리하는 방식으로 동작한다. 예를 들어 지정한 날짜에 Day 를 생성하는 DayService의 메소드는 아래와 같다.

DayService 에서 데이터를 변경하고 notifyListeners() 를 호출하면 아래 코드처럼 Provider 라는 것의 아래에 위치한 child 들은 화면을 그리는 함수인 build() 가 재호출되면서 데이터가 갱신되어 출력되는 방식이다.

현재 데이터는 DB에 영속적으로 저장되지 않고, DayService 클래스 내의 리스트 인스턴스 변수에 저장되어 메모리에만 임시로 저장되도록 해놓았다. 빨리 백엔드를 구현하고 서버에 올려서 앱과 백엔드가 잘 통신되는지 확인해보고 싶다.

이미지 저장

이미지 저장도 만만하게 봤다가 엄청 고생했는데, 우선 UX 측면에서 이미지를 조절할 수 없다거나 크기가 잘리는 등 문제는 차치하더라도 이미지를 앱 내 저장소에 저장하는게 생각보다 너무 까다로웠다. 아마 이 부분도 백엔드가 구현되면 차라리 더 쉽게(?) 해결되지 않을까 생각한다! 결과적으로는 아래와 같이 ImagePicker 로 기기의 이미지를 불러와 File 로 변환하고, 바이트배열로 변환하여 새로운 파일에 쓰도록 구현했다. 그리고 새롭게 저장된 파일의 주소를 Diary 객체에 저장한다.

그리고 읽어올 때는 Diary 객체에서 파일 주소를 읽어와 해당 주소에 저장된 바이트 배열을 다시 File로 변환해 반환한다. UI단에서는 Image.memory(파일주소) 함수를 통해 이미지를 읽어오게 된다.

워낙 고생을 오래 한 부분이라 백엔드로 전환되면 어떻게 구현할 수 있을지 기대되는 부분 중 하나이다.

팀 내 갈등 및 해결 과정

프로젝트를 진행하며 크고 작은 문제들이 있었다. 간단히 회고해보고 어떻게 하면 다음 프로젝트에서는 이러한 문제를 예방할 수 있을지 고민해보았다.

개발 관련

먼저 개발 관련 문제가 있었다. 앱 프론트 개발을 위해 Flutter를 사용하기로 했지만 나와, 같이 개발을 하기로 한 개발자 팀원 모두 Flutter에 대한 경험이 없었기에 각자 공부를 해오고 페이지를 나누어 개발을 하기로 했었다.

 

때문에 깃헙에 레포를 파서 작업을 진행했는데, 이 과정에서 다른 개발자 팀원이 깃헙을 통한 협업 경험이 없어서 master 브랜치에 작업하고 바로 푸시하여 충돌이 나고 코드가 날라가는 등의 문제가 종종 생기곤 했다.

 

이를 해결하기 위해 깃 컨벤션을 정하고 기본적인 협업 방법에 대해 해당 개발 팀원과 함께 찾아보고 공부하는 시간을 먼저 가졌다. 주로 사용되는 커밋 메시지 컨벤션과 관련된 문서 링크를 참고해 우리 상황에 맞는 컨벤션을 만들었고, git-flow 관련 잘 정리된 블로그를 화면 공유를 통해 같이 읽고 토론하며 깃 관련 협업에 대한 대략적인 규칙을 정했다.

 

공모전이 끝나고, 사전에 이러한 것들에 대해 커뮤니케이션을 진행했다면 혼란이 조금 덜 하지 않았을까 하는 생각을 하게 되었다. 다음 프로젝트를 진행하게 된다면 모든 개발을 진행하기 이전에 내부적으로 이러한 내용에 대한 세미나를 진행하고, 사용할 git flow나 커밋 컨벤션 등을 정해두면 좋을 것 같다.

협업 관련

워낙 다들 바빴던지라 마지막까지 시간에 쫓기며 개발과 최종 발표 준비를 해나가고 있었다. 발표를 3일 정도 앞두고 기획을 맡은 팀원들이 발표를 맡은 팀원에게 발표 준비가 어떻게 진행되고 있는지 물었다. 문제 없이 잘 진행되고 있다고 했다.

 

그렇게 발표 당일 새벽, 해당 팀원이 공유해준 발표 자료에는 다른 팀원들이 이해하고 있는 기획 의도와 전혀 다른 내용이 들어가있었다. 해당 팀원은 이제와서 무슨 말이냐며 오히려 따지고 들었다. 우선 발표 당일이었기에 급하게 발표자를 다른 팀원으로 변경하고 새롭게 발표를 맡은 팀원과 나는 새벽 6시까지 자료를 만들고, 쪽잠을 잔 뒤 발표를 하게 되었다.

 

속상하고 힘들었지만 이러한 일들을 겪으면서, 팀원들간의 커뮤니케이션이 얼마나 중요한지 깨달을 수 있었다. 다른 팀원에게 일을 맡겼다고 해서 그냥 나몰라라 할게 아니라 중간 중간 서로 작업의 진척도나 진행 방향을 확인하고 빠르고 잦은 연락을 할 필요가 있겠다고 생각이 들었다. 우리 팀이 이러한 의사소통을 할 수 있는 편안한 상황이었는지에 대해서도 생각해보는 계기가 되었다. 노션, 트렐로 등 툴을 사용해 서로 맡은 일의 분야가 다르더라도 서로 작업 진척도를 공유하고 계속해서 확인할 수 있는 환경을 만들면 좋았겠다 하는 아쉬움이 남았다.

향후 개선 방안

우선 가장 우선적으로 현재는 앱 내에서 처리하고 있는 데이터의 CRUD를 백엔드로 이전할 계획이다. 그러기 위해선 로그인 기능도 필요할 것이고, 이 과정에서 그동안 배웠던 백엔드 기술들을 실습해볼 수 있을 것으로 생각한다.

 

그 다음으로는 급하게 개발하느라 앱 프론트에 중복코드나 자잘한 버그가 아직 많이 남아있어서 이 부분을 정리하고 가야할 것 같다. 앱스토어에 실제 출시를 목표로 개발을 진행하고 있기 때문에 UX 측면에서도 개선할 점들이 많이 보이는데 그런 부분들도 점차 개선해나가고자 한다.

 

해커톤은 종료되었지만 뜻이 맞는 팀원들끼리 주기적으로 회의를 진행하며 앱 출시를 위해 서비스를 개선하는 작업을 진행하고 있으며 개선이 필요한 사항들이 보일 때 마다 노션 페이지에 정리해두고 있다. 이 과정에서 이뤄지는 의미있는 내용들은 블로그에도 공유하려고 한다.

후기

여러 가지로 느낀 점이 많았다. 전공 과제 의외에 프로젝트를 따로 진행해본 것이 거의 처음이라 서툴기도 했고 조금은 무모하기도 했던 것 같은데 앞으로 마주하게 될 수많은 프로젝트를 진행함에 있어 성공적으로 마무리하기 위해선 어떤 부분을 더 신경써야 할지 알아둘 수 있어서 값진 경험이었다고 생각한다.

 

그리고 그 무엇보다 이번 프로젝트가 의미있었던 것은 오랜만에 개발 공부와 개발하는 과정이 정말 즐거웠다는 점이다. 왜 그럴까 생각해봤는데, 목표가 있는 공부와 개발을 할 수 있어서 그런게 아닌가 싶었다. 그동안은 취업을 우해서, 언젠가 필요할테니깐,, 과 같은 마음으로 공부를 하고 코드를 짰다면 이번에는 당장 눈 앞에 보이는 결과물을 완성시키기 위해서 필요한 기술을 공부하고 코드를 작성하다보니 공부할 의욕도 넘치고, 밤을 세워 코딩을 해도 지치지 않고 재미를 느낄 수 있었다.

 

최근에 읽은 일본의 유명한 MS 개발자가 쓴 책 ‘오늘, 또 일을 미루고 말았다’에 다음과 같은 문장이 나온다.

공부에 대해서 나는 나만의 신념을 가지고 있다. ‘목적 없는 공부’는 하지 않는다는 것이다. (중략) 배워두면 어딘가에 도움이 될 것 같았다. 하지만 그래서는 공부를 지속하기 힘들다는 사실을 깨달았다. 그래서 무언가 계기가 생기기를 기다렸다. (중략) 그에 대한 대답은 ‘일단 시작부터 한 후 그 과정을 기억한다’라고 답할 수 있겠다. (중략) 공부는 어디까지나 수단이다. 그 수단을 활용해 이루고 싶은 목적이 있을 경우에만 유용하다. (오늘, 또 일을 미루고 말았다 189-192)

프로젝트가 끝난 지 얼마 되지 않아 이 책을 읽었기에 저 말이 현재의 나에게 정말 딱 들어맞는 말이라고 생각했다. 어쩌면 이게 나에게 맞는 학습 방법인게 아닐까 하는 생각이 들었다. Flutter라는 처음 접하는 기술을 빠르게 공부해서 1주만에 앱을 개발해낼 수 있었던 것도 이루고 싶은 목표가 있었기 때문이라고 생각한다.

 

이 프로젝트를 계속해서 발전시켜 나가며 백엔드 기술을 꼭 도입하고, 출시까지 이뤄내보고 싶은 이유도 이와 같다. 이 앱을 계속해서 발전시켜 나가는 과정에서 기존에 배운 백엔드 기술을 적용하고 새롭게 적용하고 싶은 기능이 있을 때 새롭게 필요한 기술을 배워 적용하는 과정에서 빠르게, 많이 성장할 수 있을 것 같다는 생각이 들었다.