본문 바로가기

UIKIT

ViewController 내에 init으로 viewModel 할당하는 이유

SearchViewController에 SearchViewViewModel을 init을 통해 주입하는 구조는 의존성 주입(Dependency Injection) 패턴의 대표적인 예입니다. 이 방법은 코드의 재사용성, 테스트 가능성, 유연성을 높이기 위해 많이 사용됩니다.

 

class SearchViewController: UIViewController {
    
    let viewModel: SearchViewViewModel
    
    init(viewModel: SearchViewViewModel) {
        self.viewModel = viewModel
        super.init(nibName: nil, bundle: nil)
    }

 

1. 목적과 이유

a. ViewController와 ViewModel 간의 분리

  • 목적: SearchViewController와 SearchViewViewModel의 책임을 명확히 분리하기 위함입니다.
    • SearchViewViewModel은 데이터를 처리하거나 비즈니스 로직을 담당합니다.
    • SearchViewController는 주로 UI를 관리하며, 사용자 입력을 뷰모델로 전달하고 결과를 UI에 표시합니다.
  • 이유:
    • 뷰컨트롤러는 주로 UI 관리에만 집중하게 하고, 데이터 로직을 뷰모델에 위임하여 코드의 응집도를 높이고 관심사의 분리를 유지할 수 있습니다.

b. 의존성 주입(Dependency Injection)을 통한 유연성

  • 목적: 의존성(여기서는 SearchViewViewModel)을 외부에서 주입하여 유연성과 재사용성을 높이기 위함입니다.
  • 이유:
    • 뷰컨트롤러가 뷰모델을 직접 생성하면, 뷰모델이 고정되어 재사용성이 떨어지고, 테스트하기 어려워집니다.
    • 외부에서 뷰모델을 주입받으면, 필요에 따라 다른 구현체를 전달할 수 있어 더 유연하게 사용할 수 있습니다.

c. 테스트 용이성

  • 목적: 단위 테스트와 UI 테스트를 더 쉽게 작성할 수 있도록 설계합니다.
  • 이유:
    • 뷰모델을 주입받는 구조에서는 테스트용 MockViewModel이나 Stub을 주입하여, 테스트할 때 의존성을 쉽게 교체할 수 있습니다.
    • 예를 들어, SearchViewController의 동작을 테스트할 때 실제 데이터를 가져오는 대신, 테스트용 데이터만 반환하는 MockViewModel을 전달할 수 있습니다.

 

2. 이렇게 해야 하는 상황

a. ViewModel의 독립적인 테스트가 필요한 경우

  • 뷰모델의 로직이 복잡하거나 데이터 흐름이 많다면, 뷰모델을 독립적으로 테스트할 필요가 있습니다.
  • 이 경우, 뷰컨트롤러가 뷰모델을 직접 생성하면 테스트하기 어려워지므로, 외부에서 주입받는 구조가 적합합니다.

b. 다양한 ViewModel을 주입해야 하는 경우

  • 상황에 따라 뷰모델의 구현이 달라질 수 있는 경우:
    • 예를 들어, SearchViewController가 특정 환경에서는 MockSearchViewViewModel을 사용하고, 실제 앱 실행 시에는 SearchViewViewModel을 사용하는 경우.
  • 이처럼 다양한 뷰모델을 동적으로 주입할 필요가 있다면, 의존성 주입 구조를 사용하는 것이 효과적입니다.

c. 유닛 테스트나 UI 테스트를 작성하는 경우

  • 테스트 환경에서는 실제 SearchViewViewModel 대신 가짜 데이터를 반환하는 MockViewModel을 전달할 수 있습니다.
    • 이를 통해 네트워크 요청이나 데이터베이스 호출 없이도 뷰컨트롤러의 동작을 검증할 수 있습니다.

 

3. 만약 init 없이 뷰모델을 직접 생성하면?

a. 강한 결합(Strong Coupling)

  • 뷰컨트롤러 내부에서 SearchViewViewModel을 생성하면, 뷰컨트롤러와 뷰모델이 강하게 결합됩니다.
  • 이렇게 되면 SearchViewController는 항상 특정한 뷰모델만 사용해야 하므로, 테스트나 확장이 어려워집니다.

b. 재사용성 저하

  • 다른 뷰모델을 사용하는 뷰컨트롤러를 만들기 어렵습니다.
  • 예를 들어, 같은 UI를 공유하면서 다른 데이터 로직을 사용하는 뷰모델을 주입하고 싶을 때, 직접 생성하는 구조에서는 이를 구현하기 어렵습니다.

 

결론

SearchViewController가 SearchViewViewModel을 init으로 주입받는 구조는:

  1. 다양한 뷰모델을 쉽게 교체할 수 있어 유연성을 제공합니다.
  2. 검색 대상(유저, 게시글 등)이 바뀌더라도, 뷰모델만 변경하여 기능 확장이 가능합니다.
  3. 재사용성과 유지보수성이 좋아져, 뷰컨트롤러 코드를 수정하지 않고도 다양한 요구사항을 처리할 수 있습니다.

이처럼 상황에 맞는 뷰모델을 쉽게 교체할 수 있는 유연성이 이 설계의 핵심입니다. 😊