-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DIContainer 구현 & MHError 정의 #69
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM⭐️
let key = String(describing: type) | ||
guard let object = objects[key] as? T else { | ||
MHLogger.error("\(#function): \(key)에 해당하는 object 없음") | ||
throw MHError.DIContainerResolveFailure(key: key) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fatalError를 쓰지 말아봅시당 〰️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 🐐
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 💥
#️⃣ 연관된 이슈
⏰ 작업 시간
📝 작업 내용
📒 리뷰 노트
useCase = DIContainer.shared.resolve(~~)
를 할 거기 때문에,viewModel을 생성하는 쪽에서 do-catch로 에러처리 해줘야 합니다 !
문제 상황
현재 상황에서 DIContainer를 도입하는 것이 적절한지에 대해 논의가 필요했다.
의존성 주입을 누가 해줄 것인지, 모듈화되어 있는 구조에서 어떻게 의존성을 주입할 것인지 결정이 필요함
문제 해결
DIContainer 도입 계기
클린 아키텍처가 적용을 함에 따라 아래와 같이 뷰컨트롤러 하나를 띄우더라도 viewModel부터 useCase, Repository를 다 만들어주고 최종적으로 viewModel을 뷰컨트롤러에 넣어주면서 띄워준다.
그러나, 모듈화가 되어있는 우리 프로젝트의 경우 Presentation 레이어에서
let issueRepository = IssuesRepository()
와 같은 코드는 작성할 수 없다.위 코드와 같이 작성하려면
import MHData
를 해주어야 하는데, 그러면 Presentation 모듈이 Data 모듈을 의존하게 되므로 클린 아키텍처가 깨지게 된다.따라서 DIContainer를 도입하여 SceneDelegate에서 미리 의존성들을 주입해두고 Presentation 계층에서 꺼내 쓰기로 결정하였다.
도입 과정
Swinject를 기반으로한 DIContainer를 모방하기로 했다.
싱글톤 DIContainer가 [프로토콜.Type: Any]를 통해 프로토콜과 구현체를 키밸류로 갖고 있는다.
구현하는 과정에서 두 가지 의문사항이 생겼다.
1. DIContainer에 ViewModel을 저장할 필요가 있나 ?
우리의 ViewModel은 정보를 유지할 필요도, 해당 화면을 조작하다가 닫을 경우 이전 정보를 항상 유지할 필요도 없으므로 계속 DIContainer가 갖고 있을 필요가 없음
2. ViewModel을 만들 때 생성자 파라미터로 UseCase를 받아야 하나 ?
우리 프로젝트는 Coordinator가 없으므로 화면 전환이 일어나는 의존성 주입이 보통 아래와 같은 코드에서 발생한다.
이때 useCase를 뷰컨트롤러에서 DIContainer로부터 빼오는데,
이렇게 되면 viewController가 viewModel만 알면 되는데 useCase까지 알게되는 셈이다.
viewController에 useCase 의존성까지 둘 필요가 없으므로 ViewModel의 생성자가 동작하는 시점에 DIContainer에서 직접 꺼내오기로 결정했다.
3. DIContainer Resolve 실패 시 FatalError vs Throw vs Optional
1. 옵셔널 반환 (T?)
장점
단점
2. 에러 던지기 (throws)
장점
단점
3. fatalError 사용
장점
단점
3번에 대한 정리 및 결론
에러를 던지는 것으로 결정
이유
아래와 같이 사용할 수 있음 !
결론
클린 아키텍처를 유지하기 위해, Presentation 계층에서 Data 계층의 의존성을 직접 생성하지 않고 DIContainer를 통해 해결함
ViewModel은 DIContainer에 저장하지 않고, 생성자에서 필요한 UseCase를 DIContainer로부터 직접 가져오도록 처리
throws를 채택하여 의존성 주입 실패 시 명시적인 에러 처리를 강제하고, 디버깅과 유지보수를 용이하게 함
앱 안정성을 높이고 의존성 관리와 코드의 분리도를 개선하며, 클린 아키텍처의 원칙을 유지
참조 링크