Conversation
- 6개 Feature(Bookmark, Detail, Search, Subscribe, MyPage, Launch)에서 미사용 Core 의존성 제거 - SDWebImageSwiftUI, ComposableArchitecture 외부 의존성 완전 제거 - SwipeBackHandler를 Shared → DesignSystem으로 이동 (UI 유틸리티 적절한 레이어 배치) - AppFlowCoordinatorView에 import DesignSystem 추가 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 9개 Feature에 Interface 모듈 추가 (Factory protocol 정의) - 각 Feature에 ViewFactoryImpl 구현체 추가 - AppCoordinator가 구현체 대신 Interface(protocol)만 의존하도록 전환 - NewDokTabView를 Factory 기반으로 리팩토링 - AppDIContainer에서 Feature import 제거 (Domain/Data/Core만 유지) - App 모듈에 CompositionRoot 추가 (Factory 조립 담당) - Feature 변경 시 AppCoordinator 재컴파일 불필요 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Feature-specific UseCase 구현체 7개를 Domain → Feature로 이동 - DefaultHomeBusinessUseCase, FetchHomeDataUseCaseImpl → Home - LoginUseCaseImpl, SignupUseCaseImpl → Auth - ArticleDetailUseCaseImpl → Detail - ProfileUseCaseImpl → MyPage - SearchUseCaseImpl → Search - UseCase Protocol은 Domain에 유지 (공유 계약) - AppDIContainer에서 feature-specific UseCase DI 등록 제거 - CompositionRoot에서 UseCase를 직접 생성하도록 변경 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request undertakes a significant architectural refactoring aimed at enhancing modularity, testability, and maintainability of the application. It establishes a robust dependency injection pattern using Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request refactors the application's dependency injection and module structure. It introduces a new CompositionRoot for centralizing view model and use case creation using Swinject, and defines *ViewFactory protocols and implementations for each feature to decouple the AppCoordinator from concrete view implementations. The AppCoordinator now receives these factories as dependencies. Dependencies on ComposableArchitecture and SDWebImage were removed. Review comments highlight that force unwrapping of resolved dependencies in CompositionRoot.swift could lead to runtime crashes and suggest using safe unwrapping. Additionally, it is recommended that the makeTabView function in AppCoordinator should return AnyView for consistency with other factory methods and for type erasure.
| }, | ||
| loginViewModelProvider: { | ||
| let userUseCase = container.resolve(UserUseCase.self)! | ||
| let loginUseCase = LoginUseCaseImpl(userUseCase: userUseCase) |
There was a problem hiding this comment.
Force unwrapping (!) resolved dependencies can lead to runtime crashes if the dependency is not registered in the Swinject container. Consider using guard let or if let to safely unwrap, or provide a default value/error handling mechanism.
| let loginUseCase = LoginUseCaseImpl(userUseCase: userUseCase) | |
| let userUseCase = container.resolve(UserUseCase.self)! |
| loginViewModelProvider: { | ||
| let userUseCase = container.resolve(UserUseCase.self)! | ||
| let loginUseCase = LoginUseCaseImpl(userUseCase: userUseCase) | ||
| return LoginViewModel(loginUseCase: loginUseCase) |
There was a problem hiding this comment.
Force unwrapping (!) resolved dependencies can lead to runtime crashes if the dependency is not registered in the Swinject container. Consider using guard let or if let to safely unwrap, or provide a default value/error handling mechanism.
| return LoginViewModel(loginUseCase: loginUseCase) | |
| let loginUseCase = LoginUseCaseImpl(userUseCase: userUseCase) |
| @MainActor func makeTabView(selectedTab: NewDokTab? = nil, exploreDay: Int? = nil, exploreSelectedTab: Int? = nil) -> some View { | ||
| NewDokTabView( | ||
| homeFactory: homeFactory, | ||
| exploreFactory: exploreFactory, | ||
| subscribeFactory: subscribeFactory, | ||
| bookmarkFactory: bookmarkFactory, | ||
| mypageFactory: mypageFactory, | ||
| exploreIntent: exploreIntent, | ||
| selectedTab: selectedTab, | ||
| exploreDay: exploreDay, | ||
| exploreSelectedTab: exploreSelectedTab | ||
| ).environmentObject(router) |
There was a problem hiding this comment.
The makeTabView function returns some View, while other factory methods in AppCoordinator return AnyView. For consistency and to ensure type erasure if needed, consider making makeTabView also return AnyView.
| @MainActor func makeTabView(selectedTab: NewDokTab? = nil, exploreDay: Int? = nil, exploreSelectedTab: Int? = nil) -> some View { | |
| NewDokTabView( | |
| homeFactory: homeFactory, | |
| exploreFactory: exploreFactory, | |
| subscribeFactory: subscribeFactory, | |
| bookmarkFactory: bookmarkFactory, | |
| mypageFactory: mypageFactory, | |
| exploreIntent: exploreIntent, | |
| selectedTab: selectedTab, | |
| exploreDay: exploreDay, | |
| exploreSelectedTab: exploreSelectedTab | |
| ).environmentObject(router) | |
| @MainActor func makeTabView(selectedTab: NewDokTab? = nil, exploreDay: Int? = nil, exploreSelectedTab: Int? = nil) -> AnyView { | |
| let tabView = NewDokTabView( | |
| homeFactory: homeFactory, | |
| exploreFactory: exploreFactory, | |
| subscribeFactory: subscribeFactory, | |
| bookmarkFactory: bookmarkFactory, | |
| mypageFactory: mypageFactory, | |
| exploreIntent: exploreIntent, | |
| selectedTab: selectedTab, | |
| exploreDay: exploreDay, | |
| exploreSelectedTab: exploreSelectedTab | |
| ).environmentObject(router) | |
| return AnyView(tabView) | |
| } |
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- SwipeBackHandler: interactiveContentPopGestureRecognizer를 #if compiler(>=6.2)로 감싸 Xcode 16 CI에서도 빌드되도록 수정 - FetchHomeDataUseCaseImpl: final class + @unchecked Sendable로 actor 전달 시 data race 경고 해결 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
No description provided.