아키텍처 - MVC와 MVVM의 차이

이재원·2024년 10월 8일
0

아키텍처

목록 보기
1/2

MVC와 MVVM의 차이점: UI 업데이트 방식의 핵심

소프트웨어 개발에서 MVC(Model-View-Controller)MVVM(Model-View-ViewModel) 패턴은 UI를 구현할 때 자주 사용되는 디자인 패턴입니다. 두 패턴 모두 유지보수성역할 분리를 목표로 하지만, UI 업데이트 방식에서 중요한 차이가 있습니다. 이 글에서는 MVC와 MVVM의 주요 차이점과, 특히 UI 업데이트수동으로 처리하느냐, 자동으로 처리하느냐의 차이를 중심으로 살펴보겠습니다.

1. MVC 패턴: 수동으로 UI 업데이트

MVC 패턴은 Model, View, Controller로 구성됩니다. ControllerViewModel 사이에서 중재자 역할을 하며, UI 이벤트 처리와 데이터 변경을 모두 책임집니다. Controller는 사용자의 상호작용에 따라 Model을 업데이트하고, 그 결과를 View수동으로 반영해야 합니다.

MVC의 동작 흐름:

  1. 사용자View와 상호작용.
  2. ViewController에게 이벤트를 전달.
  3. ControllerModel의 데이터를 업데이트.
  4. Controller수동으로 View를 갱신.

MVC에서 ViewController는 다음과 같은 역할만 수행하는 것이 이상적입니다.

  1. View의 생명주기(Lifecycle) 관리
    : viewDidLoad(), viewWillAppear(), viewDidAppear() 등의 생명주기 메서드에서 UI를 초기화 및 갱신
  2. UI 요소의 업데이트 및 상태 관리
    : UI 컴포넌트(버튼, 라벨, 테이블 뷰 등)을 적절히 배치하고 변경하는 역할을 수행
  3. 이벤트 처리
    : 버튼 클릭, 제스처, 테이블 뷰 셀 선택 등의 UI 이벤트를 감지하고 처리
  4. ViewModel 또는 다른 계층과의 데이터 바인딩

반대로, ViewController에서 하면 안되는 역할은 다음과 같습니다.

  1. 비지니스 로직을 직접 수행하면 안됩니다
    : 예를 들어, API 요청을 직접 보내고 응답을 처리하는 코드를 뷰 컨트롤러 내부에 작성하면 안 됩니다. 대신, ViewModel 또는 UseCase 같은 별도 계층을 만들어 관리해야 합니다.
  2. 데이터 변환/처리 로직을 직접 수행하면 안됩니다
    : json을 직접 파싱하거나, 날짜 변환가 같은 데이터를 변형하는 로직을 뷰 컨트롤러에서 하면 안 됩니다. 이 경우 Formmater, Model, ViewModel 등의 계층을 활용해야 합니다.
  3. 네트워크 요청을 직접 수행하면 안됩니다
    : Alamofire 또는 URLSession을 직접 호출하지 않고, 네트워크 레이어(Service 또는 Repository)를 만들어서 분리해야 한다.
    : 데이터 가져오기, 캐싱, 데이터 저장 등의 로직도 별도의 계층에서 처리해야 한다.

MVC 예시 코드 (UIKit)

// Model
struct User {
    var name: String
    var age: Int
}

// View (UIView)
class UserView: UIView {
    let nameLabel = UILabel()
    let ageLabel = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)

        nameLabel.translatesAutoresizingMaskIntoConstraints = false
        ageLabel.translatesAutoresizingMaskIntoConstraints = false

        addSubview(nameLabel)
        addSubview(ageLabel)

        // Layout constraints
        NSLayoutConstraint.activate([
            nameLabel.centerXAnchor.constraint(equalTo: centerXAnchor),
            nameLabel.centerYAnchor.constraint(equalTo: centerYAnchor, constant: -20),
            ageLabel.centerXAnchor.constraint(equalTo: centerXAnchor),
            ageLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor, constant: 10)
        ])
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func updateView(with user: User) {
        nameLabel.text = "Name: \\(user.name)"
        ageLabel.text = "Age: \\(user.age)"
    }
}

