Skip to content
ioob.dev
Go back

애플 공식 SwiftUI 튜토리얼은 2년째 깨진 채다

SwiftUI After 7 Years: A Story of Mediocrity

원문 보기 · Code Bird · ykvm ·
· 10분 읽기

애플 튜토리얼을 그대로 빌드하면 깨진다

ykvm이 “내 말을 믿을 필요 없다”며 내미는 물건은 애플의 1차 자료입니다. 애플 공식 SwiftUI 튜토리얼의 완성 데모 프로젝트를 받아 최신 Xcode로 빌드하고 최신 macOS에서 실행하면 됩니다. 결과는 영상 타임스탬프로 보여주고요. 그 프로젝트의 사이드바는 커스텀이 아니라 아주 표준적인데요. 원문 저자가 이 현상을 처음 본 건 2년도 더 전이고, 그동안 바뀐 건 Liquid Glass 때문에 버튼 크기가 서로 달라진 것뿐입니다. 그건 SwiftUI 탓이 아니라고 원문에서도 먼저 못 박습니다. 고치진 않았죠.

레이아웃 엔진이 크기 협상 위에 서 있다는 설계는 키노트에서는 논리적으로 들립니다. 떠 있는 뷰나 커스텀 사이드바를 짜보면 얘기가 달라지는데요. 결국 전부를 GeometryReader로 감싸게 되는데, 원문은 이 지점을 항복 선언이라고 부릅니다. 그 순간 선언형의 이득은 사라지고 좌표를 손으로 계산하게 되며, 그 코드는 벗어나려 했던 Auto Layout보다 더 장황해집니다. 게다가 다음 업데이트에서 레이아웃 엔진이 또 바뀌면 그 좌표 산수를 통째로 다시 쓰게 되겠죠.

데이터 흐름도 같은 진단을 받습니다. 단일 진실 공급원은 문서에서만 꿈이고, 실물은 프로퍼티 래퍼와 매크로와 계속 바뀌는 지원 프레임워크의 뒤범벅이죠. 애플이 성능이 재앙 수준이고 SwiftUI가 뷰를 상시 재렌더하고 있다는 걸 깨닫고 Observation 프레임워크와 @Observable을 내놨지만, 컴파일러 트릭으로는 부족했고 레이아웃 엔진은 여전히 추측을 계속합니다.

“SwiftUI에서는 뷰가 몇 번 갱신될지, 갱신될 때 왜 그러기로 했는지 확실히 알 수가 없다. 문서화되지 않은 디버깅 API를 써도 전체 그림은 안 나온다.”

(“In SwiftUI, you can never know for sure how many times a view will update and, when it does, why it chose to. Even using the undocumented debugging APIs doesn’t give you the full picture.”)

if #available로 뒤덮인 코드베이스

요즘 SwiftUI 코드베이스를 열면 if #available 체크가 우스울 지경으로 널려 있습니다. ykvm은 우습다기보다 창피하다고 씁니다. 2019년에 누군가 코드를 더 적게, 더 낫게 쓰게 해주겠다고 했는데 7년 뒤에 남은 게 이겁니다.

기능 동등성 쪽 목록은 구체적입니다. UIKit이나 AppKit에 수십 년 있던 것이 SwiftUI에 도착한 시점을 늘어놓으면 이렇습니다.

첫 버전부터 있던 API도 안전하지 않습니다. NavigationView는 버그가 많기로 유명했는데 애플은 그걸 고치는 대신 NavigationStack으로 통째로 갈아치웠죠. 그러면 구버전용 분기를 따로 유지해야 합니다.

원문이 대조군으로 드는 건 Jetpack Compose입니다. 의존성 관리자로 받아 실행 파일에 같이 묶으면 2014년 기기에서도 똑같은 UI가 나오는데요. SwiftUI에는 그 백포팅 경로가 없어서, 최신 API로 짜고 구버전에 내려보내는 대신 shim과 패치를 쓰고 다음 업데이트에서 안 깨지길 빌게 됩니다.

“우리는 기본적으로 애플의 QA 일을 대신 해주고 있다.”

(“We’re basically doing Apple’s QA work for them.”)

