“당신은 메모를 잘 하는 사람입니까?”
“아주 가끔은….?”

그리 머지않은 과거, 우리 손에 작은 수첩과 펜이 들려있던 시절이 있었다. 하지만 지금은 스마트폰이 그 자리를 차지했고 수첩을 사용하는 사람은 쉽게 찾아 볼 수 없는데, 스마트폰의 세련된 모습뿐만 아니라 오랜 기간 수첩이 수행했던 단순한 기능과 비교할 수 없이 다양하고 똑똑한 기능으로 사람들의 마음을 순식간에 빼앗아갔기 때문일테다.
그런데 오히려 굉장한 기능과 복잡함 때문에 가끔은 정작 필요한 기능을 제대로 사용하지 못할 때가 종종 있는데 내게는 유난히 Todo 앱이 그러했다. 옛날처럼 흰 종이 한 장과 펜만 있으면 되는데 달력/서버와의 연동, 기간 설정, 카테고리 입력, 태그 달기, 수많은 입력 사항 등등 내가 사용하지 않을 멋진 기능들이 오히려 나를 메모에서 멀어지게 했다. 덕분에 스마트폰을 손에 쥔지 5년이 지났지만 그 어떤 Todo/Memo 앱에도 정착하지 못하고 포스트잇과 기본 메모 앱 사이를 왔다 갔다 할 수밖에 없었다.

그러던 어느 날, John을 만나 심플한 메모 앱, Blink 기획 이야기를 들었다. 획기적이었다! 지금까지의 Todo/Memo 앱은 한 줄에 하나의 아이템이 들어가는 즉, 리스트 형식이었는데 Blink는 수첩에 간단하게 메모하던 방식대로 한줄에 여러 아이템을 착착 적어나가는 방식이었다. 한 장의 흰 종이 그리고 펜. 그 이상도 이하도 아닌 정말 메모를 위한 메모 앱이었다.

정말 사용하기 편한 앱이겠어! 내가 원하던 앱이군!! 이제 남은 문제는 단 하나. 프알못인 내가 어떻게 이걸 구현하지?? 😳

진짜 개발 이야기

0. 개발 환경

  • Platform : iOS
  • IDE : Xcode
  • Language : Swift
  • DataBase : Realm
  • Crash Report : Fabric
  • Version Control : Github
  • without Storyboard(왜 그랬는지 그 당시 나는 스토리보드를 멀리했다. 그렇다고 Autolayout을 사용하지 않은 건 아니다.)

1. 엔진 개발

핵심기능

  • 가로 방향 아이템 배열
  • 단일 아이템 다중 분산

Class

  • UICollectionViewController
  • UICollectionViewControllerFlowLayout


아직도 생생한 1년 전 봄, Blink iOS 개발이 시작됐다.
Blink는 메인화면과 셋팅화면 2가지 화면으로 구성된 단순한 구조의 앱으로 디자인도 플레인하며, 소요되는 색상이나 이미지도 많이 없는 편이라 혼자서 구현하기에 그리 어렵진 않을거라 생각했다.


작은 문제가 있다면 메인화면 레이아웃 구성. 우리는 이 레이아웃을 Blink의 ‘엔진’이라 불렀는데 역시 엔진은 엔진. 생각보다 만드는데 꽤 오랜 시간이 걸렸고, 해결해야 할 문제는 크게 3가지였다.


(문제1) 세로로 아이템을 나열하던 방식을 가로 방향으로 변경하기

한 줄에 여러 개의 아이템을 넣고, 각 아이템을 독립적으로 관리(터치)할 수 있어야 했다.

가장 먼저 생각난 방법은 UILabel 쌓기
UILabel를 박스라고 생각하고 각 UILabel 하나에 아이템 하나를 담은 후 공간을 박스로 채워가는 방법. 그리고 각 UILabel에 TapGesture를 붙여서 아이템이 탭 될 때마다 어느 아이템이 선택된건지 체크하면 되겠지? 라고 생각했다. 그런데 이렇게 하려니 새로운 메모가 추가 될때마다 각기 다른 너비의 UILabel을 모두 계산한 뒤 그에 맞게 모든 UILabel의 frame을 매번 업데이트하고, 수백 개의 UILabel의 제스처를 관리하려니 생각만 해도 로드가 너무 컸다. UILabel을 UIButton으로 변경해도 상황은 마찬가지(지금 생각해도 🍵). 고민에 고민을 거쳐 생각해낸 방법은

(해답1) UICollectionViewController

그 쯔음 Custom Photo Album을 구현하느라 한참 빠져있었던 클래스였다. 그래, 내가 모든 Label의 프레임을 일일이 계산해서 뿌려주는 건 너무 힘들지만 친절한 UICollectionViewController의 힘을 빌리면 아이템 추가도, 정렬도, 관리도 훨씬 손쉽게 할 수 있을거야.
그렇게 나는 컬렉션 뷰와 친해졌다.


