Swift로 코딩하면 크래시 안난다면서요?

Dophi·2022년 12월 24일
0

컨퍼런스

목록 보기
1/14

소개글

각종 컨퍼런스에 나온 강연들을 정리해보면서 공부해보고 있습니다.
이번 포스팅은 DEVIEW 2020에서 김창기님께서 강연해주신 내용을 정리했습니다.
제목은 "Swift로 코딩하면 크래시 안난다면서요?" 이며 Swift에서 발생하는 크래시를 막기 위한 방법들에 대한 내용입니다.
말투는 편한 말투로 작성하니 양해 부탁드립니다.

영상 다시보기
문서 자료

발표내용

1. Swift로 바꿨는데 크래시가 줄지 않았어요

Object-C에 대한 현실적인 문제

  • Object-C를 제대로 쓸 수 있는 고급 개발자가 부족하다
  • 발생한 문제를 빠르게 확인 및 수정하기가 어렵다

Swift로 바꾸는 이유

  • Swift로 바꾸는 비용이 발생하더라도 생산성을 올릴 필요가 있다
  • 개별 개발자의 역량보다 도구가 안정성을 담보하게 할 필요가 있다
  • 정적이고 강한 타입 언어는 코드의 안정성을 도구로 상당 부분 확보 가능하다
  • 익숙치 않은 스타일의 언어(Object-C)를 다수의 개발자가 익숙한 스타일(Swift)로 바꿀 필요가 있다

Swift로 바꾸는 여러 이유가 있겠지만 그 중 하나가 위와 같은 이유입니다.
애플은 Swift를 출시함으로써 기존 Object-C 대신 Swift를 쓰면 생산성이 올라가고 크래시가 줄어들 것이라고 했습니다.

마이그레이션 후의 현실

  • 극적인 크래시 감소가 일어나진 않는다
  • 크래시의 종류만 바뀌었을 뿐이다

크래시를 줄이기 위한 방법

  • 발생한 크래시를 모두 조사하여 어떤 패턴을 가지는지 확인해본다
  • 비슷한 패턴의 크래시는 가이드라인을 만들어서 방어를 하자

하지만 Swift로 바꾼 후에서 여전히 크래시는 남아있었습니다.
그래서 크래시 패턴에 대해 정리하고 이에 대한 해결법을 가이드라인으로 만들어서 크래시를 줄이고자 했다고 합니다.

가이드라인을 만드는 법

  • 충분히 숙지할 수 있도록 개수가 많지 않고 단순해야 한다
  • 문제만 명시하는 것이 아니라 해결책도 함께 제시해야 한다
  • 가능하다면 SwiftLint 등을 써서 자동화해야 한다
  • 맴버들의 공감을 얻어서 자발적으로 따르도록 해야 효과적이다

가이드라인을 어떻게 만들어야할지 설명해주시고 있습니다.
특히, 뒤에서도 말하시지만, 억지로 가이드라인을 따르게 하는 것보다는 공감을 얻어서 스스로 지키도록 하는 것이 성장에도 좋고 효과적이라고 합니다.

2. 어떤 코딩 습관이 우리 앱을 불안정하게 만들었을까요? (룰 만들기)

Optional

Optional은 null이 될 가능성을 의미한다
Optional을 잘못 처리하면 null로 인한 크래시와 동일한 크래시가 발생한다

  • 어떤 경우에도 force unwrap은 하지 말아햐 한다
  • guard let / if let 을 귀찮아 하지 말아야 한다
  • Optional일 필요가 없을 때는 Optional로 하지 말아야 한다
  • IUO는 Optional로 바꾸는 것을 권장한다 (IUO 예시: var name: String!)
  • 타입 캐스팅도 100% 확신이 있더라도 as! 보다는 as?를 사용해야 한다

Optional은 크래시의 주요 원인 중 하나입니다.
귀찮더라도 Optional 처리는 꼭 해줘야하며, 코드에서 !를 발견한다면 잠재적인 크래시가 있다고 보면 된다고 합니다.

Arithmetic Operation

대표적인 크래시로 Overflow와 Divide by zero가 있다

Overflow

  • 연산 후 만들어지는 값의 범위에 주의할 필요가 있다
  • 필요시 오버플로우 연산자를 사용한다 (&+, &* 등)

Divide by zero

  • 다른 연산을 통해 나온 값을 사용할 때, 의심이 되면 반드시 확인이 필요하다

많이 사용되는 문법이지만, 해당 크래시들을 run-time에서 방어하기가 어렵다고 합니다.
5/0 이렇게 하는 경우는 거의 없겠지만, a/b 에서 b가 0이 될 수도 있으니, 꼭 확인하고 주의해야합니다.

32비트 호환 문제

Int같이 디바이스에 따라 32비트/64비트로 달라지는 가변적인 타입이 존재한다
64비트에서는 정상 동작하지만 32비트에서는 크래시가 나는 경우가 있다

  • 크기가 가변적인 타입은 들어가는 값의 범위를 꼼꼼하게 확인해야 한다
  • 크기가 64비트가 확실할 때는 Int64 같은 크기가 지정된 타입을 사용해야 한다

Int형은 해당 컴퓨터의 CPU 비트 수에 따라 크기가 달라진다고 합니다.
32비트 컴퓨터는 Int -> Int32, 64비트 컴퓨터는 Int -> Int64 이렇게 말이죠.
그래서 64비트 값을 넣어놨는데 32비트 컴퓨터에서 작동시키면 크래시가 날 수 있으니 주의해야 합니다.

