[CS] MVC 패턴이란?

이지연·2025년 6월 23일

웹 CS (web CS)

목록 보기
3/16
post-thumbnail

개요

프로그래밍을 하다 보면 'MVC 패턴'이라는 말을 자주 듣게 된다. 특히 백엔드 개발이나 웹 애플리케이션의 구조를 설계할 때는 거의 기본처럼 여겨지는 개념이다. 하지만 처음 접하는 입장에서는 "MVC가 도대체 뭘 의미하는 건지", "어디서부터 어떻게 적용해야 할지" 막막하게 느껴질 수 있다.

최근에는 React나 Vue처럼 컴포넌트 기반의 UI 프레임워크를 먼저 접하는 개발자도 많아, 전통적인 MVC 패턴이 다소 생소할 수 있다. 하지만 여전히 많은 백엔드 프레임워크(Django, Spring, Laravel 등)에서 MVC 구조를 기반으로 설계하고 있고, 프론트엔드에서도 상태관리나 구조적 설계를 고민하다 보면 결국 ‘역할 분리’라는 주제에 도달하게 된다.

이번 글에서는 MVC가 무엇이고, 왜 중요한지, 그리고 실전에서는 어떻게 적용되는지 차근차근 정리해보려 한다. 단순한 이론 설명이 아니라 실전 예시를 통해 MVC 패턴의 핵심 원리와 장단점을 함께 살펴볼 예정이다.


MVC란?

MVC는 Model-View-Controller의 약자로, 소프트웨어 아키텍처 패턴 중 하나다. 애플리케이션을 세 가지 주요 역할로 나누어 설계함으로써 역할 분리를 극대화하는 구조다.

이 패턴은 1970년대에 처음 제안된 이래로 지금까지도 다양한 환경에서 널리 사용되고 있다. 특히 서버 사이드 웹 프레임워크(Spring, Rails, Django 등)나 클라이언트 기반 프레임워크(Vue, Angular 등)에서도 형태는 다르지만 MVC의 철학은 여전히 적용되고 있다.


각 구성요소 설명

1. Model

Model은 애플리케이션의 핵심 데이터와 비즈니스 로직을 담당하는 부분이다. 데이터베이스와 직접적으로 통신하거나 데이터를 가공하는 작업이 이루어진다.

예시)

  • 게시판 시스템에서의 게시글, 사용자, 댓글 등
  • 상품 정보를 가져오거나 저장하는 기능

2. View

View는 사용자에게 보여지는 화면(UI)을 담당한다. 템플릿 렌더링, HTML, CSS, JS 등을 통해 시각적 요소를 구성하며, Model의 데이터를 기반으로 표현만 담당한다.

예시)

  • 목록 페이지, 상세 페이지의 화면 구성
  • 사용자 입력을 위한 폼(Form) 제공

3. Controller

Controller는 사용자의 입력을 받아서 처리하고, 알맞은 Model과 View를 연결하는 역할을 한다. 사용자의 요청 흐름을 제어하며 로직의 흐름을 조율한다.

예시)

  • 사용자가 글을 작성하면 Controller가 해당 요청을 받아 Model에 저장하고 View를 갱신
  • 특정 URL 요청 시 적절한 데이터를 가져와서 화면에 전달

이 세 가지 구성 요소를 분리함으로써 애플리케이션의 구조가 명확해지고, 개발자 간 협업이나 유지보수 시 큰 이점을 얻게 된다.


왜 MVC를 사용하는가?

개발 초기에는 모든 로직을 하나의 파일이나 함수 안에 작성하는 경우가 많다. 하지만 프로젝트 규모가 커지고 팀 단위의 협업이 이뤄지기 시작하면, 코드의 복잡도는 급격히 증가하고 유지보수가 어려워진다.

MVC는 이러한 상황에서 관심사 분리(Separation of Concerns)를 통해 복잡도를 낮추고, 유지보수성과 확장성을 높여준다.


장점

1. 역할 분리로 유지보수 용이

Model, View, Controller 각각이 독립적으로 관리되기 때문에 특정 기능을 수정할 때 다른 부분에 미치는 영향이 적다.

2. 협업에 유리함

역할이 명확하게 분리되어 있어 디자이너, 프론트엔드 개발자, 백엔드 개발자가 동시에 작업하기 용이하다. 예를 들어, 한 명이 View를 수정하는 동안 다른 한 명은 Model을 개선할 수 있다.

3. 재사용성 향상

View를 바꿔도 Model은 그대로 재사용할 수 있고, 다양한 형태의 View에서도 동일한 Model을 공유할 수 있다.

4. 테스트 편의성

각 레이어가 독립적이기 때문에 단위 테스트(unit test) 작성이 쉬워지고, 테스트 대상도 명확해진다.


단점

1. 구조가 과할 수 있음

작은 프로젝트에서는 굳이 Controller, Model, View를 나눌 필요 없이 더 단순한 구조가 오히려 효과적일 수 있다.

2. Controller가 비대해지는 문제

MVC를 잘못 설계할 경우, Controller에 너무 많은 책임이 집중되어 오히려 유지보수가 어려워질 수 있다. 이를 해결하기 위해서는 Controller의 역할을 분리해주는 추가적인 구조(예: Service Layer)가 필요할 수 있다.


결론적으로 MVC는 대규모 애플리케이션의 구조적 문제를 해결하기 위한 강력한 도구이지만, 무조건적인 적용보다는 프로젝트의 성격에 맞게 적절히 활용하는 것이 중요하다.


실전 예시로 이해해보기

