WWDC22로 분석하는 Apple의 방향성

Sunny Jeon
SSG TECH BLOG
Published in
15 min readDec 29, 2022

안녕하세요? 저는 App개발팀의 iOS 개발자 전선수입니다.

이전 아티클에서 저희 파트에서 SwiftUI 도입을 고민하면서 느꼈던 점을 소개한 바 있습니다.

최소 지원버전이 iOS 16이라면 UICollectionViewCell 내부에 SwiftUI 코드를 내장할 수 있어서 “존버하면(존중하면서 버티면) 함께 사용할 수 있다”로 귀결될 수 있지만, 이 SwiftUI 를 통해 Apple의 숨은 메시지를 잘 읽는 것이 중요하다는 점 역시 함께 말씀드렸습니다. 그래서 이번 기회에 WWDC22를 정독하고 학습하며 얻었던 저의 생각을 아티클로 발간하고자 합니다.

해당 내용은 제가 2022 summer let us: Go! with SSG 에서 발표했던 “SSG의 뻔하지 않은 SwiftUI 도입 고민 (feat. WWDC22)”의 영상 후반부에 짤막하게 발표한 부분이 있으니, 직접 듣고 싶으신 분은 아래의 링크 하단의 “영상 다시보기” 2번 영상을 확인해주세요. 🥹

이 글을 읽기 전에 🍎

iOS 개발 입문자보다는 Swift 기본 문법을 이미 습득한 개발자를 대상으로 하는 내용이나, 주요 개념을 쉽게 설명하기 위해 최대한 어려운 용어 기술은 자제하였습니다. 😎
WWDC22의 Swift Generics, Protocol 두 세션을 보고 나면, 이 글을 이해하는 데 더 도움을 줄 수 있습니다.

제가 읽은 Apple이 개발자에게 안내하는 방향성

결론을 먼저 말씀드리면,

새로 Apple에 입문하는 비전공 개발자라고 하더라도, 프로그래밍할 때 주요 설계 원칙은 지켜서 개발해야 한다. Apple은 그 원칙을 지킬 수 있도록 Swift라는 언어를 더 고도화하였으므로, 개발자가 이 도구를 잘 선택하여 개발해야 한다.

라는 것입니다. 제가 이 글에서 안내할 주요 원칙은 캡슐화, 다형성, 추상화라고 할 수 있습니다. 먼저, 세 개념들의 사전적 정의를 간단하게 알아보겠습니다.

캡슐화(encapsulation)

In software systems, encapsulation refers to the bundling of data with the mechanisms or methods that operate on the data, or the limiting of direct access to some data, such as an object’s components.

출처: https://en.wikipedia.org/wiki/Encapsulation_(computer_programming

위의 문장에서 bundling과 limiting에 주목할 필요가 있습니다. 간단히 읽으면, 객체의 메서드와 속성을 묶고, 이러한 것에 직접 접근을 제한하는 특성으로 해석할 수 있습니다. 캡슐화가 잘 반영된 설계(struct, class 등)는 정보 은닉이 잘 지켜져 외부에서 함부로 수정하지 말아야 할 속성의 접근을 통제하여 유지보수성을 높여줍니다.

다형성(polymorphism)

In programming language theory and type theory, polymorphism is the provision of a single interface to entities of different types or the use of a single symbol to represent multiple different types. The concept is borrowed from a principle in biology where an organism or species can have many different forms or stages.

출처: https://en.wikipedia.org/wiki/Polymorphism_(computer_science)

사전적 정의 그대로 single interface to entities of different types를 읽으면, 다른 타입의 개체에 단일의 인터페이스를 제공하는 것입니다. 주로 Ad hoc, Paramatetric, Subtype 개념에서 쓰이는데, 다른 타입이 같은 이름의 메서드를 사용하지만 동작은 동일한 경우, 여러 파라미터에 대해 동일한 동작을 구현하다보니 Generic을 사용하는 경우, 상속에서 사용하는 경우 등이 프로그래밍 언어의 특징 중 다형성을 이해하고 개발하는 사례들이라고 할 수 있습니다.

