갈피: 나의 첫 모바일 앱 개발기
인생 첫 앱을 만들었습니다. 독후감 앱입니다.
tl; dr
인생 첫 앱을 만들었습니다. 독후감 앱입니다. Flutter를 사용했고 오픈소스입니다. 앱스토어에 올라가 있습니다. 플레이 스토어에는 아직 없어요. 금방 올리겠습니다. (2019-08-22 수정: 플레이 스토어에도 올라갔습니다 😊)
들어가며
어쩌다보니 웹 프론트엔드 엔지니어가 되었다. 클라이언트 작업을 좋아해서, 하는 일에 불만은 없다. 하지만 적어도 2019년 중순 현재까지는 모바일 기기에서 웹 제품만으로는 제공하기 어려운 경험들이 분명히 있다. 때문에 네이티브 앱이 필요할 때 만들 능력을 갖추고 싶다는 생각은 예전부터 해왔다.
만약 앱을 만든다면 크로스 플랫폼 솔루션을 쓰고 싶었다. 뿌리(?)가 웹이라 더 그런지 몰라도, 한 앱을 두 플랫폼에 제공하기 위해 전혀 다른 두 개의 코드베이스를 관리하는 것은 가급적 피하고 싶었다. 한 기업의 마켓플레이스에 사실상 종속되는 기술을 배우기가 그닥 내키지 않기도 했다.
기술을 배우는 가장 좋은 방법 중 하나는 그 기술로 무언가를 만들만한 뭔가를 떠올리고, 그걸 실제로 만들어보는 것이다. 크로스 플랫폼 모바일 앱 개발을 배우기 위해 크로스 플랫폼 모바일 앱을 만들어보기로 결심했다.
독후감 앱을 만든 이유
독후감 앱을 만든 이유는 두 가지다.
첫째로, 내가 필요로 하는 앱이기 때문이다. 개인 프로젝트를 시작할 때는 적어도 한 명의 잔존 유저(i.e. 나)을 확보하는 것이 중요하다고 생각한다. 내가 사용하는 동안은 제품을 꾸준히 개선해나갈 동인이 생기는데, 이건 큰 장점이다. (돌이켜보면, 내 첫 웹사이트도 직접 사용할 블로그였다)
둘째로, 독후감 앱의 스펙이 일반적인 앱 개발에서 요구되는 대부분의 요소 - 여러 UI 패턴, 로컬 데이터베이스, 인증, 써드파티 API 호출 등 - 를 모두 포함하기 때문이다. 쓸모있는 앱을 만드는 과정에서 필요에 의해 이런 요소를 자연스레 학습할 수 있을 것이라 생각했다.
갈피 galpi
처음엔 이름 짓기보다 제품 만들기가 더 중요하다는 생각으로 “booklog” 라는 임시 이름으로 시작했다. 개발이 어느정도 진행되고 앱 스토어에 올릴 때가 되자 작명을 더 미룰 수 없어졌다. 그 때부터 딱 맞는 이름을 찾기 위한 고민을 시작했다. 조건은 세 가지였다:
- 한글과 영문 두 표기가 모두 조형적으로 마음에 들 것.
- 발음하는 느낌이 좋을 것.
- 독후감이라는 기능의 본질과 잘 닿아있을 것.
머리를 쥐어짜던 중 책갈피라는 단어가 스쳐 지나갔다. 앱에 갈피라는 이름을 붙이면 어떨까 하는 생각이 불현듯 떠올랐다. 표준국어대사전에 따르면 갈피라는 단어는 “겹치거나 포갠 물건의 하나하나의 사이. 또는 그 틈.“ 을 뜻한다고 한다.
몇 번 소리내어 발음도 해 보고 적어놓고 보니 보면 볼수록 너무 마음에 들었다. 더 고민하지 않고 바로 이름을 바꾸었다. 결국 갈피라는 이름으로 앱이 나왔다.
Flutter로 만든 이유
무슨 앱을 만들지 다음으로 내려야 할 결정은 어떤 기술을 사용할지였다. 앞에서 밝혔듯 크로스 플랫폼 솔루션을 원했는데, 사용자가 충분히 많으면서도 배워두면 앞으로 쓸만한 법한 기술을 찾으려니 생각보다 선택지가 다양하진 않았다.
React를 매우 즐겁게 사용하고 있는 만큼 (참고: React를 Vue.js보다 선호하는 이유) 가장 처음으로 떠올린 후보는 React Native였다. 하지만 - 아무것도 안 바꿨는데 캐시 문제로 빌드가 깨지고, 빌드 캐시를 날릴 방법이 공식 문서 어디에도 없는 등 - 문서화와 툴링 관련 아쉬움을 느낄 일이 자꾸 생겼다.
그런 상황이 반복되자 지금 이 도구에 시간과 노력을 투자할 가치가 있는지 회의가 들었다. 결국 진입장벽을 넘지 못하고 포기했다. 관련해서 부담 없이 도움을 구할 사람이 주변에 있었으면 좀 나앗을 것 같은데, 아쉽게도 그런 상황은 아니었다. 몇 달 전 마지막으로 시도했을 때의 기억인지라, 지금은 또 어떨지는 모르겠다.
그러던 중 회사 동료 분의 추천으로 구글의 크로스 플랫폼 UI 툴킷인 Flutter 를 다시 들여다보게 되었다. Flutter는 이전에 이름 정도는 들어봤지만 (지금은 기억이 나지 않는 이유로) 그다지 눈여겨보진 않고 넘긴 기술이었다.
막상 다시 살펴보니 공식 문서가 매우 잘 쓰여있고 이미 대부분의 용례에서는 충분히 검증된 기술로 보였다. 또한 픽셀 단위로 동일한 UI를 보장한다는 내용을 포함해, 크로스 플랫폼 프레임워크가 갖춰야 할 미덕(?)을 잘 이해하고 있다는 인상을 받았다. 커뮤니티도 커지고 있고, 회사 차원의 투자도 활발히 이루어지고 있는 것으로 보여 시도해볼만한 가치가 있다고 판단했다.
결과적으로, 인생 첫 앱을 Flutter로 만들어 배포까지 마쳤다.
Flutter를 써 본 감상
플러터는 아름답고, 하나의 코드베이스에서 모바일, 웹, 데스크톱을 위한 네이티브 어플리케이션을 만들기 위한 구글의 UI 툴킷입니다. Flutter is Google’s UI toolkit for building beautiful, natively compiled applications for mobile , web , and desktop from a single codebase. (source)
Flutter를 쓰면서 기록할만하다고 느낀 포인트 몇 가지.
Beginner friendly
문서와 도구가 상당히 잘 준비되어 있다. 나는 Dart 언어를 사용해본 적도 없고 네이티브 앱 개발 경험 또한 전무한데도 불구하고 앱을 릴리즈하기까지 크게 막히는 부분이 없었다. 빠른 발전 속도 때문인지 조금씩 업데이트가 필요한 부분이 문서 여기저기 보이긴 했으나, 치명적인 오류는 없었다. 공식 유튜브 채널과 Medium의 Flutter Community부터도 도움을 많이 받았다.
Everything is a widget!
Flutter에서는 (HTML에서는 CSS 속성으로 처리될 정렬, 마진/패딩 등의 스타일링을 포함한) 모든 것이 위젯으로 표현된다. 필연적으로 조금만 방심하면 위젯 트리가 매우 깊어지는데… 이런 접근이 가져다주는 장점이 무엇인지는 아직 잘 모르겠다. 그렇다고 엄청 불편한 것도 아니고, 좀 어색하다는 느낌.
개인적으로 현 시점에서는 React가 더 나은 컴포넌트 API를 갖고 있다고 생각한다. 아주 훌륭한 선구자를 굳이 따라가지 않은 디자인들에 대해서는 조금 의문이다. (다른게 문제는 아닌데, 다르게 함으로서 무엇을 얻었는지 잘 모르겠다) 혁신이라 생각하는 React Hooks에 대응하는 개념이 아직 없는 점도 슬펐다. (참고: 「Hello, React Hooks!」 발표자료 공개)
Material Design 컴포넌트
Flutter는 다양한 위젯을 제공하는데, 그 중에는 Material Design 컴포넌트(이하 MDC)들도 포함된다. 컴포넌트를 만들고 적절한 때에 적절한 UI를 그리기 위한 API만을 제공하는 React와는 사뭇 다른 접근인데, 처음에는 내가 프레임워크에 기대하는 영역을 벗어나는 느낌이라 좀 거부감이 들기도 했다.
막상 개발해보니 MDC의 존재가 그렇게 고마울 수 없었다. 특히 회사에서와는 다르게 디자이너가 없어서 많이 힘들었는데, MDC는 구세주였다. 유튜브를 비롯해, 이미 같은 요소를 사용해 만들어진 여러 앱을 참고하며 정말 많은 도움을 받았다. 익숙하지 않은 환경에서 만약 MDC까지 없었다면 훨씬 많은 시간을 쓰고도 더 완성도가 낮은 앱이 나왔을 것이다.
ConstraintLayout
ConstraintLayout 하에서의 오버플로우 등 UI 버그의 디버깅 때문에 고생을 많이 했다. 아직 익숙하지 않아서 그런지, 혹은 오류 메시지가 친절하지 않아서 그런지, 아무튼 고통스러웠다. CSS가 그리웠다.
Dart
Dart는 확실히 가장 좋은 언어는 아니다. 아직 Non-null 타입이 지원되지 않음을 깨달았을 때는 꽤 충격을 받기도 했다. (논의가 열심히 이루어지고 있긴 하다.) 하지만 못 쓸 정도 수준은 전혀 아니다. Flutter가 제공하는 장점 중 상당 부분이 Dart 엔진에 의존하고 있다고 들었는데, 만약 그렇다면 Dart를 써야 한다는 것이 그다지 비싼 비용도 아닌 것 같다.
툴링도 현재로서는 언어와 비슷하게 못 쓸 정도는 아니지만 살짝 부족한 부분들이 있다는 느낌이었다. 예를 들어 VS Code 공식 확장에서 트레일링 콤마를 찍냐 아니냐에 따라 포매팅이 달라지는데 항상 콤마를 찍도록 포매팅할지 여부를 설정할 방법이 없는 등… 미세하게 불편한 부분이 있다.
충분히 많은 사용자가 있는 언어의 단점은 빠르게 개선하면 되는, 그리고 그렇게 해결되기 마련인 문제라고 생각한다. Flutter 커뮤니티가 지금보다 더 크게 성장하고 Fuschia 등의 다른 프로젝트가 성공한다면 지금 Dart 언어에 느끼는 아쉬움은 금세 사라질 것 같다.
배운 점
나의 커리어에 관하여
이 트윗, 그리고 이어지는 트윗 에서 썼듯이 앱을 만들면서 내가 - 비록 커리어의 시작부터 지금까지 웹 프론트엔드 개발자로 일해왔지만 - 꼭 평생 웹 프론트엔드 개발자로만 살아갈 필요가 없다는 것을 깨달았다. 스스로 나의 가능성을 제한할 필요 없다!
나에게는 정말 중요한 깨달음이었는데, 회사 일에만 파묻혀 살다보면 떠올리기 어려운 지점인 것 같다. 퇴근 후와 주말에 한두시간씩이라도 꾸준히 시간을 내서 개인 프로젝트를 진행하길 정말 잘 했다는 생각이 들었다. 앱을 만들면서 얻은 가장 큰 (심지어 앱 개발 기술 그 자체보다도 귀한) 수확이었다.
플랫폼에 종속되지 않는 지식에 관하여
굉장히 겁을 먹고 시작했던 것에 비해 앱을 내기까지의 과정이 생각보다 순탄했다. 이유를 생각해보면 처음 경험해보는 다른 플랫폼, 다른 언어에서의 개발이지만 기본적인 원칙 - 선언적인 UI 프로그래밍, 컴포넌트 기반의 구조화, 비동기 처리 등 - 은 비슷하게 적용되는 부분이 많아서 그런 것 같다.
나의 분야에서 쌓아온 지식과 노하우가 다른 플랫폼, 다른 언어에서의 개발에 적용되는 경험이 즐거웠다. 주로 웹 프론트엔드만 해왔지만 한 분야에 국한되는 지식만 쌓은 건 아니라는 생각이 들어 뿌듯하기도 했다.
앱을 개발하고 배포하는 일에 관하여
생각보다 어렵지 않다. 재밌다!
앞으로 해야 할 작업
개발을 놓지 않고 계속 해나가기 위해선 최대한 빨리 앱 배포 프로세스를 한 번 밟아보는게 중요하다고 생각했다. 그래서 의도적으로 코드 퀄리티나 기능을 희생해가면서 MVP 구현에 집중했다. (그런 것 치고 엄청 빠르진 않았지만… 회사 다니면서 한 것 치고 나쁘지 않았다고 합리화를 해본다 🙄)
목표를 달성했으니 이제 미뤄둔 일들을 건드릴 수 있게 되었다.
안드로이드 스토어 등록
아이폰 및 맥북 사용자라 개발은 iOS 시뮬레이터에서 진행했고, 어쩌다보니 크로스 플랫폼 운운한 것이 무색하게도 아직 앱 스토어에만 앱을 배포해뒀다. 안드로이드 스토어에도 앱을 올려야 한다. 배포만 하면 되는데… 왜 항상 배포는 이리 귀찮은지…
배포 및 테스트 자동화
위 작업이 끝나면 fastlane 등의 서비스로 배포, 테스트, 스토어에 올릴 스크린샷을 찍는 등의 작업을 자동화할 예정이다. 그사이 조금 익숙해졌다지만, 네이티브 앱 배포는 웹 어플리케이션 배포에 비해 훨씬 품이 많이 든다. 지치지 않고 개발의 템포를 유지하려면 시급하게 해결해야 할 문제.
백엔드 작업 및 데이터 이관
백로그에 있는 기능 중 가장 우선순위가 높은 작업이다. 지금은 데이터를 로컬 데이터베이스에만 저장하고 있어서, 앱 삭제시 데이터가 날아간다. 사용자의 입장에서 생각해보면 요즘 시대에 말이 안 되는 동작이라 생각한다.
때문에 가입/로그인 및 데이터를 서버로 옮기는 작업까지 MVP에 포함시켜야하나 고민을 많이 했다. 하지만 Firebase 등을 사용하지 않고 직접 백엔드를 구현한다면 (그럴 생각이다) 작지 않은 스펙이라 일단 이렇게 나 자신과 타협을 보았다.
데이터를 서버로 옮기는 작업이 끝나도, 오프라인 환경에서 앱을 사용 가능하게 만들려면 로컬 데이터베이스 사용은 필요할 것 같다. 빠른 배포를 위해 잠깐 시간이 지나면 필요없어질 작업을 한 것은 아니었다는 점이 불행 중 다행(?).
클라이언트 코드베이스 개선
어떤 기능을 구현할 때마다 정말 그러기 위해 필요한 최소한의 언어/프레임워크 지식만 익히고 바로 써먹는 식으로 앱을 만들다보니 클라이언트 코드베이스가 좀 엉망이다. Stream을 써야할 곳에 Future를 state와 엮어서 pseudo-Stream (?) 을 만들어 쓰는 등 알면서도 안/못 고친 민망한 코드가 많다.
첫 출시를 마쳤으니 잠시 숨을 고르면서 이런 민망한 코드들도 좀 정리하고, 서버로 데이터 이관이 끝나면 provider 같은 상태 관리 라이브러리도 도입해면서 코드베이스 퀄리티를 끌어올릴 생이다.
맺으며
굉장히 즐거웠던, 난생 첫 앱을 만드는 경험을 간략히 기록으로 남겨 보았습니다. 갈피의 소스 코드는 GitHub 리포지토리에 공개되어 있습니다. 제가 쓰고 싶어 만들었지만 남들도 쓰고 싶은 앱이 될 수 있게 앞으로도 열심히 만들어 보겠습니다. 읽어주셔서 감사합니다.