(문제2) 아이템이 길면 넘치는 부분을 다음 줄로 넘겨주기

화면의 가로길이를 넘는 아이템을 어떻게 잘 잘라서 다음 줄로 넘겨줄 것인가?
여기서부터 길고 긴 고민과 고난의 시간이 시작되었다.
길고



여정
사용자가 입력하는 아이템의 길이가 짧으면 오케이지만, 화면 가로길이보다 긴 아이템을 입력하거나, 아이템을 착착 쌓아가다가 화면 오른쪽 엣지를 넘어가면 그땐 어떻게 하지??
예를 들면 아래와 같은 상황이다.


새로운 아이템인 ‘가을이 간식’을 입력하면 오른쪽 끝에 있던 단어 ‘프란츠 카프카 책 사기’는 ‘프란츠 카프, 카 책 사기’로 쪼개지면서 자연스럽게 다음 줄로 넘어가야 했다.

사용자가 아이템을 추가, 수정 그리고 삭제 할 때마다 화면 레이아웃이 유격 없이 위와 같이 업데이트돼야 했다. 이를 위해 하나의 아이템을 화면 길이에 맞게 둘(혹은 셋, 넷..)로 쪼개주는 기능이 iOS에 있을까 해서 혹시나 하고 찾아봤지만 역시나 없었다. 유사한 레이아웃을 가진 앱도 보이지않고, Stack Overflow를 찾아봐도 비슷한 경우도 없었다😥. 처음에는 사용자가 입력하는 아이템 자체를 화면 길이와 비교해 자르고 붙이려 했지만 이 방법은 DB를 대책 없는 혼란에 빠지게 했다. 아이템 하나가 추가되거나 변경될 때마다 DB의 모든 데이터를 쪼개고 붙이고 삭제하고 할 수는 없는 노릇이었다. 정말 상상만 해도 끔찍한 처리방식이다. 하지만 프알못인 나는 일단 시도해봤다. 결과는 아래와 같았다.


시도 1.

화면에 난감한 장면이 펼쳐졌다. 분명 내가 입력한 아이템은 4개였는데 DB에 같은 게 복사되고 또 복사 되고 또 복사되고…뫼비우스의 띠? 헤헷 =ㅅ=

이런 방법으로는 결코 안정적인 메모앱을 만들 수도 없었고, 데이터 관리도 엉망이 될 게 분명했다. 다른 방법을 찾아야했다. (아무리 생각해도 사용자가 입력한 데이터 원본은 절대 건드리면 안 되는 거였다. 왜 당연한 걸 몰랐을까?)

(해답2) 사용자가 입력하는 데이터 원본은 그대로 유지하되, 화면에 뿌려주는 아이템은 따로 관리

DB에 입력되는 사용자의 데이터는 건드리지 않고, 메모리에서만 존재하는 새로운 데이터 체계를 만들었고, 화면 길이와 아이템의 가로 길이를 비교해 자르거나 붙이는 작업을 계속해줬다.

그 결과 아래와 같은 화면으로 한 발짝 더 나아갈 수 있었다.


시도 2.

입력한 DB가 잘 유지되고 있음을 확인하고 디자인을 입혔다.

아직 레이아웃은 엉망이지만…

아이템 간의 간격을 일정하게 맞추고, 적절한 지점에서 아이템을 잘라주는 게 쉽지 않았다.


(문제3) 아이템의 너비를 어떻게 정확하게 계산할 것인가

계획했던 레이아웃에 가까이 오긴 했지만, 아이템이 깔끔하게 정렬되지지 않는 게 문제였다. 게다가 위 이미지에는 띄어쓰기가 없는데 아이템에 띄어쓰기라도 들어가면 대혼란이 빚어졌다.
헤헷 =ㅅ= 초반에 아이템의 가로 길이를 측정하던 방식은 아이템의 글자 개수를 카운트한 뒤, 글자 하나가 지니는 대략적인 사이즈를 곱해주는 것이었다.

예) 아보카도 = 4(글자 개수) * 15(한 글자당 너비) = 60 point

당연히 위 방식으로는 정확한 너비를 구할 수 없었다. 특수문자나 띄어쓰기가 들어가면 대혼란이 오는 것도 당연했다. 그리고 한글 기준의 너비였으니 영어, 중국어, 일본어, 러시아어, 아랍어, 프랑스어 등등으로 입력하면 레이아웃이 한층 더 심각하게 깨어지는 건 굳이 테스트해보지 않아도 명백했다. 아이템의 정확한 가로길이를 계산해야만 했다.

(해답3) 아이템의 글자를 분리해 다음 각각의 정확한 너비 측정 후 합산

아이템이 추가/변경될 때마다 모든 아이템을 계산해야 했기 때문에 중복되는 과정 없이 연산을 단순하게 만드는 게 중요했다. 새로운 방식을 적용한 결과는 아래와 같았다.


시도 3.