추상화(abstraction)

In software enginerring and computer science, abstraction is: The process of removing or generalizing physical, spatial, or temporal details or attributes in the study of objects or systems to focus attention on details of greater importance; It is similar in nature to the process of generalization; the creation of abstract concept-objects by mirroring common features or attributes of various non-abstract objects or systems of study — the result of the process of abstraction.

출처: https://en.wikipedia.org/wiki/Abstraction_(computer_science)

generailizing, mirroring에 주목하여 읽는다면, 추상화한다는 것은 어떠한 것을 표현할 때 일반화하는 과정인 동시에 그 결과물이 그 특징들을 잘 반영해야 함을 알 수 있습니다. 추상화는 모델링의 근간이 되는 개념으로 요구 조건을 파악하고, 서버 API 데이터를 예측할 수 있는 시점에 진행되어야 하며, 개발이 이미 진행되고 있는 과정에서 특정 모델의 추상화는 자제해야 합니다. 물론, 스펙의 변경으로 개발 중간에 재추상화가 이뤄지는 경우도 있으나, 꼭 필요한 경우가 아니라면 추상화를 끝내고 개발을 진행해야 합니다.

이 개념들이 중요한 이유

이 3가지 개념들은 컴퓨터공학(컴퓨터과학 또는 관련 전공)에서 이미 학습하고 오는 개념들임에도 실전에서 이 의미를 이해하지 않고 개발하는 경우를 볼 수 있으며, 비전공자인 경우 학습이 충분하지 않아 잘 모른다면, 코드의 품질을 저하시키는 원인이 되기도 합니다. 😱

Apple은 이번 WWDC22에서 작심한 듯, Swift 프로그래밍 언어의 주요 문법 중 Generic과 Protocol에 대한 교육 세션을 준비하는 동시에 Swift 5.7부터는 개발자가 이 특성들을 더 편하게(자신도 모르게) 반영할 수 있도록 개선되는 부분을 짚어주기까지 합니다. 🤔

저는 저희 코어매장파트에서도 iOS 앱 개발 경력을 시작하는 신입 개발자에게 Swift 문법과 iOS 앱 개발(UIKit, Foundation 등)을 가르치기 전에, 이 개념들의 중요성을 여러 번 주지시키면서 멘토링을 진행하고 있습니다. 저는 코딩을 하기 전에, 추상화를 먼저 진행하고 나서 캡슐화가 잘 된 모델을 설계하며, 다형성을 고려하여 개발하다 보면, 본인과 팀이 설계하는 코드의 품질이 높아질 것이라 확신합니다. 🤩

UIHostingConfiguration과 캡슐화

지난 아티클의 마지막 부분에서 최소 지원버전이 iOS 16이라면, UICollectionViewCell 내부에 SwiftUI 코드를 내장하는 방법으로 Apple이 새로 발표한 UIHostingConfiguration을 소개한 바 있습니다. 그리고 SwiftUI로 미리미리 재사용 가능한 모듈화된 Custom View를 구성해놓는다면 별도의 처리 없이 XIB + AutoLayout을 쓰는 경우 효과적인 소프트 랜딩이 가능하다는 결론을 냈었습니다.

즉, 자주 사용하면서 자주 바뀌지 않는 영역이라면 SwiftUI로 잘 설계했을 때, UIKit의 의존성을 낮출 수 있고, UIKit의 퍼포먼스 마저 SwiftUI보다 떨어진다면 신속하게 교체할 수 있다는 뜻입니다. UIKit 기반의 코드를 SwiftUI로 신속하게 교체하려면 해당 영역의 모듈화가 잘 되어있어야 하며, 캡슐화가 잘 된 설계를 해야 합니다.

이미 Apple은 개발자에게 힌트를 여러 번 주고 있었는데 Objective-C의 CFArrayRef, CFStringRef 등은 이미 Opaque Type이었으며, 최근에 SwiftUI로 iOS 개발을 입문하는 개발자에게도 some View를 return하는 보일러플레이트 코드를 볼 수 있는데, 여기서 some 이라는 키워드가 이미 뷰의 캡슐화의 핵심 개념인 Opaque Type입니다.