이론만으로 MVC 패턴을 이해하기는 쉽지 않다. 그래서 이번에는 간단한 게시판 예제를 통해 MVC 구조가 어떻게 적용되는지를 살펴보자.


기능 시나리오: 게시글 목록 페이지

  • 사용자가 /posts 주소에 접근하면, 전체 게시글 목록이 화면에 표시된다.
  • 이 기능은 아래처럼 MVC 구성 요소로 나눌 수 있다.

1. Model

Model은 게시글 데이터를 다루는 부분이다. 예를 들어 데이터베이스에서 게시글을 조회하거나 생성, 삭제 등의 로직이 이쪽에 들어간다.

// models/PostModel.ts
export class PostModel {
  static async findAll() {
    return db.query("SELECT * FROM posts ORDER BY created_at DESC");
  }
}

2. View

View는 사용자가 보는 화면이다. HTML 혹은 템플릿 파일로 구성되어 있으며, 데이터를 받아 사용자에게 보여주는 역할을 한다.

<!-- views/postList.ejs -->
<ul>
  <% posts.forEach(post => { %>
    <li><%= post.title %> - <%= post.author %></li>
  <% }); %>
</ul>

3. Controller

Controller는 요청을 받아 필요한 데이터를 가져오고, 그 결과를 View에 전달한다. 사용자의 액션과 전체 로직 흐름을 담당한다.

// controllers/PostController.ts
import { PostModel } from "../models/PostModel";

export const getPostList = async (req, res) => {
  const posts = await PostModel.findAll();
  res.render("postList", { posts });
};

기존 방식과 비교해보기

아래는 MVC를 적용하지 않은 코드 예시다. 모든 로직이 한 파일 안에 있고, 관심사가 분리되지 않아 유지보수가 어렵다.

app.get("/posts", async (req, res) => {
  const posts = await db.query("SELECT * FROM posts");
  res.send(`
    <ul>
      ${posts.map(p => `<li>${p.title}</li>`).join("")}
    </ul>
  `);
});

처음에는 코드 양이 적고 단순해 보일 수 있지만, 기능이 늘어날수록 이 구조는 점점 복잡해지고 관리가 어려워진다. MVC 패턴을 사용하면 각 역할을 분리해 코드의 가독성과 유지보수성을 확보할 수 있다.


MVC vs MVVM vs MVP 간단 비교

소프트웨어 설계 패턴에는 MVC 외에도 여러 가지가 있다. 특히 프론트엔드 프레임워크가 발전하면서 MVVM, MVP 같은 패턴도 많이 사용된다. 각 패턴은 궁극적으로 '역할 분리'라는 공통된 목적을 갖고 있지만, 데이터 흐름View와의 관계에서 차이가 있다.


1. MVC (Model-View-Controller)

  • Model: 데이터와 비즈니스 로직
  • View: 사용자 인터페이스
  • Controller: 사용자의 입력을 처리하고 Model과 View를 연결

View가 Controller를 통해 Model에 접근하고, 그 결과를 View에 반영
전통적인 웹 서버 구조(Spring, Rails, Django 등)에서 많이 사용


2. MVVM (Model-View-ViewModel)

  • Model: 데이터
  • View: UI
  • ViewModel: View와 Model 사이의 중간 계층. 양방향 데이터 바인딩

ViewModel이 View의 상태를 직접 조작하지 않음.
데이터 바인딩으로 View와 ViewModel이 자동으로 연결됨
React + 상태관리 라이브러리(Recoil, Zustand) 또는 Vue 구조와 유사


3. MVP (Model-View-Presenter)

  • Model: 데이터 및 로직
  • View: UI
  • Presenter: View와 Model 사이를 중개하지만, View에 대한 참조를 직접 가지고 있음

View가 Presenter에 이벤트를 위임하고, Presenter가 View를 직접 업데이트함
테스트가 쉬워서 Android 개발에서 많이 사용됨


요약 표

패턴중개 역할View와의 관계사용 예
MVCControllerView가 Controller에 의존전통적 웹 백엔드
MVVMViewModel양방향 바인딩, 간접 연결Vue, React + 상태관리
MVPPresenterView를 직접 참조Android, 일부 데스크탑 앱

결론적으로 어떤 패턴을 선택할지는 프레임워크의 특성과 프로젝트의 구조에 따라 달라진다. 중요한 것은 구조의 일관성과 관심사 분리의 명확성이다.


마치며

MVC 패턴은 오랜 시간 동안 다양한 프로젝트에서 검증되어 온 아키텍처 설계 방식이다. 지금은 다양한 패턴들이 등장했지만, 여전히 역할 분리와 구조화된 사고를 배우는 데 가장 기본이 되는 접근 방식이다.

실제로 프로젝트를 하다 보면 코드는 금방 복잡해지고, 어느 순간부터 어디서 무슨 일을 하는지 파악하기 어려워진다. 이럴 때 MVC 패턴을 도입하면 "어떤 역할은 어디서 처리해야 하는가?" 라는 기준이 생기고, 결과적으로 유지보수나 협업도 훨씬 수월해진다.

중요한 건 특정 패턴을 무조건 따르는 것이 아니라, 패턴의 철학을 이해하고 상황에 맞게 적절히 조합해 쓰는 능력이다. 앞으로 다양한 프레임워크나 프로젝트를 접할 때도 이런 구조적 사고가 큰 도움이 될 것이다.

profile
Eazy하게

2개의 댓글

comment-user-thumbnail
2025년 8월 25일

Eazy하게보는중
전 빵을 먹어서 비대해졋어요

1개의 답글