// Controller (UIViewController)
class UserController: UIViewController {
    private var user: User!
    private var userView: UserView!

    override func viewDidLoad() {
        super.viewDidLoad()

        userView = UserView(frame: view.frame)
        view.addSubview(userView)

        // Model에서 데이터 가져오기
        user = User(name: "Alice", age: 30)

        // View를 수동으로 업데이트
        userView.updateView(with: user)
    }

    // 사용자 데이터를 업데이트하고 다시 View를 갱신하는 함수
    func updateUser(name: String, age: Int) {
        user.name = name
        user.age = age

        // 수동으로 View 업데이트
        userView.updateView(with: user)
    }
}

따라서 ViewController가 UI 및 이벤트 로직 외의 역할을 가지지 않도록 구조를 설계하는 것이 중요합니다. 만약, UI, 네트워크, 데이터 처리 등을 모두 한 곳에서 하면 뷰 컨트롤러의 역할이 과도해지고 유지보수가 어려워집니다.

이러한 경우엔 MVVM, MVP, VIPER 같은 디자인 패턴을 도입하여 역할을 분리해야 합니다. 이 글에서는 MVVM에 대해서만 다뤄 보겠습니다.

2. MVVM 패턴: 데이터 바인딩을 통한 자동 UI 업데이트

MVVM 패턴은 Model, View, ViewModel로 구성되며, 핵심 차이점은 데이터 바인딩을 통해 자동으로 UI가 업데이트된다는 것입니다. ViewModelViewModel 사이에서 UI 상태데이터 처리를 담당하지만, UI 업데이트데이터 바인딩을 통해 자동으로 이루어집니다.

MVVM의 동작 흐름:

  1. ViewViewModel데이터 바인딩을 통해 연결.
  2. ViewModelModel의 데이터를 관리하고 업데이트.
  3. 데이터 바인딩을 통해 View는 자동으로 갱신.

MVVM에서 ViewModel은 View와 Model 사이의 중간 계층으로서 다음과 같은 역할을 수행합니다.

  1. 비지니스 로직 처리

    ViewModel은 View에서 받은 사용자 입력을 기반으로 비지니스 로직을 실행합니다. 예를 들어, 사용자가 버튼을 눌렀을 때 특정 데이터를 가공하거나, 상태를 변경하는 등의 역할을 수행합니다.

  2. 네트워크 요청 수행(Service 계층 호출)

    ViewModel은 네트워크 요청을 수행하지만, 직접 네트워크 요청을 수행하지 않고 Service 계층을 호출하여 데이터를 가져옵니다.

    즉, API 요청을 ViewModel에서 실행하는 것이 아니라 Service 또는 Repository에서 수행하고, ViewModel은 그 결과를 받아 View에 전달하는 역할을 합니다.

    func fetchUserData() {
        userService.fetchUser { [weak self] user in
            DispatchQueue.main.async {
                self?.user = user
            }
        }
    }
  3. 데이터 가공 및 변환

    ViewModel은 View에서 바로 사용할 수 있도록 데이터를 변환하는 역할을 합니다.

    하지만, 데이터 변환이 복잡한 경우 Model에서 처리하는 것이 더 적절합니다.

  4. View와의 데이터 바인딩

    View에서 사용할 데이터를 @Published 또는 ObservableObject 를 통해 바인딩 합니다.

    view는 ViewModel의 데이터를 구독하고, 데이터가 변경되면 UI를 자동으로 업데이트 합니다.

  5. ViewModel은 UI를 직접 업데이트 하지 않음

    UIkit의 ViewController처럼 UI를 직접 견경하는 코드가 포함되면 안 됩니다.

    UI 업데이트는 View에서 ViewModel의 데이터를 구독하여 자동으로 반영하는 방식을 처리해야 합니다.