Opaque Type과 캡슐화

some View를 return했을 때의 장점을 알면, 캡슐화의 특성을 더 제대로 이해할 수 있습니다. some View를 return한다는 것은 Opaque Type을 return한다는 뜻입니다. 이렇게 쓰면, 이 View를 가져다쓰는 곳에서는 내부 구현(=실제 타입)이 숨겨지는 이점이 있습니다. 또 다른 이점으로, 조금의 디자인 수정이 있어(가령 View 내부 구성에 HStack 하나를 더 추가한다거나 등) 수정을 하더라도 가져다쓰는 곳에서는 이 타입을 일일이 변경해 주어야 하는 수고를 덜어줍니다.

개발자는 내부 구현은 신경쓰지 않고, 오직 이 some View를 return하는 곳에만 집중하여 개발할 수 있습니다. 저희 파트에서는 아직 SwiftUI를 사용하지는 않더라도 캡슐화의 원칙은 잘 지켜서 개발하고 있습니다. 하나의 모듈유닛은 하나의 역할만 하며, 이 유닛을 가져다쓰는 곳에서는 내부 구현을 몰라도 되며, 변경이 있더라도 일일이 변경해야 하는 번거로운 일이 발생하지 않습니다. 앞으로도 이 원칙이 잘 지켜져야만, 나중에 SwiftUI로 전환 시 해당 모듈들을 Opaque Type으로 쓸 수 있다는 로드맵을 그릴 수 있다고 생각합니다.

Swift Generics와 다형성

그러나, 상황에 따라서는 호출하는 곳에서 타입을 알아야 할 수 있습니다. 즉, Opaque Type이 return되지 않아야 할 땐, 다른 방법으로 개발해야 합니다. 그럴 때 사용하는 것이 Generic입니다. Generic을 사용하면, 호출할 때는 구체적인 타입을 명시하더라도, 다양한 타입이 하나의 동작(파라미터 다형성; Parametric Polymorphism)을 하는 것을 보장하도록 설계할 수 있습니다.

즉, 현업에서는 타입에 의존하지 않는 범용 코드를 작성하기 위해, 중복을 피하고 코드를 유연하게 작성하기 위해 Generic을 사용한다고 할 수 있습니다. Apple의 Foundation 프레임워크를 잘 들여다보면 내부의 타입이 Generic으로 처리되어 있음을 알 수 있습니다.

Protocol과 추상화

Apple은 WWDC 2015에서 Swift를 Protocol Oriented Programming 언어라고 발표한 바 있습니다. 어떻게 보면 Swift를 마케팅하기 위한 단어 선택이라고 볼 수 있지만, Apple은 추상화의 측면에서 더 큰 지원을 하고 있는 Protocol을 개발자가 사용하도록 방향을 제시하고 있습니다. Protocol을 사용하면, 어떤 프로퍼티와 메서드를 구현해야 하는지 명확해지며, 다중 상속을 사용하지 못하는 Swift Class의 한계를 뛰어넘을 수 있습니다.

즉, Protocol을 잘 사용하면, 주요 비지니스 로직을 우아하게 추상화할 수 있습니다. 하지만, 로직과 관계를 추상화하는 데에는 좋은 문법적 요소이나, 모든 설계를 Protocol만 고집하여 개발하는 것은 추천하지 않습니다. 여전히 struct와 class는 객체와 모델을 추상화하는 가장 효과적인 설계 수단이기 때문입니다. 수평적으로 채택할 수 있는 로직들과 모델을 Protocol로 추상화하는 것이 좋습니다.

이제, 코드 보안을 해치지 않는 선에서 현업에서 Generic과 Protocol을 잘 반영하는 예제를 하나 보여 드리겠습니다. 이 예제에서는 서로 다른 탭모듈이 똑같은 액션을 하는 로직을 어떻게 개발하는지를 살펴보겠습니다.