성능 쪽은 ykvm 자신의 대조 실험입니다. 실험용 앱의 예전 버전에 있던 이미지 갤러리를 UIKit과 SwiftUI로 붙여 비교했는데, 배경 스레드 디코딩 같은 손질을 다 하고도 SwiftUI 그리드 스크롤이 눈에 띄게 덜 매끄럽습니다. 일부러 구형 아이폰을 썼다는 단서도 본인이 붙이고요. JPEG 몇 장 띄우는 데 M5 Pro Max 슈퍼칩이 필요하다면 아키텍처가 통째로 잘못된 것이고, 고품질 소프트웨어는 그렇게 만드는 게 아니라는 겁니다.

한 번 배우고, 두 번 배우고, 사방에서 디버깅하기

크로스플랫폼 약속은 ykvm이 보기에 애초에 조심스럽게 걸려 있었습니다. 옛 키노트를 다시 봐도 “write once, run anywhere”라는 말은 안 나오고 “이 도구들을 한 번 배워서 어디에나 적용하라”는 쪽이죠.

문제는 그 한 번이 한 번으로 안 끝난다는 데 있는데요. iOS에서 배운 SwiftUI는 맥 레이아웃에 거의 그대로 쓰이지 않습니다. 데이터 흐름이나 합성 레이아웃 같은 핵심 개념은 같지만 실제로 쓰는 컴포넌트와 설정 방법이 다르고, 같은 뷰가 플랫폼마다 다르게 구현돼 있기도 하고요. 6인치 화면과 27인치 화면의 UI 설계가 같을 리 없겠죠.

“내 경험상 SwiftUI의 ‘한 번 배워 어디에나 적용하라’는 자주 이렇게 바뀐다. 한 번 배우고, 두 번 배우고, 어딘가에 적용하고, 사방에서 디버깅하기.”

(“In my experience, SwiftUI’s ‘learn once, apply anywhere’ often turns into ‘learn once, learn twice, apply somewhere, debug everywhere.’”)

이 대목이 HN에서 가장 정면으로 반박당한 자리입니다. willtemperley는 iPad와 macOS 사이에서 대부분의 컴포넌트가 똑같이 동작해서 일주일 내내 iPad에서 테스트하지 않고도 일한다고 썼습니다. 대신 그가 문제 삼는 건 다른 축인데요. M2 Max에서 돌리는 macOS 성능이 M1 iPad보다 한참 나쁘고, 특히 애니메이션이 그렇다는 겁니다.

나쁜 게 아니라 평범한 것

여기까지가 프레임워크 이야기고, ykvm의 진짜 표적은 그 뒤에 있습니다. 그는 SwiftUI를 애플의 기준선이 내려간 증거로 읽습니다.

Cocoa와 Aqua 시절이라면 상상도 못 할 일이었죠. 잡스가 핥고 싶어지는 버튼 대신 깜빡이는 사이드바와 튀는 버튼을 들고 나왔다면 그 자리에서 조리돌림당했을 거라고요. 그리고 자기가 최근 몇 달 사이 직접 본 것들을 늘어놓습니다.

모두 애플이 만든 것들입니다. 원문은 이걸 찾으려고 깊이 판 게 아니라고 덧붙이고요.

velocity라는 단어에 대한 정의가 이 글에서 가장 날이 선 문장입니다.

“생산 등급 품질과 안정성에 대한 기대는 이른바 velocity에 자리를 내줬다. 쓰레기를 출하하고 싶은데 그걸 더 빨리 하고 싶을 때 쓰는 단어.”

(“The expectations of production-grade quality and stability gave way to so-called velocity—which is a word you use when you want to ship garbage, only do it faster.”)

그래서 도대체 SwiftUI의 무엇이 문제냐는 자기 질문에 ykvm이 내놓는 답은 한 단어입니다. 전부. 적어도 안정적이고 성능이 나오고 유지보수되는 시스템을 만드는 데 중요한 것 전부.

“SwiftUI는 진짜로 나쁜 게 아니다. 평범한 것이다. 그리고 그게 내 생각엔 훨씬, 훨씬 더 나쁘다.”

(“SwiftUI is not truly bad. It’s mediocre. And that, in my opinion, is much, much worse.”)

나쁜 물건은 버릴 근거를 줍니다. 평범한 물건은 그 근거를 안 주죠. 그런데 ykvm은 7년을 꼬박 세면서도 정작 자기가 그 실험용 앱을 무엇으로 통째로 다시 짰는지는 “궁극의 크로스플랫폼 프레임워크”라고만 하고 끝내 밝히지 않습니다. 다음 얘기라고 미뤄둔 그 이름이 이 글에서 유일하게 빠진 증거입니다.


Share this post on:

Comments

Loading comments...