띄어쓰기도, 특수문자도, 영어도 꽤 잘 계산해서 잘라준다!

헤헷 =ㅅ= 하지만 여전히 아이템 사이의 간격을 일정하게 만드는 문제가 남아있었다.

여기서부터는 UICollectionViewControllerFlowLayout 프로토콜의 여러가지 메서드를 조정하면서 맞춰갔다. 당시 나는 iOS의 UICollectionViewController가 얼마나 훌륭한 클래스인지 제대로 느낄 수 있었고 결국 지금과 같은 화면을 구현해낼 수 있었다.


결과

역시, 집에 갈 땐 메로나 :)


2. 업데이트

Blink는 2017년 5월 17일 버전 1.0.0을 출시한 뒤 지금(2018년 4월 5일)까지 40번 가량의 업데이트를 거쳐 버전 1.4.4가 되었다.

그러는 동안 아래와 같은 다양한 기능이 추가되었다.

  • 스마트 제스처 : 위아래 드래그(UIPanGesture)를 이용한 아이템 아카이브/상단으로 보내기 기능



  • 음성 입력 : 타자 입력이 힘들 때 사용하기 좋은 음성 입력 기능



  • 반복 알림(한시간/하루) : 깜빡(Blink)하지 않게 중요한 건 반복 알림으로 알려주는 기능



  • 다섯 페이지 : 한 페이지가 부족할때, 아이템 분류가 필요할 때 다섯 페이지(In-App Purchase)



  • 백업/복원 : 아이템을 백업해뒀다가 필요할때 복원할 수 있는 기능
  • URL 정리 : 긴 URL을 간단한 키워드로 정리해주는 기능
  • 단어 잘림방지 : 오른쪽 엣지에서 잘리는 단어를 음절 단위가 아니라 띄어쓰기를 기준으로 잘라주는 기능

간단하게 입력하고 손쉽게 완료할 수 있는 기본 컨셉을 해치지 않기 위해 정말 필요하다고 생각되지 않으면 새로운 기능을 추가하지 않았고, 추가할 기능은 며칠씩 테스트하며 기존 방식에 잘 부합되는지 확인에 확인을 거쳤다. 그렇게 업데이트를 해온 지 어언 1년, 생산성 카테고리에서 자리를 잡아가는 Blink를 보면 괜히 뿌듯하다. 아이폰의 기본 기능과 디자인에 충실하면서 기본 기능에 충실한 메모 앱 Blink, 앞으로 더 많은 사용자들이 사용하면서 피드백을 들려주면 좋겠다.


3. 버그 이야기

작년 가을, 심각한 버그가 발생했다. 앱을 실행하면 흰 화면만 뜨고 메인화면이 뜨지 않는 매우 심각한 버그였다. 여기저기 수소문했지만, 주변에서는 그 현상이 일어나는 기기를 찾을 수 없어 디버깅 할 수 없었고, 해결하는데 꽤 오랜 시간이 걸렸다. 잘 사용하던 사람들이 흰 화면을 호소하는 리뷰가 올라올 때마다 점점 말라갔다. 버그를 만들어내고 해결하지 못하는 개발자라니🤯 혹시나 하는 마음에 몇 번씩 수정 업데이트를 했지만 해결되지 않다가 AppDelegate의 Notification 관련 메서드를 수정하고 나서야 겨우 해결할 수 있었다. iOS10 일때는 문제가 없었는데 iOS11로 시스템이 업데이트 되면서 해당 메서드가 몇몇 디바이스에서 오류를 일으키는 것 같았다.
그때를 생각하면 아직도 마음 한 구석이 위축된다ㅜ 전 세계에서 여러 사람이 사용하는 서비스에 당장 해결 할 수 없는 버그의 발생은 개발자인 나에게 자괴감과 함께 여러 가르침을 주고 떠났다. 테스트용으로 만드는 앱은 혼자 감당하면 되니까 괜찮지만 수많은 사람들이 사용하는 앱을 배포할 때는 한줄 한줄 고민해야 한다. 내 폰에서만 잘된다고 문제가 없다고 생각하면 안된다는 사실! 실제로 버그가 발생하면 밤새 머리를 쥐어짜며 살펴봐도 수만 줄의 코드 중에서 어느 녀석이 문제인지 알아내기란 쉽지 않다. 그러니 코드를 처음 작성할때 눈앞의 휴식을 생각하기 보단 정말 필요한 코드인지, 다른 기능과 충돌되지는 않는지 고민 해야한다…그래야하는데 말이다😔.
그리고 버그가 없는 앱을 만드는 게 역시 제일 좋지만, 버그를 끝까지 해결하려는 자세 역시 매우 중요하다는 것을 깨달았다. 버그가 발생할 때마다(꽤 자주) 재촉하지 않고 늘 그 자리에서 함께 고민하고 기다려준 John, 고맙습니다 :)


John의 블링크 메모 앱 디자인 과정 읽으러 가기