Hỏi & Đáp
디자인패턴 질문
안녕하세요 지훈님 ㅎㅎ MVC "요청 받는 것, 데이터 처리 및 CRUD, 화면에 표시하는 것을 구분" -> 이건 Spring MVC(Model 2) 설명입니다. 사실 MVC는 세 갈래인데요 — Smalltalk MVC(V가 M을 구독) / Model 2(Spring·Rails, 구독 없음) / Cocoa MVC(Controller가 M·V 중재). 이 셋이 이름만 같고 다른 물건입니다. Spring MVC엔 "Model이 변하면 View가 갱신된다"가 아예 없습니다. 상태 변화에 반응할 화면 자체가 없으니까요. "M과 V가 서로 직접 참조할 수 있는 구조" -> 맞습니다 단, Smalltalk MVC 한정입니다. Cocoa MVC는 V가 M을 직접 참조 안 합니다. class TodoView { constructor(model) { this.model = model; // ← View가 Model을 안다 model.subscribe(() => this.render()); } render() { const left = this.model.items.filter(i => !i.done).length; // 도메인 규칙이 뷰로 샘 } } "단위 테스트도 어려워짐" 정확합니다. 저 filter 한 줄 때문에 뷰를 띄워야만 테스트 가능해집니다. "컨트롤러 안에서 다 다루니 점점 커짐" 문제 자체는 실재합니다. 다만 이건 Cocoa MVC에서 터지는 현상이고, iOS에서는 Massive View Controller 라고 부릅니다. MVP "M과 V가 서로 직접 참조할 수 없게 만듦" -> 맞습니다. View를 인터페이스로 추상화해서 진행한다고 보면 됩니다. interface TodoView { fun showTodos(items: List ) fun showLoading(); fun hideLoading(); fun showError(msg: String) } class TodoPresenter(private val view: TodoView, private val repo: TodoRepo) { fun onSubmit(text: String) { view.showLoading() repo.add(text) view.showTodos(repo.all()) // 갱신 view.hideLoading() } } 백엔드 예시로는 헥사고날의 Port/Adapter 그 자체라고 보시면 됩니다. Activity가 Adapter, 테스트할 땐 FakeView 주입 = Mock Repository 주입. "MVP에서도 비대해지는 문제는 해결 어려움" 정확히는 MVP의 비대화는 "다 떠안아서"가 아니라 갱신을 일일이 명령해야 해서입니다. "화면 상태" 하나 늘 때마다 view.xxx() 메서드가 늘어납니다. MVVM "그래서 등장한 것이 MVVM" -> 아닙니다. MVVM은 MVP를 고치려고 나온 게 아닙니다. 2005년 MS의 John Gossman이 만들었고, 이유는 WPF에 이미 강력한 선언형 바인딩 엔진이 있었기 때문입니다. 기술이 먼저 있었고 패턴이 따라온 것이지, 순차 진화가 아닙니다. "데이터 바인딩으로 뷰가 자동 업데이트, 코드가 줄어듦" -> 정확합니다. class TodoViewModel(private val repo: TodoRepository) : ViewModel() { private val _uiState = MutableStateFlow(TodoUiState()) val uiState = _uiState.asStateFlow() // ← View 타입이 등장조차 안 함 fun add(text: String) = viewModelScope.launch { _uiState.update { it.copy(isLoading = true) } runCatching { repo.add(text) } .onSuccess { _uiState.update { s -> s.copy(items = repo.all(), isLoading = false) } } .onFailure { e -> _uiState.update { s -> s.copy(error = e.message, isLoading = false) } } } } @Composable fun TodoScreen(vm: TodoViewModel) { val state by vm.uiState.collectAsStateWithLifecycle() if (state.isLoading) CircularProgressIndicator() Text("남은 일: ${state.items.count { !it.done }}") } MVP는 Presenter가 View를 알았지만, MVVM은 ViewModel이 View를 아예 모릅니다. 상태만 노출하고 뷰가 알아서 구독합니다. "'컨트롤러 비대화'와 '직접 참조' 두 가지를 모두 잡음" -> 절반만 맞습니다. 직접 참조 → 맞습니다. 비대화 → 안 잡힙니다. MVVM 써도 ViewModel은 똑같이 뚱뚱해집니다. 비대화의 근본 해법은 패턴 교체가 아니라 계층 분리(Service·UseCase)입니다. "단점으로는.. 그냥 구조가 복잡해졌다?" -> 구체적으로 얘기하는 게 중요한데요. 바인딩이 암묵적 의존이라 추적이 안 됩니다. 값이 왜 안 바뀌는지 콜스택을 못 따라가고, 불필요한 리컴포지션/리렌더 성능 이슈가 생기는 단점이 있습니다. 반면 MVP는 view.showLoading() 이 코드에 박혀 있어 눈으로 따라갈 수 있다고 보면 됩니다. 또 질문 있으시면 언제든지 질문 부탁드립니다. 좋은 수강평과 별점 5점은 제게 큰 힘이 됩니다. :) 감사합니다. 강사 큰돌 올림.
- Lượt thích
- 0
- Số bình luận
- 2
- Lượt xem
- 27