각 모듈들은 서로 다른 형태의 데이터를 저장하며, 탭했을 시 하단에는 필터링된 데이터를 보여주어야 합니다. 필터가 저장하는 로직을 단순하게 이렇게 개발할 수도 있습니다만,

두 개의 동일한 카테고리 모듈이 필터링 액션을 한다고 하면(= 각 필터에 해당하는 로직이 어떤 액션을 해야 하는지 protocol로 개발하면 되고), 두 개의 데이터 타입은 다르더라도 이전에 받은 서버 데이터를 저장하는 동작만큼은 같아야 합니다. (= 이 저장하는 동작을 각각 따로 구현할 수도 있겠지만, Generic을 사용하여 하나의 동작으로 통일하여 개발할 수도 있습니다.)

Generic을 사용하면 로직을 일관되게 가져갈 수 있고, 버그가 일어날 확률 역시 낮출 수 있음을 확인할 수 있습니다.

Swift 5.7부터 생기는 변화 (feat. WWDC22)

WWDC22를 보다보니, 놀라운 변화를 알 수 있었습니다. Generic 메서드를 개발할 때, 두 개 이상 타입이 들어가다 보면 메서드를 이해하기 어려울 정도로 가독성이 떨어지는 경우가 있었는데, 이런 단점을 해결해주는 묘수를 던져주었기 때문인데요.

바로, Swift 5.7부터는 some 키워드를 파라미터에서도 쓸 수 있게 되었습니다. 즉, Opaque Type을 받는 것처럼 보기 편해진 것입니다. 이로써 미래에는 불필요한 where절이나 <T: Type1, U: Type2, V: Type3, W: Type4> 이런 구문은 더 이상 보지 않아도 될 것으로 보입니다.

그리고 Protocol로 추상화를 반영하다 보면, 불편한 점이 있었는데, Opaque Type을 파라미터에 넣는다고 하더라도 여러 타입이 담기는 Array와 같은 자료 구조에서는 같은 액션을 취하도록 구현하는 것이 불가능했습니다. 그러나 이 역시 추상화한 Protocol 앞에 any를 붙여서 같은 액션을 쉽게 할 수 있습니다.

결론

Swift의 some은 Swift 5.1에서 처음 소개됐으며, any는 Swift 5.6에서 처음 소개된 문법적 개념이나, 이번 WWDC22를 보면서 Swift 5.7부터는 someany를 잘 사용한다면, 개발자가 추상화 과정에서 설계를 더 세련되게 할 수 있을 것이라는 확신을 얻을 수 있었습니다. 그 설계의 맛을 제대로 느껴보려면, 개발자가 컴퓨터 공학의 중요 개념들인 캡슐화, 다형성, 추상화를 잘 이해해야 합니다.

많은 분들이 본인 나름의 주관대로 Apple의 숨은 메시지를 잘 찾아보며, 이번 WWDC22의 여러 세션들을 즐겁게 감상했을 것이라 생각하지만, 저는 처음에 Apple이 제안하는 이상적인 설계 방향이나 디자인 패턴이 무엇일지 무척 혼란스러웠습니다. 🤯
하지만,

중요한 것은 꺾이지 않는 마음

중꺾마 정신을 되새기며, 기본 개념에 최대한 초점을 맞춰서 정독하니 여러 퍼즐들(Apple이 SwiftUI의 View를 Opaque Type으로 캡슐화하여 return하도록 설계를 제안했던 점, Generic과 Protocol 세션이 조금 교육에 가까운 느낌으로 제공했던 점 등)이 맞춰지기 시작했습니다. 🧩

이 아티클이 WWDC22의 여러 세션들을 더 잘 이해할 수 있고, 누군가에게는 올바른 설계 원칙을 지키게 인도하는 모피어스 같은 아티클이 되길 바랍니다.

읽어주셔서 감사합니다! 따뜻한 연말 보내시길 바라요🙏🏻

--

--