테이스터라는 테이스팅 노트 앱을 개발하면서 앱을 개발해서 배포한다는 것의 책임에 대해 알게 되었고, 기초적인 지식이 없이 무조건 새로운 기술을 도입해 보는 것이 능사는 아니라는 것을 뼈저리게 깨닫고 반성하게 되었다.
나에게 개발자로서의 자세에 대해 깊게 생각해본 계기가 되었고, 개발에 대한 아프지만 의미 있는 경험이라고 생각하여 이렇게 블로그에 기록해 본다.
🚧 사건의 배경
나는 2023년 12월 11일, SwiftData를 도입한 테이스팅 노트인 테이스터라는 앱을 배포했다.
모든 과일이나 물건들의 디자인을 가져올 수 없어서 피그마에 모든 아이콘을 여러 레퍼런스를 참고해서 그릴정도로 열정적으로 1인 앱 개발에 힘썼다.
약 1년 동안 다운로드 수가 516건, 업데이트가 앱 배포 시 몇백 건은 되는 듯하여 적지 않은 사용자가 있는 앱이었다.
🆙 업그레이드를 해보자
사용하는 유저가 있다 보니 앱에 대한 좋은 평가도 있었다. 개선사항도 열심히 적어주시는 것을 보고 앱을 조금 더 업그레이드 해보자!라는 생각이 생겨 작업을 시작하게 되었다.
우선 간단하게 맛, 향들을 추가했다. 하지만 여기서 추가적으로 개선하고 싶었던 것이 있었는데... 바로 모델의 변경이었다. 자세한 내용들은 아래 포스트에 있지만 간단하게 요약해 본다면...
[Project-Taster] 기본 컴포넌트 적용 및 아키텍처 변경
현재 앱 구조는 아래와 같다. 이번 변경 목표는 다음과 같다.├── Taster│ ├── Preview Content│ │ └── PreviewContainer.swift│ ├── Resource│ └── Source│ ├── Model│
swift-library.tistory.com
[Project-Taster] SwiftData 마이그레이션
🤔 문제 상황가장 먼저 수정해야할 것은 모델이라고 느꼈다. 우선 모델이 중복되는 프로퍼티가 너무 많다고 느꼈고, 각 Type이나 Flavor, Color의 경우 저장하는 형식이 너무 비효율적이라고 생각했
swift-library.tistory.com
[Project-Taster] 모델 수정 (SwiftData)
📝 공식 문서1. Defining data relationships with enumerations and model classes Defining data relationships with enumerations and model classes | Apple Developer DocumentationCreate relationships for static and dynamic data stored in your app.develop
swift-library.tistory.com
아래같이 프로토콜을 도입하고, 그 프로토콜에 따른 뷰를 만들어서 조금 더 뷰를 조립하는 방식으로 작성하고 싶었다.
extension SchemaV2 {
@Model final class WineTastingNote: Notable, Alcoholable, Lookable, Smellable, Tastable, Grapable { ... }
@Model final class CoffeeTastingNote: Notable, Smellable, Tastable { ... }
@Model final class WhiskeyTastingNote: Notable, Alcoholable, Lookable, Smellable, Tastable, Finishable { ... }
@Model final class CocktailTastingNote: Notable, Alcoholable, Tastable, Ingredientable { ... }
}
그래서 SchemaV1과 SchemaV2를 만들었고, 데이터 구조 변경을 위한 마이그레이션을 구현하고, 이것을 실기기, 테스트 코드도 만들어서 테스트를 했다!!!
문제없이 되는 것을 확인하고, 배포를 했는데...
💥 앱 크래시 발생
결론으로는 앱 크래시가 발생했다... 자그마치 83건... 하지만 앱 크래시에 대비를 하지 못한 상황이기 때문에 나는 당황할 수밖에 없었다. 도대체 어디에서 크래시가 나는 거지?
Window → Organizer에서 확인해 보니 어느 정도 확인은 되었다. 앱 진입시점부터 문제가 발생하는 것 같다.
놀랐던 건 이번 마이그레이션 전에도 앱 크래시가 발생했다는 점인데... 이전 버전 아카이브가 없어서 그런지 확인이 불가했다.
😭 해결 과정과 회고...
당연하게도 앱이 안 열린다는 리뷰가 몇 개 달렸는데, 앱이 열리지 않아 삭제하고 다시 설치했더니 노트 내용들이 다 날아갔다는 말을 듣고 정말... 죄송했다.
처음에는 배포버전을 18.0으로 올리는 바람에 발생한 문제라고 생각해 버전을 내리고 재배포했지만, 크래시가 발생하는 것을 보면서 마이그레이션 자체에 뭔가 문제가 있다는 것을 알게 되었다. 분명 실기기로 몇 번을 빌드하면서 잘 옮겨가는 것을 확인했는데, 내가 놓친 부분이 발생한 것 같다. 이 상황이 풀기 제일 어려운 상황인 것 같다. 내 기기에서는 문제가 없지만 다른 기기에서는 문제가 발생한다는 것이...
우선 SwiftData의 마이그레이션 자체가 지금은 도입 단계이다 보니 충분한 테스트와 검증 과정을 거쳤어야 했는데, 된다는 것만 생각하고 간단한 테스트만 작성해서 앱을 배포했다는 것이 너무 큰 실수였다. 🥹
📀 데이터 원격 저장소, 백업의 중요성
이번 기회로 알게 된 것은 나의 무능함과... 데이터 원격 저장소 및 백업의 중요성이다. 앱을 삭제하게 되면 데이터 자체가 모조리 날아간다. 또한 이번처럼 앱 크래시가 발생할 경우 유저의 데이터를 보장할 수 있는 방법을 마련해야 한다. 이런 데이터 하나하나가 얼마나 소중한지 알게 되었다...
🧪 테스트, 기능 보장의 중요성
두 번째는 테스트 및 기능 보장의 중요성이다. 앱에 어떠한 변경, 리팩토링이 있을 경우 앱의 기존 기능이 보장되어야 한다는 점과 실기기로 빌드해 보면서 테스트하는 것에는 구멍이 발생할 수밖에 없다는 것이다. 실제로 테스트 코드를 작성하면서 기존 기능을 보장하는 방법을 고민해봐야 한다는 것을 깨달았다.
⛑️ 지식, 안정성의 중요성
세 번째는 지식, 안정성의 중요성이다. 나는 마이그레이션 시 아래의 MigrationStage를 활용했는데, 이것이 대략적으로 어떻게 이루어져 있는지 주의해야 하는 것이 무엇인지에 대한 사전 지식 없이 도입했고, 그냥 된다는 것 자체에 의미를 둔 것 같다.
/// Describes a migration between two versions of the same schema.
@available(swift 5.9)
@available(macOS 14, iOS 17, tvOS 17, watchOS 10, *)
public enum MigrationStage {
case lightweight(fromVersion: any VersionedSchema.Type, toVersion: any VersionedSchema.Type)
case custom(fromVersion: any VersionedSchema.Type, toVersion: any VersionedSchema.Type, willMigrate: ((_ context: ModelContext) throws -> Void)?, didMigrate: ((_ context: ModelContext) throws -> Void)?)
}
심지어 iOS 17 버전부터 지원되는 기능이기 때문에 기존 문서, 구글링에 의존해야 하는 신입개발자 수준에서는 정보가 부족하다는 것이 정말 위험할 수 있구나라는 것도 깨닫게 되었다. (다양한 시행착오를 내가 직접 겪어야 한다)
물론 개인적으로 연습하는 프로젝트나 학습을 위한 프로젝트에서는 새로운 기술을 학습하고 사용하는 것은 좋지만, 실제 서비스는 보다 안정성을 중요시하면서 내가 커버 가능한 부분까지 파악하고, 그 기술로 구현해 내는 것이 중요하다고 생각했다.
🔨 개선 사항
🌐 원격저장소 만들기
유저 데이터를 백업할 수 있도록 원격 저장소를 만들 계획이다. 다만 이 부분에서 나는 각 노트별로 썸네일 이미지를 가지고 있는데, 용량이 좀 있기 때문에 이 부분을 어떻게 처리해야 할지 고민이다.
👷 SwiftData 사용 최소화
이미 앱에서 SwiftData의 구조를 사용하고 있기 때문에 전체를 들어낼 순 없지만 기존의 데이터를 원격 저장소로 올리고, 캐싱의 의미로 로컬 저장소를 활용할 계획이다. SwiftData에 너무 의존하는 앱이 된 것 같아 조금 덜어낼 예정이다. 앱의 Entity는 그 어느 곳에도 의존성이 없게 만드는 것이 좋을 것 같다. (이래서 Repository Layer가 필요한지도...)
🚑 크래시 분석 도구 도입
Crashlytics와 같은 도구들을 앱에 도입해서 조금더 디테일한 크래시를 분석해보고 싶다. 마침 Firebase에서 Google Analytics도 사용 가능하고 크래시 분석도 가능하니... 실제 서비스에서는 무조건 이런 시스템이 필요하다고 느꼈다.
🧑🔬 테스트, CI/CD 도입
앱의 기능을 보장하기 위해서 실제 빌드로 테스트해보는 것 이외에도 테스트를 좀더 다양하게 만들어야 한다는 것을 깨달았다. 어떠한 테스트를 넣을 수 있을지도 같이 고민해봐야 겠다. 테스트와 연결해서 자동 테스트, 자동 배포 또한 도입해보고 싶다.
🙇🏻 마지막으로...
우선 네부캠도 하고 있고, 취준도 하고 있기 때문에 이 작업을 최우선순위로 올려서 작업하진 않겠지만... 틈나는 대로 꾸준히 해서 최대한 빠르게 개선해 볼 예정이다.
우선 이 앱을 믿고 사용해 줬는데 크래시가 난 분들에게 정말 죄송한 마음뿐이다...🥹
'→ Taster' 카테고리의 다른 글
[Project-Taster] 모델 수정 (SwiftData) (3) | 2024.11.01 |
---|---|
[Project-Taster] SwiftData 마이그레이션 (0) | 2024.10.20 |
[Project-Taster] 기본 컴포넌트 적용 및 아키텍처 변경 (0) | 2024.10.13 |
[Project-Taster] 앱을 고도화 시켜보자!! (1) | 2024.10.06 |
[Project-Taster] 버전 업 - 폰트 적용 및 중복 이미지 코드화 (0) | 2024.08.13 |