MVVM에서 ViewModelView에 대해 알 필요가 없고, UI 업데이트가 자동으로 이루어지기 때문에 MVC의 Controller보다 유지보수성이 높습니다. ViewViewModel은 느슨하게 결합되어 있어, UI의 변경 사항이나 데이터 업데이트가 자동으로 처리됩니다.

MVVM 예시 코드 (SwiftUI)

// Model
struct User {
    var name: String
    var age: Int
}

// ViewModel
class UserViewModel: ObservableObject {
    @Published var user: User

    init(user: User) {
        self.user = user
    }

    // ViewModel이 데이터를 업데이트하는 메서드
    func updateUser(name: String, age: Int) {
        user.name = name
        user.age = age
    }
}

// View (SwiftUI View)
struct UserView: View {
    @ObservedObject var viewModel: UserViewModel

    var body: some View {
        VStack {
            Text("Name: \\(viewModel.user.name)")
            Text("Age: \\(viewModel.user.age)")
            Button(action: {
                // ViewModel을 통해 데이터를 업데이트
                viewModel.updateUser(name: "Bob", age: 25)
            }) {
                Text("Update User")
            }
        }
    }
}

// SwiftUI에서 ContentView
struct ContentView: View {
    var body: some View {
        UserView(viewModel: UserViewModel(user: User(name: "Alice", age: 30)))
    }
}

3. MVC와 MVVM의 핵심 차이: 수동 vs 자동 UI 업데이트

MVCMVVM의 가장 큰 차이점은 UI 업데이트 방식을 수동으로 처리하느냐, 자동으로 처리하느냐에 있습니다.

  • MVC: ControllerUI 업데이트수동으로 처리해야 하며, 이는 코드 중복비대해진 Controller를 초래할 수 있습니다. UI 변경 시, Controller에서 명시적으로 View를 갱신해야 합니다.
  • MVVM: ViewModelView 간의 데이터 바인딩을 통해 자동으로 UI가 업데이트됩니다. 개발자는 데이터 상태 관리에만 집중하고, UI 업데이트는 데이터 바인딩 메커니즘이 처리합니다.

4. 왜 데이터 바인딩이 중요한가?

MVVM에서 데이터 바인딩UI 업데이트의 자동화를 가능하게 하는 핵심 요소입니다. 이 자동화 덕분에 ViewViewModel의 상태만 구독하며, UI는 항상 최신 상태를 유지합니다. 반면에 MVCViewController 간의 긴밀한 상호작용이 필요하여, 변화가 있을 때마다 Controller에서 직접 View를 조작해야 합니다.

결국, MVVM에서의 데이터 바인딩의존성을 낮추고, UI 로직을 더 쉽게 유지보수할 수 있게 도와줍니다. MVC에서는 이러한 자동화가 없기 때문에, ViewController가 더 강하게 결합될 수밖에 없습니다.

결론

MVCMVVM의 가장 큰 차이점은 UI 업데이트를 수동으로 처리하느냐, 아니면 데이터 바인딩을 통해 자동으로 처리하느냐입니다. MVCController가 모든 UI 로직과 업데이트를 수동으로 처리하지만, MVVMViewModel데이터 바인딩을 통해 UI 업데이트를 자동화하여 유지보수성을 높이고 의존성을 낮춥니다.

MVVM 패턴을 사용할 때 데이터 바인딩은 필수 요소로, 이를 통해 UI와 비즈니스 로직의 명확한 분리가 가능해집니다. 이러한 자동화된 업데이트 덕분에 복잡한 UI 로직을 더 간결하게 유지할 수 있으며, 대규모 애플리케이션에서 더 나은 아키텍처를 제공합니다.

이미지 출처
https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html
https://velog.io/@kyeun95/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-MVVM-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80


업데이트 기록

  • 25.02.25 -> ViewController와 ViewModel의 역할 추가
profile
20학번 새내기^^(였음..)

0개의 댓글

관련 채용 정보