Skip to content →

일본의 연호 변경, 남의 일이 아닙니다.

2019년 4월 1일부로, 일본은 새로운 연호 레이와(令和)를 쓰게 되었습니다. 그렇습니다. 일본은 자체 연호를 쓰는 나라입니다. 그리고 이 연호는 그저 상징적으로 존재하지 않습니다. 일본에서는 아주 많은 사람들이 이 연호를 일상적으로, 그리고 업무적으로 사용하죠. 그리고 iOS 개발자 입장에서, 이는 결코 간과해서는 안 될 사실입니다.

설정앱→언어 및 지역→캘린더 로 들어가면 iOS가 지원하는 여러 달력을 확인 할 수 있습니다.

우리는 종종 날짜 시스템이 전 세계적 표준을 따르고 있다고 무의식적으로 생각할 때가 있는데, 이런 생각은 예상치 못한 곳에서 치명적인 버그를 일으킵니다.

재현 되지 않는 크래시

입사 초기에, Crashlytics에서 지속적으로 잡히는 버그가 있었습니다. 커스텀으로 만든 DateFormatter에서 잡히는 에러였는데, 아무리 해도 로컬에서는 재현이 되지 않았습니다. 그 때 에러를 뱉던 코드는 다음과 같았습니다.

let dateFormat = DateFormatter()
dateFormat.dateFormat = "yyyy/MM/dd/HH/mm/ss"
print(dateFormat.date(from: "20160610090000"))

아주 간단한 코드죠. 그런데 참 묘했습니다. 잊을만 하면 이 코드에서 크래시가 발생했다고 계속해서 크래시 리포트가 날아오는 것이었습니다. 엄청 자주 크래시 리포트가 날아오는 것이라면 두 발 벋고 뛰어 들어 어떻게든 문제를 파헤쳐 해결했겠지만, 몇 달에 한 번 꼴로 일어나는 버그여서, 우선순위가 높아지질 않았습니다. 무엇보다도 재현이 불가능했기 때문에, 아주 오랜 기간 이 버그는 해결 되지 않고 남아있었습니다.

하지만 아무리 가끔씩 날아오는 버그라고 하더라도, 꾸준히 날아오는 버그를 무시하기 힘든 순간이 왔습니다. 저는 연휴에 생긴 여유 시간 동안, 이 버그를 기필고 잡고야 말겠다는 생각으로 크래시 리포트와 관련된 코드를 눈이 빠지게 쳐다보기 시작했습니다.

다행히 그 동안 누적된 크래시 리포트를 분석하니, 모든 케이스를 관통하는 공통점을 발견 할 수 있었습니다. 바로

  1. 일본의
  2. iOS 10이하
  3. iPhone5 기기

에서 발생한 크래시들이라는 점이었습니다. 여러 시행 착오 끝에, 여기에서 실마리를 얻어서 “설마…”하는 마음으로, 설정앱에서 “일본력”으로 달력을 설정하고, iPhone 5 시뮬레이터에서 해당 코드를 실행시켰습니다. 그리고…크래시가 났습니다! 재현에 성공한 것입니다! 이제 왜 그 동안 이 크래시가 그렇게 재현되지 않는지가 명쾌해졌습니다. 주변에 iPhone 5를 쓰면서 일본력을 쓰는 사람이 있을 리가 없지요! 사실 iPhone에서 “일본력”을 지원한다는 사실, 그리고 일본에서는 일본력을 엄청 많이 쓴다는 사실, 그리고 일본력의 체계 등등도 이 때 알게 되었습니다.

생각해보면 그렇습니다. “20160610090000”라는 문자열은 “쇼와 몇 년?”으로 해석 할 수 있을까요? 당연히 해석 될 수 없지요. 이런 작업은 우리가 전혀 예상치 못한 결과를 내뱉을 뿐입니다.

특히 저희는 위 연산의 결과값에 몇 가지 연산을 추가로 하고 있었는데, 이 연산의 과정 중에서 32bit에 담을 수 없는 커다란 숫자가 발생해서 Integer Overflow가 일어난 것이 크래시의 직접적인 원인이 되었습니다. iPhone 6이후의 기기들은 모두 64bit 를 사용하고 있으니, integer overflow가 일어날 일이 적었기 때문에 일본에서도 iPhone 5를 쓰는 사람들에게서만 크래시가 나고 있었던 것입니다. 실제로 일본력을 쓰는 iPhone6사용자분들 께서는 굉장히 이상한 날짜 표시가 보여지는 버그를 경험하셨겠죠.

위 문제는 다음과 같이 코드 한 줄을 추가하여 해결하였습니다.

let dateFormat = DateFormatter()
dateFormat.dateFormat = "yyyy/MM/dd/HH/mm/ss"
dateFormatter.locale = Locale(identifier:"en_US_POSIX") // 추가 된 코드
print(dateFormat.date(from: "20160610090000"))

이 버그는 아주 많은 교훈을 주었습니다.

  • 날짜를 다루는 일은 아주 어려운 일이며, 우리가 함부로 커스텀한 DateFormatter나 DateModel을 만들어서 문제를 해결하면 안 된다는 것
  • 가급적 setLocalizedDateFormatFromTemplate 등 처럼 iOS Framework에서제공하는 기능들을 사용해서 문제를 해결해야 한다는 것.
  • 앱을 만드는 것은 단순히 예쁜 화면을 만드는 것 뿐이 아니라, 여러 나라의 문화와 생활 관습을 이해하고 반영하는 일이라는 것.
  • 도저히 해결 안 되는 버그도, 포기하지 않고 계속해서 관심을 가지면 어느 순간 실마리를 붙잡을 수 있다는 것.

쓰고 보니 짧은 글이지만, 제가 오기 전부터 몇 년동안 계속해서 발생하던 버그였고, 저도 이 버그를 고치기까지 적지 않은 삽질을 했습니다. 고쳤다는 사실보다, 포기하지 않고 물고 늘어진 끝에 얻은 승리였기 때문에 더더욱 기억에 오래 남는 버그였네요.

참고 문헌

Published in Debugging

Comments

댓글 남기기

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d 블로거가 이것을 좋아합니다: