글 | 허 원 진 아키텍트
지난 호에 이어, iOS의 애플리케이션 프레임워크와 언어를 전혀 모르는 상태에서 24시간 안에 IoT 앱을 만드는 과정 중 나머지 8~16시간을 다룬다. 이전 글 이후 8시간의 내용이다. 소프트웨어 개발은 코딩이 아니라는 생각의 작은 증명과 혹독한 환경에서 무엇인가 느끼는 것이 목적이다. 개발 전 과정의 자료는 공개된 자료만을 사용해서 필자의 접근방법을 검증 또는 따라할 수 있게 했다.
8시간 - 앱에 아이덴티티를 넣자
단지 빠르게 24시간 안에 앱을 만드는 것은 무의미하다. 앱으로써 상품가치가 있는 완성도 있는 앱을 만들어야한다. 기능적 안정성과 차별화된 상품의 아이덴티티를 넣어야한다. 앱에서 아이덴티티는 앱 아이콘, 런처 스크린, 앱 화면 디자인으로 시각화된다.
Xcode를 이용해서 프로젝트를 생성하면 기본적으로 만들어지는 파일 중에 Images.xcassets 파일이 있다. 이곳에 아이콘이나 이미지가 저장된다(단순히 이미지들이 링크가 걸리는지, 실제로 이 파일에 머징이 되는지는 모르겠다). 이곳에 매우 효과적으로 이미지를 관리하고 사용할 수 있다. 보통의 플랫폼은 앱에 필요한 이미지를 이름 규칙으로 명시하거나 프로퍼티 파일을 코드 기반으로 관리하는 어려움이 있다.
하지만 Xcode는 작업자가 명료하게 이미지를 보고 관리할 수 있는 환경을 제공한다. 아마도 6 버전 이전에는 Xcode도 좀 불편한 환경을 제공했고, 점점 개선되었을 것이다. 맞는 크기의 이미지를 파인더에서 드래그 앤드 드롭(Drag-and-drop) 하면 된다. 그림 1의 이미지처럼 모든 크기의 이미지를 안 넣어도 실행은 된다.
하나의 이미지를 인풋으로 여러 이미지를 생성해주는 툴도 있고, 웹 애플리케이션도 있다. 하지만 이렇게 자동으로 리사이징된 아이콘은 디테일이 떨어진다. 가능한 각 크기별로 꼼꼼히 그리는 것을 추천한다. 해당 리소스에 문제가 있을 경우 코드 에러/경고와 마찬가지로 Xcode에서 알려준다. 전 iOS 프로젝트뿐만 아니라, 모든 프로젝트에서 이미지의 표준 포맷은 PNG를 쓰고 있다. 라이선스와 신뢰가 선택의 이유이다.
다음은 런치스크린, 인트로 화면이라고 불리는, 실행하자마자 잠깐 보여주는 화면이다(그림 2). iOS에서 이미지 리소스는 플랫폼별로 개별적으로 정의된다. 이전에 보았던 실행 아이콘뿐만 아니라, 런치 스크린도 에디터 중간의 wAny hAny를 눌러서 기기별로 위치와 이미지를 잡아야 한다. 여기까지 하면 개발할 때 수없이 누르는 런치 아이콘과 인트로가 예뻐져서 기분을 좋게 할 수 있다. 일정상 나중에 할 수도 있지만, 필자는 최대한 프로젝트 중반부 이전에 하는 것이 좋다고 생각한다. 개발 참여자들의 기분도 매우 중요하기 때문이다.
그림 3에서 페이스북 오른쪽에 있는 아이콘이 브랜딩한 아이콘이다. 이 과정은 애플의 공식 자료 Asset Catalogs에 잘 나와 있다(그림 4).
8.2시간 - 이제야 파악된 Xcode 프로젝트 구조
이 글이 iOS 개발 강좌였다면, 이 부분은 앞에서 다뤘을 것이다. 하지만 이것은 전지적인 시점에서나 가능한 일이다. 필자는 8.2시간이 지나서야 프로젝트 구조가 파악됐다. 통합개발환경을 잘 다루는 것은 매우 중요하다. 필자가 회사에서 진행했다면 선행 그룹에 스터디를 지시하고, 스터디가 끝나면 공유하는 방식으로 진행했을 것이다. 하지만 지금 생각하면 너무 스터디 시간이 과도하고 초심자에게 전달하는 내용 또한 너무 많은 것 같다. 이 도전 이후의 필자라면 이렇게 주문할 것 같다.
“다음의 목표만 달성하도록 스터디 후 전파할 것”
1. 소프트웨어의 진입점 찾기
2. 코드 커밋/업데이트 방법
3. 코드 실행 실기기 방법 찾기
Xcode 프로젝트는 크게 다음과 같이 구성된다.
1. 프로젝트 메타
2. 참조 라이브러리
3. 소스 코드
4. 테스트 코드
그림 5에서 “A”가 붙은 파일을 제외하고 기본으로 생성된 파일이다. M은 마지막 커밋 이후에 수정된 파일을 A 마지막 커밋 이후에 추가된 파일을 뜻한다. 커밋을 하면 이 마크가 사라진다.
8.4시간 - 요구사항 외의 것을 너무 하고 싶다
도전 8시간의 결과는 필자가 생각한 것보다 진행이 빨랐다. 안도감이 들었고, 도전 중에 생각난 수많은 아이디어를 실현하고 싶은 욕구가 발동하기 시작했다. 이런 추가 요구사항을 처리하는 것은 매우 중요하다. 절대로 이런 추가 아이디어/요구사항은 이번 배포에 포함하면 안 된다. 소프트웨어의 균형이 무너지고 프로젝트가 불확실해진다. 시간이 남는다면 테스트를 더하고, 그래도 남으면 그때 검토하면 된다.
그림 6에서 “결함 #19: 상태바와 화면이 겹침”처럼 결함이 든 일감이 프로젝트 루트에 있으면 안 된다. 이 뜻은 해당 일감과 결함이 요구사항과 관련이 없다는 뜻이다. 반드시 모든 일감과 결함은 요구사항이나 다른 일감 밑에 있어야 한다.
바르게 고치면, 그림 7과 같이 새 기능의 결함이 된다. 이렇게 하면 결함에 대한 최소한의 설명으로도 무슨 뜻인지 쉽게 파악할 수 있다. 테스트 중심으로 개발한다면, 결함은 테스트 케이스 밑으로 등록한다.
9시간 - iOS Swift 하이브리드 앱의 핵심 구조
UI를 웹으로 가져가는 하이브리드 앱은 애플리케이션 아키텍처와 함께 Native에서 JavaScript를 호출하고, JavaScript에서 Native를 호출하는 Native-JavaScript Bridge가 제일 중요하다. Native와 인터렉션이 없는 하이브리드앱의 경우, 이 브리지가 필요 없지만 디바이스의 웹 비표준 영역에 있는 많은 센서(가속도, 기압, 온도, 기울기, 자기장, 지문)와 액터(카메라 플래시, 진동 모터)를 사용하기 위해서는, 이 브리지가 반드시 필요하다. 이 부분의 구현은 도전 시작 2시간쯤 구현됐으나, 제대로 했는가에 대한 확신이 없었다. 파편적인 자료와 Object C로 된 자료를 바탕으로 구현했기 때문이다. 제대로 한 것 같다.
[리스트 1]이 핵심 코드다. 이 글을 보고 따라한다면, 이 코드부터 복사할 것을 권한다. 이 브리지를 완성하려면 네이티브 소스 코드와 html 코드가 필요하다.
네이티브에서 웹을 콜할 때는 evalu-ateJavaScript를 사용하고, 웹에서 네이티브를 콜할 때는 window.webkit.messageHandlers를 사용한다. 앱뷰어에 웹뷰를 생성하고, 2개의 함수를 이용해서 통신하는 것이 하이브리드 앱 매커니즘의 핵심이다. 필자는 Xcode가 붙여준 주석은 일부러 나뒀다. 그곳에 무엇을 해야 할 지 힌트가 되기 때문이다.
9시간 - 기능 구현이냐, 결함 수정이냐
일반적으로 결함을 즉각적으로 수정하는 것은 안 좋다. 그렇다고 일주일이나 한 달 후에 수정하라는 의도는 아니다. 필자가 오늘 4개의 새 기능을 구현하기로 계획했다면, 개발 중 결함이 발생했을 때 바로 수정하지 말고 기록 후 4개의 기능 구현 후 수정하라는 뜻이다.
이 규칙의 예외가 있다. 결함이 4개 기능 개발 모두에 비용 증가와 같은 악역향을 준다면 결함 수정이 우선이다. 이전 글에서 시연 동영상을 자세히 본 독자는 필자가 실제 버튼 보다 윗쪽을 터치하고 있다는 것을 눈치챘을 것이다. 결함 때문이다. 이럴 경우 터치 이후의 사용자 시나리오 상의 모든 개발 시에 불편을 주게 된다. 이 결함의 수정 후 다시 개발을 진행했고, 이 결함의 수정으로 다른 결함도 해결됐다. 같은 원칙으로 소프트웨어를 개발하면 문제의 원인 또한 같기 때문에, 이렇게 비용절감 효과를 볼 수 있다. 아키텍처는 중요하다.
9.5시간 - 앱 강제 종료
개발환경과 케이블을 연결하고 실행을 하면, Xcode로 앱을 정지시킬 수도 있다. 하지만 케이블을 뽑은 상태에서는 좀 난감하다.
홈 버튼을 두 번 연속으로 누르면, 앱 실행 목록이 나타나고 이중 화면 윗쪽으로 스와이프 하면 해당 앱을 종료할 수 있다. 필자처럼 껐다 안 켜도 된다.
10시간 - 자연스러운 사용자 인터렉션
도전에서 만들고 있는 앱은 블루투스 LE(Low Energy) 기술을 사용하고 있다. 블루투스를 사용하기 위해서는 기기를 검색해야 한다. 하지만 이 기기 검색은 와이파이에 안 좋은 영향을 미치고 배터리 소모가 큰 편이다. 따라서 계속 검색하는 것이 아니라 필요할 때만 검색해야 한다. 웹 브라우저처럼 리플래시 같은 버튼을 추가하거나 적절히 검색해 주어야 한다.
비콘이나 기기를 찾게 되면 디바이스를 움직이게 된다. 이를 이용하여 디바이스가 어느 정도 움직일 때만 일정 시간 스캔을 하도록 프로그램밍 했다. ViewController에 [리스트 2]에 제시한 코드만 오버라이드하면 흔들림 감지가 가능하다. 하지만 많이 흔들어야한다. 우선 이 간단한 방법으로 기능을 구현하고 이후에 이벤트를 분석하여 적당한 움직임으로 블루투스 스캔이 되도록 프로그램밍한다.
사용자가 움직여서 기기의 흔들림이 발생하면, 스캔 의도를 인식하여 스캔중이라는 사용자 피드백이 필요하다. 이를 애니메이션으로 표현했다(그림 9).
11시간 - 첫 번째 추상화 인터페이스 만들기 프로토콜
그 동안 이벤트 리스닝을 위해 Swift 언어의 프로토콜을 상속하고 구현했다. 이 프로토콜이 필자가 생각하는 자바 인터페이스와 가장 비슷하게 생각하는 요소이다. 만약 필자의 생각이 맞다면 인스턴스를 만들 수 없고 바디가 없는 형태로 선언이 가능해야 한다. 블루투스 검색의 시작과 종료를 UI에서는 알 수가 없기 때문에 리스너 개념의 Delegate를 설계했다(리스트 3).
다행히 컴파일 에러가 없다.
class ViewController: UIViewController, WKScriptMessageHandler, BluetoothUIDelegate
구현부 코드다. 자바와 다르게 상속과 구현을 구분하지 않는다. 이제는 인스턴스 생성이 되는지 확인할 차례다.
var a = BluetoothUIDelegate();
생성할 수 없다는 에러가 발생한다. 필자가 생각하는 인터페이스가 맞다. 필자가 Swift 문법을 알았다면 프로토콜부터 만들었을 것이다. 전체 흐름을 설계할 수 있기 때문이다.
12시간 - 신호강도 애니메이션
비콘으로부터 가까워짐/멀어짐을 좀 더 생동감 있게 보여주기 위해서 애니메이션을 사용했다(그림 11). 비콘을 들고 멀리 이동하면서 촬영했다.
어렸을 때 많이 봤던 첩보 영화의 위치추적 신호 미터기 같은 애니메이션이다. 정보는 단순히 보여주는 것 이상의 재미를 주어야 한다.
12.5시간 - 설정값 읽기/쓰기가 필요해
앱 재실행 시 마지막에 연결됐던 장치와 재연결을 하려면, iOS의 어딘가에 마지막 연결장치 정보를 저장해야 한다. 파일 읽기/쓰기는 좀 어려운 편이다. 데이터 구조를 알아야 하고 물리적인 저장공간을 다뤄야 하기 때문이다. 때문에 모던 플랫폼은 쉽게 읽고/쓰기를 위한 Key/Value 형태의 접근을 지원한다. 플랫폼 설계 시 이전 플랫폼의 장점을 계승하기 때문이다. 그냥 있을 것이라는 믿음을 가지고 찾았더니 정말 있다(그림 12).
애플 문서에 따르면, 다음의 객체 형태의 저장을 지원한다고 한다. 여러분이 다루고자 하는 데이터가 이외의 것이라도 스트링 형태로 변환하면 되기 때문에 모두 가능하다.
- NSData
- NSString
- NSNumber
- NSDate
- NSArray
- NSDictionary
- NSURL
대부분의 객체지향 언어가 set/get 메소드를 구현하는 반면, Swift에서는 변수의 인너 블록으로 처리한다(리스트 4). 어차피 사용하는 변수 근처에 메소드를 구현하니, 이 방법이 가독성과 유지보수에 더 좋은 것 같다. set/get으로 값 저장을 처리한 이유는 언제든지 앱이 종료될 수 있게 하라는 가이드를 따르기 위함이다. 값을 set 하는 행위에서 저장이 되면 앱 종료를 걱정할 필요가 없기 때문이다. 값을 넣거나 가져올 때는 그냥 변수처럼 쓰면 된다.
BeaconProvicder.lastConnectUUID="3124234-128922-12756-12455";
println(BeaconProvicder.lastConnectUUID);
13시간 - 뒤로가기 버튼이 없다
상세 화면에서 전체 화면으로 갈 수 있는 방법이 없다(그림 13).
몇 개의 앱을 살펴봤더니 상단에 고정 내비게이션이 있다. 하지만 지금 만드는 앱의 뒤로가기 기능을 넣자고 상단에 내비게이션을 넣는 것은 공간 낭비라고 생각했다. 또한 즐겨찾는 기기보다 정보의 중요성도 낮은 데 위에 올릴 명분이 없다. 방법은 하단에 두는 방법과 제스처로 처리하는 방법이 있다. 하단에 둘 경우 페이지를 넘기는 내비게이션 정보와 겹치는 문제가 있고, 제스처는 암시(스와이프 하면 뒤로 갈 수 있음, 풍선 도움말이나 튜토리얼)나 학습이 필요하다. 화면 상단이나 하단 모두 왼손 검지나 오른손 검지로 터치하기 힘든 위치다. 그래서 그림 15와 같이 선택된 기기 이미지에 뒤로가기를 오버레이 했다.
14시간 - 하이브리드에서 네이티브의 고려
감지할 수 있는 범위 밖 기기의 위치를 보여주기 위해서는 지도가 필요하다. 지금까지는 모든 화면의 웹뷰를 통해 출력했다. 하지만 맵을 보여주기 위해서는 웹뷰와 맵뷰 사이의 전환이 필요했다. 이 과정은 코드만으로도 가능하나, 스토리보드를 통해 시도해봤다(그림 17). 여타의 다른 UI 툴과는 다르게 화면 개발에 꼭 필요한 정보만 설정하도록 하여 매우 편하다. 가능한 스토리보드 사용을 권장한다.
스토리보드도 런치 스크린처럼 각 디바이스별로 정의가 가능하다. 뷰가 늘면서 이를 제어해주는 컨트롤러도 추가된다. 뷰당 하나의 컨트롤러가 올바른 디자인이다. 맵뷰가 활성화된 상태에서 지도를 터치하면, 뒤에 있는 웹뷰가 나오는 문제 때문에 많은 시간을 소비하게 된다. 이 문제는 16시간까지 해결을 못한 상태이다. 모달 형태의 윈도우가 원인인 것 같다. 하이브리드 웹앱이면서 웹맵이 아니라 네이티브맵을 사용한 이유는 빠른 로딩 속도와 어노테이션의 지원 때문이다. 이 긍정적인 경험을 웹으로 제공하기에는 비용이 너무 많아 보였다.
16시간 - 정리
- 예쁘게 만들면 모든 스태프가 즐겁다.
- 선도 개발 조직 운영 시에는 분명한 목표를 부여하고 경제적으로 운영해야 한다.
- 요구사항 기반의 소프트웨어 개발은 아무리 강조해도 부족하다.
- Xcode6의 스토리보드는 매우 훌륭하다.
소프트웨어 개발은 기능을 늘리는 것이 아닌 긍정적인 사용자 경험을 늘리는 것을 목표로 해야한다.
하이브리드 앱이라고 웹을 사용자에게 강요하지 말라. 방법은 여러 가지다.
정보를 넘어 재미를 생각하자.
<저작권자(c)스마트앤컴퍼니. 무단전재-재배포금지>