최근 사이드프로젝트를 진행하고 찾아보며 MVP(최소 기능 구현)에 대한 요구사항이 많은 것을 확인했다.
사실 처음 MVP도 아키텍처 구조인줄 알았지만, 사용자 요구사항을 최대한 빨리 구현하는 것임을 알았다.
최소 기능 구현이된 프로젝트를 중간에 맡게되며, MVC 구조를 가지고 있는 프로젝트를 처음 진행하며,
음? 내가 쓰던 viewmodel이랑 controller의 차이가 거의 없네? 라는 생각을 하고
여지껏 MVVM을 잘못 알고 쓰고있었나?? 라는 생각을 들어 찾아보게 되었다.
- MVC란?
우선 MVC는 (Model - View - Controller) 구조로 Controller가 사용자 입력을 받아 로직을 처리하고
직접 View를 업데이트 한다.
- Model: 비즈니스 로직, 데이터 모델
- View: 사용자 UI (버튼, 텍스트 등)
- Controller: 사용자의 입력을 받아서 로직을 처리하고, View를 직접 업데이트함
사용자 입력 → Controller → Model 업데이트 → Controller가 View에 반영
class LoginController {
void onLoginPressed(BuildContext context) async {
final result = await loginApi();
if (result.success) {
Navigator.push(...); // View 직접 조작
}
}
}
- MVVM이란?
MVVM은 (Model-View-Viewmodel)구조로 View는 ViewModel을 구독하여 상태 변화를 인지한다.
구독이란 말이 좀 두리뭉실 할 수 있는데,
실제로는 ViewModel이 상태를 관리하고, View는 그 상태를 watch/observe하면서 변화에 반응하는 구조다.
즉, 데이터 변화가 발생했을 때 ViewModel이 이를 감지하고 상태를 업데이트하면, View는 그 변경을 감지해 화면을 자동으로 갱신한다. View들 간에 직접 데이터를 주고받는 게 아니라, ViewModel을 통해 상태를 중앙에서 관리하고 전달받는 방식이라고 이해하면 된다.
- Model: 비즈니스 로직, 데이터 처리
- View: UI, 사용자 인터페이스
- ViewModel: View에 보여줄 상태를 가공해서 전달. View는 ViewModel을 구독함
사용자 입력 → View → ViewModel 호출 → Model 업데이트 → ViewModel이 상태 변경 → View가 자동 반영
ex) Flutter에서 Riverpod을 사용한 Viewmodel 구현
// 로그인 상태를 관리하는 Provider 정의
// View는 이 provider를 watch/구독해서 상태에 따라 UI를 바꾼다
final loginProvider = StateNotifierProvider<LoginViewModel, LoginState>(
(ref) => LoginViewModel(),
);
// ViewModel: 상태(state)를 관리하는 클래스
// StateNotifier를 상속받고, 상태 타입은 LoginState
class LoginViewModel extends StateNotifier<LoginState> {
// 초기 상태를 설정 (ex: 아무 일도 안 일어난 상태)
LoginViewModel() : super(LoginState.initial());
// 로그인 로직 실행
Future<void> login(String id, String pw) async {
// 상태를 로딩으로 변경 → View에서는 로딩 UI 보여줌
state = LoginState.loading();
// API 호출 (비동기)
final result = await loginApi(id, pw);
// 결과에 따라 상태를 성공 or 실패로 변경
state = result.success
? LoginState.success()
: LoginState.error("로그인 실패");
}
}
// UI
ref.watch(loginProvider).when( // 상태 구독하고, 상태에 따른 UI를 보여줌
data: (state) => showSuccessUI(), //성공 시에 화면
loading: () => showLoading(), // 로딩 중에 화면
error: (e, _) => showErrorUI(e), //에러 발생 시에 화면
);
- 두 아키텍처 MVC와 MVVM의 가장 큰 차이
MVC에서는 Controller가 View를 직접 제어하고, MVVM에서는 View가 ViewModel을 통해 스스로 업데이트
즉 남이 바꿔주냐 내가 스스로 보고 바꾸냐의 차이!! 따라서, 결합도의 차이가 생김.
- 정리
개발 초기에는 단순한게 결합도가 낮은 Viewmodel이 좋은거 Controller는 유지보수가 안좋다니까 안좋은거! 라고 단순히 생각했다. 그러나 아키텍처는 상황에 따라, 앱 규모에 따라 선택하는 문제일 수도 있겠다는 생각을 하고 아키텍처에 관해 추가적으로 공부가 필요하다고 느낀다.