## Feelin `2024.02 ~ Now` ### ![앱스토어 이미지](https://github.com/user-attachments/assets/6dc8b1a0-6170-4e2a-a1e7-c4bf94207774) - [앱스토어에서 다운 받기](https://apps.apple.com/kr/app/sopt/id6738319829) --- ### 기능 소개 #### <br> <details> <summary> 좋아하는 아티스트를 선택하기(자세히 보기) </summary> <div markdown="1"> <br> > 📮 미션 - <img src="" width=200 /> <img src="" width=200 /> <img src="" width=200 /> <br> > 💪 랭킹 <img src="" width=200 /> <br> </div> </details> <details> <summary> 노트 작성 / 수정 </summary> <div markdown="1"> <br> <img src="" width=200 /> <img src="" width=200 /> <img src="" width=200 /> <br> </div> </details> <details> <summary> 노트 작성 / 수정 </summary> <div markdown="1"> <br> <img src="" width=200 /> <img src="" width=200 /> <img src="" width=200 /> <br> </div> </details> <br> --- ### 📱 App Version | 날짜 | 버전 | |:--|:--| | 24.12 | `v1.0.0` | | 25.01 | `v1.0.1` | | 25.01 | `v1.0.2` | <br> ### 🛠 개발 환경 및 라이브러리 [![swift](https://img.shields.io/badge/swift-5.10-orange)]()[![xcode](https://img.shields.io/badge/Xcode-15.4-blue)]() [![tuist](https://img.shields.io/badge/Tuist-4.17.0-purple)]()[![Kingfisher](https://img.shields.io/badge/Kingfisher-7.12.0-green)]()[![FlexLayout](https://img.shields.io/badge/FlexLayout-2.0.10-yellow)]()[![PinLayout](https://img.shields.io/badge/PinLayout-1.10.5-black)]() <br> ### 🏡 설계 과정 ### 1. 서비스의 본질 파악 #### 기획서 요구사항 분석 > 기획서 및 명세사항이 확정되지 않은 상황에서 개발에 착수 > 그럼에도 다음과 같은 인사이트를 얻게 되었다: - 공통 에러를 처리할 수 있어야 함. - 모든 화면에서 회원 및 비회원 여부를 알 수 있어야 한다. - 모든 화면에서 토큰 만료 여부 파악 및 공통적으로 처리할 수 있어야 한다. - 다양한 화면 전환에 대응할 수 있어야 한다. - Case 1: 회원가입 후 메인화면으로 넘어가는 Navigation 플로우 - Case 2: 비회원 활동 중 로그인이 필요한 Navigation 플로우 - Case 3: 자동 로그인을 통한 메인화면으로 이동하는 Navigation 플로우 - Case 4: 메인화면에서 토큰만료 또는 로그아웃 버튼에 의해 다시 로그인 화면으로 이동하는 Navigation 플로우 - Case 5: 딥링킹을 통해 다양한 화면으로 전환할 수 있어야 한다. - 중복되는 컴포넌트 및 로직이 많을 가능성 - 노트 조회, 수정, 작성, 그리고 삭제 기능 - 음악 플레이 기능 - NoteCell, ArtistCell 소결론: - 화면전환에 용이한 구조로 설계해야 함 - 에러처리를 위한 중앙 관제탑이 필요함 - 개발자 여럿이서 병렬적으로 작업할 수 있는 환경이어야 함 ### 2. 아키텍처 선정 #### Clean Swift를 사용해 볼까? 이유: 그냥. 많이들 사용한다고 하고 한 번 공부해 보고 싶어서.😆 ### Clean Architecture + Coordinator로 넘어간 이유: <img width="1642" alt="스크린샷 2025-01-30 16 50 44" src="https://github.com/user-attachments/assets/e8dedd75-317a-45e9-8a4e-79bd723507b7" /> > 하루종일 고민한 흔적 처음에 CleanSwift를 도입하고자 한 가장 큰 이유는 스터디에 있었다. 하지만 기획서가 업데이트 되고 다양한 네비게이션 플로우를 요구하는 상황에서 CleanSwift를 도입하여 여러 플로우 처리를 해야 할 경우 네비게이션 스택을 관리하는 객체가 따로 없기에 `NotificationCenter`를 활용하거나 `SceneDelegate`에 접근하여 `window`의 `rootViewController`를 바꿔줘야 하는데 다음과 같은 우려되는 부분이 존재: - UIWindow에 다양한 객체가 접근하는 문제 - 유지보수성 용이하지 않다 - SceneDelegate에 접근한다는 것 자체가 하위 모듈에서 상위 모듈에 접근해야 하는데 이는 적합하지 않다고 생각 - 처음 생성한 NavigationController로 화면 전환이 계속 이어지는 게 아니라 rootViewController를 바꿔가며 NavigationController를 관리해야 하는 것은 너무 비효율적이다. - 접근방법 상태 관리 복잡 - 플로우 전환 시 NavigationController를 재생성해야 할 때의 오버헤드 고려 - PopToViewController방식으로 Router에서 특정 VC까지만 pop 하는 방법 또한 다음과 같은 문제 - 휴먼 에러 발생할 가능성(잘못된 VC타입을 주입할 경우 문제 생김) - VC 갯수가 많아질수록 유지보수 ↓↓ #### 중론: CleanSwift 예제 및 관련 글들을 찾아본 결과 Storyboard를 활용하여 앱을 설계하는데에 초점을 맞춘 아키텍처인듯 보임. 이런상황에서 CleanSwift라는 아키텍처를 우리 프로젝트에 적용하게 된다면 프로젝트를 위한 아키텍처가 아닌 아키텍처에 프로젝트를 끼워 맞춘다는 느낌 네비게이션 스택을 관리하려면 Clean Swift관점에서 하위 router가 상위 router를 알아야 하는데 해당 방식은 결국 많이들 얘기하는 Coordinator패턴과 유사하다고 판단 CleanSwift에 Coordinator를 도입하자니 Router의 역할과 겹치게 된다. 따라서 Coordinator를 활용하면서도 테스트에 용이한 CleanArchitecture + MVVM을 활용하기로 결론을 지었다. #### 최종 결론 - Clean Swift에서의 Router와 겹치는 부분을 고려할 때, Coordinator 패턴을 도입하는 것이 앱의 네비게이션 로직을 효과적으로 관리하고, 각 화면의 독립성을 보장하는 데 더 적합하다고 판단. - 이로 인해 앱의 확장성과 유지보수성이 향상될 것이라 기대. - 따라서, 테스트에 용이하며 구조적으로 견고한 Clean Architecture와 MVVM을 기반으로 하는 MVVM-C 아키텍처를 채택하기로 결정. #### 결정 이유 1. **네비게이션의 중앙 집중화**: - Clean Swift 아키텍처에서는 Router가 네비게이션을 담당하지만, 복잡한 플로우를 효과적으로 처리하는 데 한계가 있다고 판단. - 반면, Coordinator는 Parent와 Child 구조를 통해 각 화면 전환을 보다 유연하게 관리할 수 있다고 결론. 2. **상태 관리의 간소화**: - UIWindow의 rootViewController를 변경하는 방식은 상태 관리가 복잡하고, 여러 모듈에서 공통적으로 접근해야 하는 문제가 발생. - Coordinator를 사용하면 각 네비게이션 플로우를 독립적으로 관리할 수 있으며, 필요에 따라 적절한 화면을 활성화할 수 있다고 판단. 3. **테스트 용이성과 유지보수성**: - Clean Swift의 구조는 Storyboard와 강하게 연결되어 프로젝트에 유연성을 제한할 수 있다고 판단. - MVVM-C 구조는 각 ViewModel을 통해 로직을 분리하고, Coordinator를 통해 화면 전환을 처리함으로써 더 깔끔하고 테스트하기 쉬운 코드 구조를 만들 수 있다고 결론. 4. **효율적인 리소스 관리**: - Coordinator 패턴은 네비게이션 컨트롤러를 재생성하는 오버헤드 없이 화면을 관리할 수 있겠다 판단 - 이는 앱의 성능을 최적화하고, 메모리 관리를 개선하는 데 기여하지 않을까 생각 --- #### Modular Architecture **모듈화를 왜 하였는가** - 클린 아키텍처의 각 Layer별 필요한 기능을 모듈 단위로 분리하는 것이 필요(책임 분리) - 상위 Layer와 하위 Layer를 폴더 별로는 구분짓기 어렵지만 모듈화를 진행하면 가능 - 기획에서 확장 가능성을 내포하였기 때문 일단 MVP 단계까지 개발한 뒤 추후 유저 반응을 보고 서비스를 디벨롭 하자는 기획의 얘기를 듣고 해당 프로젝트가 단일성이 아닌 추후 더 고도화 된 앱으로 발전할 가능성을 인지함. 하나의 모듈에 파일이 추후 많아지게 되면 빌드 속도 저하가 예상되었고 이는 생상성 저하로 까지 이어질 가능성을 인지함. 이를 방지하기 위해 모듈화 - 데모앱을 통해 빠른 개발 및 디버깅 ### 그럼 왜 Tuist를 써? - 모듈단위 계층, App의 설정을 코드로 관리할 수 있음 - 파일 계층이 변경되어도 tuist에서 관리하기 때문에 conflict를 방지할 수 있음 - tuist graph를 활용하여 각 모듈간 의존성을 한 눈에 파악하기 쉽다. - build시 모듈간 상호참조 여부를 빠르게 파악할 수 있어서 - makefile로 각 모듈 별로 필요한 파일을 생성할 수 있음 장점, 단점 - Dependency Injection - Coordinator #### Coordinator #### Dependency Injection #### Unit Test