Boost‐SwiftUI‐2025.05.20(화).md - BoostSwiftUI/SwiftUI GitHub Wiki
원본 텍스트 파일
스터디 시간 및 참여자
- 2025.05.20 화 오후 9:03 ・ 61분 24초
- 고병학 권승용 김대황 김인환 유정주 이준복 이창준
- 클로바노트를 이용해 회의 내용을 기록하고, Claude를 이용해 요약, 편집했습니다.
프로토콜(Protocol) 활용 및 설계 패턴
현업에서의 프로토콜 활용 현황
현업 개발자들이 실제로 프로토콜을 어떻게 활용하고 있는지에 대한 경험을 공유했습니다. 대부분의 개발자들이 프로토콜을 잘 활용하려고 노력하고 있지만, 실제 적용에서는 몇 가지 패턴으로 수렴되는 경향을 보였습니다.
다형성을 위한 프로토콜 활용
- 리스트 내 다양한 타입 관리: 기존에 타입 캐스팅을 사용하던 코드를 프로토콜과 제네릭을 조합하여 리팩터링
- 리스트 안에 다양한 종류의 타입이 들어갈 수 있도록 공통 프로토콜로 묶어서 처리
- 제네릭을 활용하여 동적으로 타입을 받을 수 있게 구현
- 기존의 switch문을 통한 타입 검사 방식에서 벗어나 더 유연한 구조로 개선
공통 모듈 추출을 위한 인터페이스 패턴
가장 일반적으로 사용되는 패턴으로, 공통 로직을 모듈화할 때 프로토콜을 인터페이스로 활용하는 방식입니다:
-
기본 구현 패턴:
- 프로토콜을 public으로 선언하고 공통적으로 사용하는 로직들을 모두 포함
- Extension을 통해 기본 구현을 제공하여 중복 코드 제거
- 각 구현체에서는 필요한 부분만 오버라이드하여 사용
-
모델 추상화 패턴:
- 다양한 곳에서 사용하는 모델의 이름이 변경될 가능성에 대비
- 프로토콜을 통해 공통 인터페이스를 정의하고 실제 사용처에서는 프로토콜 타입으로 처리
- 공통으로 사용하는 변수들을 프로토콜에 미리 선언하여 일관성 확보
Associated Type 사용의 한계와 대안
Associated Type을 사용할 때 겪는 어려움과 해결 방안에 대한 논의:
-
Associated Type의 문제점:
- 타입 추론이 복잡해지면서 프로토콜을 채택하지 않은 것처럼 보이는 현상 발생
- Swift 6 이후 Associated Type 구체화 요구사항으로 인한 경고 메시지 증가
- 코드의 복잡성이 증가하면서 유지보수가 어려워짐
-
대안적 접근법:
- Associated Type 대신 제네릭을 활용하여 동일한 효과 달성
- 프로토콜 내부의 Associated Type 사용을 최대한 줄이고 외부에서 제네릭으로 처리
- 단순함을 유지하면서도 타입 안전성을 확보할 수 있는 방향으로 설계
모듈화 및 리소스 관리
모듈 구조 설계
실제 프로덕션 환경에서 적용된 모듈화 전략과 그 효과에 대한 사례를 공유했습니다:
-
모듈 분리 구조:
- App: 메인 애플리케이션 모듈
- Core: 핵심 비즈니스 로직
- Domain: 도메인 계층 로직
- Data: 데이터 계층 및 API 통신
- Design System: 공통 UI 컴포넌트 및 디자인 요소
-
공통 모듈 관리:
- API 기반 주소가 동일한 경우 공통 모듈로 분리
- 서드파티 로그인 로직과 같이 여러 서비스에서 공통으로 사용하는 기능들을 별도 모듈로 관리
- Repository 패턴을 활용하여 데이터 소스 추상화
리소스 관리 최적화
카카오 테크 블로그에서 소개된 리소스 관리 방법을 실제 적용한 사례:
-
리소스 접근 방식 개선:
// 기존 방식 UIImage(named: "imageName") UIColor(named: "colorName") // 개선된 방식 UIImage.imageName // 자동완성 지원 UIColor.primaryColor // 타입 안전성 확보 -
구현 방법:
- Associated Type을 활용한 리소스 프로토콜 정의
- Extension을 통해 UIImage, UIColor에 정적 프로퍼티 추가
- Bundle 지정 시 프레임워크별로 적절한 Bundle 설정 필요
-
장점:
- 자동완성 지원으로 개발 생산성 향상
- 컴파일 타임에 리소스 존재 여부 확인 가능
- 색상 팔레트나 이미지 리소스가 많은 프로젝트에서 관리 효율성 극대화
카카오 로그인 SDK 이슈 해결
문제 상황 분석
카카오 로그인 SDK를 사용하면서 발생한 크래시 이슈에 대한 상세한 분석과 해결 과정:
- 크래시 발생 패턴:
- Continuation을 사용하여 카카오 로그인을 async/await 패턴으로 감쌀 때 앱이 종료되는 현상
- 크래시 리포트에서 CheckedContinuation 관련 오류가 지속적으로 발생
- 정확한 크래시 지점을 파악하기 어려워 디버깅에 상당한 시간 소요
근본 원인 파악
카카오 개발자 포럼을 통해 확인한 SDK의 구조적 문제:
-
SDK 내부 동작 방식:
- 카카오톡 로그인 플로우에서 여러 번 호출될 경우, 가장 마지막 호출만 보장
- 이전 호출들은 결과를 받지 못하고 대기 상태로 남게 됨
- 결과를 받지 못한 Continuation이 timeout되면서 크래시 발생
-
단일 실행 보장 부재:
- SDK 자체에서 중복 호출에 대한 방어 로직이 없음
- 개발자가 직접 중복 호출을 방지해야 함
- 연속된 버튼 탭으로 인한 중복 호출이 주된 원인
해결 방법 구현
NSLock을 활용한 단일 실행 보장 메커니즘 구현:
private let loginLock = NSLock()
func kakaoLogin() async throws {
guard loginLock.try() else {
throw LoginError.alreadyInProgress
}
defer {
loginLock.unlock()
}
// 카카오 로그인 로직 실행
}
-
구현 핵심:
- NSLock을 사용하여 동시 실행 방지
- try() 메서드로 락 획득 실패 시 즉시 반환
- defer를 활용하여 모든 실행 경로에서 락 해제 보장
-
적용 결과:
- 카카오 로그인 버튼 연속 클릭 시에도 안정적으로 동작
- Continuation 관련 크래시 완전 해결
- 사용자 경험 개선 및 앱 안정성 향상
오디오 세션 관리 문제
시스템 인터럽트와 오디오 세션
지속적인 음성 녹음이 필요한 앱에서 발생하는 시스템 인터럽트 처리 이슈:
- 문제 상황:
- 앱이 계속 녹음을 수행하는 도중 전화, 알림 등의 시스템 인터럽트 발생
- 인터럽트 발생 순간 오디오 하드웨어에서 가져오는 음성 포맷의 샘플레이트가 0으로 변경
- 샘플레이트가 0인 상태에서 오디오 엔진 인스턴스를 시작하면 포맷 불일치로 크래시 발생
오디오 포맷 불일치 문제
-
샘플레이트(Sample Rate) 개념:
- 아날로그 음성을 디지털로 변환할 때의 샘플링 주파수
- 오디오 엔진 설정 시 하드웨어 포맷과 앱에서 지정한 포맷이 일치해야 함
- 일반적인 상황에서는 자동으로 일치하지만, 인터럽트 상황에서는 예외 발생
-
인터럽트 타이밍 이슈:
- 시스템에서 발송하는 인터럽트 노티피케이션 시점과 실제 하드웨어 권한 반환 시점 간의 차이
- 노티피케이션을 받고 즉시 오디오 엔진을 재시작하면 아직 하드웨어가 준비되지 않은 상태
- 이 짧은 시간 간격에서 포맷 불일치 문제 발생
해결 방법 및 최적화
단계별 안전 장치를 통한 안정적인 오디오 세션 관리:
-
인터럽트 시작 처리:
- 주기적으로 실행되는 녹음 로직을 일시 중단
- 리소스 정리 및 현재 상태 저장
-
인터럽트 종료 처리:
- 하드웨어 포맷 정보를 오디오 엔진에서 직접 조회
- 샘플레이트 값이 유효한지 검증 (0이 아닌지 확인)
- 유효하지 않은 경우 짧은 지연 후 재시도 (최대 5회)
- 재시도 간격을 통해 하드웨어가 안정화될 시간 확보
-
안정성 개선 효과:
- 버전 2.0 초기부터 지속되던 천 건 이상의 크래시 해결
- 다양한 디바이스와 iOS 버전에서 일관된 동작 보장
- 사용자의 통화나 알림 수신 시에도 자연스러운 앱 복구
AI 도구 활용 사례
GPT Codex를 통한 개발 생산성 향상
실제 프로덕션 환경에서 GPT Codex를 활용한 개발 워크플로우 개선 사례:
-
브랜치 기반 작업 흐름:
- 개발 요구사항을 자연어로 GPT Codex에 전달
- 각 기능별로 별도 브랜치를 자동 생성하여 코드 작성
- Pull Request 형태로 코드 리뷰 및 머지 과정 진행
-
실제 적용 예시:
- 간단한 기능 추가나 버그 수정을 단계별로 요청
- 각 단계마다 개별 커밋으로 관리되어 변경 사항 추적 용이
- 코드 품질과 일관성을 어느 정도 유지하면서도 개발 속도 향상
-
현재 한계점:
- 불안정한 동작으로 인해 PR 생성이 실패하는 경우 발생
- 복잡한 비즈니스 로직이나 프로덕션 레벨의 코드에는 아직 제한적
- 단순하고 반복적인 작업에 특히 효과적
노트북 LM을 활용한 학습 관리
구글에서 제공하는 노트북 LM을 활용한 기술 학습 및 문서 관리:
-
다양한 소스 지원:
- YouTube 영상, PDF, 마크다운, 텍스트 파일, 웹사이트 등
- 오디오 파일 및 구글 독스, 슬라이드 등 구글 워크스페이스 연동
- 여러 소스를 조합하여 종합적인 학습 자료 구성
-
자동 콘텐츠 생성:
- 입력된 자료를 바탕으로 마인드맵 자동 생성
- 학습 가이드 및 용어집 제공
- 팟캐스트 형식의 오디오 콘텐츠 자동 생성
-
대화형 학습 지원:
- 학습 자료를 바탕으로 질문-답변 형식의 대화 가능
- 출처 정보를 함께 제공하여 신뢰성 확보
- 스피드 퀴즈 등 다양한 학습 방법 제공
-
실제 활용 사례:
- JavaScript 학습을 위해 관련 영상들을 모두 링크로 추가
- 자동 생성된 마인드맵으로 전체 구조 파악
- 특정 개념에 대한 상세 설명과 예시 코드 확인
앱 배포 및 버전 관리 정책
배포 주기 전략
다양한 회사에서 적용하고 있는 앱 배포 주기와 그 배경:
-
주간 배포 (1주 1회):
- 광고 기반 수익 모델을 가진 서비스에서 주로 채택
- 새로운 광고 형태나 수익화 기능을 빠르게 출시
- 사용자 피드백을 신속하게 반영하여 개선 사항 적용
-
월간 배포 (1개월 1회):
- 가장 일반적인 배포 주기로 많은 회사에서 채택
- 충분한 테스트 기간 확보와 안정성 보장
- 기능 개발과 QA 프로세스의 균형점
-
분기별 배포 (3개월 1회):
- 대규모 기능 변경이나 메이저 업데이트 중심
- 철저한 테스트와 안정성 검증에 충분한 시간 투자
- Q1, Q2, Q3, Q4 분기별 계획적 배포
하위 버전 호환성 관리
-
호환성 기준 설정:
- 사용자 비율 1% 미만 버전까지 지원하는 정책
- 통계 데이터를 기반으로 한 과학적 의사결정
- 개발 리소스와 사용자 커버리지의 균형점 확보
-
iOS 버전 호환성:
- 최신 iOS 버전 출시 후 일정 기간 경과 후 최소 지원 버전 상향 조정
- 새로운 iOS 기능 활용과 레거시 지원의 트레이드오프 고려
-
앱 버전 호환성:
- 강제 업데이트 정책의 신중한 적용
- API 변경 시 이전 버전과의 호환성 유지 방안
- 백엔드 API 버전 관리와 연동된 전략 수립
품질 관리 및 모니터링
-
크래시율 목표 설정:
- 99.9% 크래시 프리율 목표로 설정
- Firebase Crashlytics를 통한 실시간 모니터링
- 크래시 발생 시 즉시 대응 체계 구축
-
외부 모니터링 도구 활용:
- 대기업에서는 자체 개발한 모니터링 시스템 활용
- 사용자 행동 분석을 위한 Amplitude 등의 도구 사용
- 다양한 지표를 종합적으로 분석하여 앱 품질 관리
기술적 인사이트 및 향후 과제
프로토콜 설계의 실용적 접근
이론적으로 완벽한 프로토콜 설계보다는 실용적이고 유지보수가 용이한 방향으로의 접근이 중요함을 확인했습니다. 복잡한 Associated Type이나 고급 기능보다는 단순하고 명확한 구조가 장기적으로 더 유리할 수 있습니다.
SDK 의존성 관리의 중요성
서드파티 SDK를 사용할 때는 해당 SDK의 내부 동작 방식을 충분히 이해하고, 예상치 못한 동작에 대비한 방어 코드를 작성하는 것이 필수적입니다. 특히 비동기 처리와 관련된 부분에서는 더욱 신중한 접근이 필요합니다.
AI 도구의 현실적 활용
AI 도구들이 개발 생산성 향상에 실질적인 도움을 주고 있지만, 아직은 단순하고 반복적인 작업이나 학습 보조 도구로서의 역할이 중심입니다. 복잡한 비즈니스 로직이나 아키텍처 설계에는 여전히 개발자의 판단과 경험이 핵심적인 역할을 합니다.
앱 배포 전략의 다양성
각 회사와 서비스 특성에 따라 최적의 배포 주기와 버전 관리 정책이 다를 수 있으며, 사용자 데이터와 비즈니스 목표를 종합적으로 고려한 전략 수립이 중요합니다.