Array에 숨어있는 위험

Array에 접근할 때 인덱스 범위를 벗어났다는 크래시를 많이 접할 수 있다

  • 항상 인덱스 범위를 벗어나지 않도록 주의한다
  • 첫 값, 마지막 값에 접근할 때는 안전하게 first, last를 쓰는 것을 권장한다
  • subscript에 대한 Extension으로 안전하게 접근할 수 있는 코드를 구현한다

subscript는 arr[2] 같이 컬렉션, 리스트, 시퀀스 등 타입의 요소에 접근하는 문법을 말합니다.
extension으로 새로운 subscript를 추가할 수 있는데, 발표 내용에서는 범위를 벗어나면 nil을 return하도록 해놓으셨네요.

Range에 숨어있는 위험

Range를 동적으로 만들 때 max를 min보다 작은 값으로 지정하면 크래시가 발생한다

  • 연산을 통해 min/max 값을 생성할 때 주의해야한다

divide by zero와 마찬가지로 min = 5, max = 3처럼 명시적으로 숫자를 써서 크래시가 나는 경우는 거의 없을 것입니다.
하지만 min = a, max = b처럼 변수를 대입하거나 연산을 통해 나오는 값을 쓴다면, 주의를 해야합니다.

하부는 여전히 Object-C

Object-C 코드에서 exception을 발생시키면 막을 수 없다
Swift의 에러 핸들링은 Object-C의 exception과 다르며 호환되지 않는다
UIKit, FoundationKit 등 기존 framework들은 여전히 Object-C로 되어있다

  • Exception 발생이 우려스럽다면 Utility 함수의 도움을 받아 처리 할 필요가 있다

Utility 함수가 모든 것을 처리할 순 없지만, 몇가지는 처리할 수 있도록 코드를 짤 수 있다고 합니다.

3. 실제로 이런 룰을 적용하면 어떻게 될까요?

실행시 마주치는 문제들

  • 명시적 저항 - 가이드라인과 팀원들의 생각이 다를 수 있다
  • 습관 - 어떻게 습관화 시킬 것인가
  • 기존 코드 - 옛날에 작성했던 코드들은 다 갈아엎어야 하는가

SwiftLint를 이용해서 걸러내기

  • 자동화 할 수 있는 부분은 자동화 하자

코드리뷰를 통해 걸러내기

  • 모든 것이 자동화되지는 않으므로 코드리뷰가 필요하다
  • 적어도 새로 작성되거나 변경되는 코드는 가이드라인을 지키도록 코드리뷰를 한다

한번에 다 고칠 수 있을까?

  • 대부분의 경우 별도의 시간이 주어지지 않고, 기존 코드를 고치는데도 비용이 상당히 크다
  • 경우에 따라서는 로직도 바뀔 수 있다
  • 신규로 작성되는 코드나 변경되는 코드는 가이드라인을 따르도록 한다
  • 옛날 코드는 주기적으로 크래시 로그를 보고, 높은 비중을 차지하는 코드를 수정한다

효과의 속도

  • 초반에 크래시가 큰 비율을 차지하던 부분은 빠르게 제거할 수 있다
  • 나중으로 갈수록 사용 빈도가 낮고 크래시도 가끔 일어나는 부분만 남게 되고, 수정 속도는 감소한다

핵심은 신규로 작성되는 코드나 변경되는 코드는 무조건 가이드라인을 따르도록 하고, 옛날 코드들을 크래시가 많이 일어나는 부분부터 차근차근 고치도록 하라는 얘기인 것 같습니다.

남은 숙제들

단순한 문제들이 사라지면 보이는 것들

  • Objective-C에서 발생하는 exception들을 모두 방어하기는 어렵다
  • 크래시를 제거한 부분에서 사이드 이펙트로 버그가 나올 수 있다
  • 멀티 스레드에서 생각보다 많은 크래시가 발생한다

Concurrency가 일으키는 문제들

  • GCD는 사용하기 편하지만 그만큼 별 생각없이 썼다가 이슈가 생긴다
  • 단순한 가이드라인보다는 정확한 학습과 꼼꼼한 코드리뷰가 필요하다
  • Thread로 돌릴 코드는 최대한 범위를 제한하고, 최대한 외부 변수에 접근하지 않도록 한다
  • 만약 복잡해진다면 GCD보다는 Operation을 사용하는 것을 고려하자
  • 특별한 이유가 없다면 main-thread에서 처리하는 것이 좋을 수 있다

획일적인 룰로 통제하는 것이 옳을까?

  • 가이드라인은 이해한 후에 적용해야, 공감을 얻고 효과적으로 이용할 수 있다
  • 결국 언어 자체의 속성과 그로 인한 코드의 방향성에 대한 고민이 필요하다
  • 일방적인 통제는 개발자 역량 향상에는 좋지 않다
  • 모든 팀원이 모다 안정적이고 생산성을 높일 방법을 함께 고민해야 한다

가이드라인이 임시방편은 될 수 있지만, 결국은 모두가 함께 고민하고 성장해야 성공적인 프로젝트가 완성된다고 합니다.

profile
개발을 하며 경험한 것들을 이것저것 작성해보고 있습니다!

0개의 댓글