2025. 3. 1. 06:23ㆍ코딩 도구/백엔드 개발 (Backend Development)
MVC 패턴: 서블릿과 JSP의 한계를 넘어
이 글에서는 인프런 김영한님의 "스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술"을 수강하고 정리했습니다.
서블릿의 문제점
서블릿을 사용하여 웹 애플리케이션을 개발할 때, HTML을 직접 생성하는 작업이 자바 코드와 뒤섞여서 코드가 복잡하고 유지보수가 어려운 문제가 있었다. 예를 들어, 서블릿에서 문자열로 HTML을 생성하고 출력하는 방식은 가독성이 떨어지고, 작은 수정에도 코드 전체를 수정해야 하는 번거로움이 있었다.
JSP를 사용한 개선
JSP를 도입하면서 HTML을 보다 깔끔하게 작성할 수 있게 되었다. 뷰를 생성하는 HTML 작업은 JSP에서 담당하고, 동적으로 변경이 필요한 부분만 자바 코드를 적용하는 방식으로 개선되었다. 하지만 여전히 몇 가지 문제가 남아 있었다.
JSP의 한계
회원 저장 기능을 구현하는 JSP를 보면, 코드의 상위 절반은 회원을 저장하는 비즈니스 로직이고, 하위 절반은 저장 결과를 HTML로 보여주는 뷰 영역이다. 또한, 회원 목록을 조회하는 JSP에서도 비슷한 문제가 발생한다.
JSP에는 비즈니스 로직, 데이터 조회 코드, 뷰 렌더링 코드가 한 파일에 함께 존재하기 때문에 역할이 분리되지 않아 유지보수가 어렵다. 프로젝트가 커질수록 이러한 문제는 더욱 심각해지며, 수백~수천 줄에 달하는 JSP를 유지보수하는 것은 현실적으로 매우 어렵다.
MVC 패턴의 등장
이러한 문제를 해결하기 위해 MVC(Model-View-Controller) 패턴이 등장했다. 비즈니스 로직은 서블릿과 같은 별도의 계층에서 처리하고, JSP는 HTML을 렌더링하는 일에 집중하도록 설계하는 방식이다.
MVC 패턴 개요
역할 분리의 필요성
하나의 서블릿이나 JSP에서 비즈니스 로직과 뷰 렌더링을 함께 처리하면 너무 많은 역할을 수행하게 되어 유지보수가 어려워진다. 비즈니스 로직을 변경할 때 UI 코드까지 함께 수정해야 하며, UI 변경이 필요할 때도 비즈니스 로직이 포함된 파일을 수정해야 한다. 이는 개발 효율성과 유지보수성을 저하시킨다.
변경의 라이프 사이클 차이
비즈니스 로직 수정과 UI 변경은 서로 다른 시점에 발생할 가능성이 크다. 예를 들어, UI 디자인을 변경해야 하는 경우와 회원 데이터 저장 로직을 변경해야 하는 경우는 서로 독립적인 상황에서 발생할 가능성이 높다. 이러한 변경의 라이프 사이클이 다른 요소를 하나의 코드로 관리하면 유지보수에 어려움이 생긴다.
MVC 패턴의 구조
MVC 패턴은 웹 애플리케이션에서 컨트롤러(Controller), 모델(Model), 뷰(View)의 역할을 분리하여 유지보수를 용이하게 한다.
1. 컨트롤러(Controller)
- HTTP 요청을 받아서 파라미터를 검증하고, 비즈니스 로직을 실행한다.
- 결과 데이터를 조회하여 모델(Model) 에 담는다.
2. 모델(Model)
- 뷰에서 출력할 데이터를 저장하는 역할을 한다.
- 뷰는 비즈니스 로직이나 데이터 접근을 몰라도 되며, 화면 렌더링에만 집중할 수 있다.
3. 뷰(View)
- 모델에 담긴 데이터를 사용하여 HTML을 생성하는 역할을 한다.
서비스 계층의 도입
컨트롤러에 비즈니스 로직을 직접 두는 방식도 가능하지만, 이렇게 하면 컨트롤러가 너무 많은 역할을 담당하게 된다. 따라서 일반적으로 비즈니스 로직은 서비스(Service) 라는 계층을 별도로 만들어 처리한다. 컨트롤러는 서비스 계층을 호출하는 역할만 담당하고, 서비스 계층이 핵심 비즈니스 로직을 담당하는 방식이 유지보수에 유리하다.
MVC 패턴 적용 시 고려 사항
JSP 직접 호출 제한
/WEB-INF 경로 안에 JSP 파일을 배치하면 외부에서 직접 접근할 수 없다. 이는 보안상의 이유와 함께, 항상 컨트롤러를 통해 JSP를 호출하도록 강제하는 역할을 한다.
Redirect vs Forward
- 리다이렉트(Redirect): 클라이언트(웹 브라우저)에 응답이 전달된 후, 클라이언트가 새로운 요청을 보내는 방식이다. 따라서 클라이언트가 요청 흐름을 인지할 수 있으며, URL이 변경된다.
- 포워드(Forward): 서버 내부에서 요청을 전달하는 방식으로, 클라이언트는 변경을 인지하지 못한다. URL도 변경되지 않는다.
MVC 패턴의 한계
MVC 패턴을 적용하면 컨트롤러와 뷰를 명확하게 분리할 수 있어 유지보수성과 확장성이 향상된다. 하지만 코드 중복과 공통 처리의 어려움이 존재한다.
MVC 컨트롤러의 단점
포워드 중복
View로 이동하는 코드가 항상 중복 호출되어야 한다. 물론 이 부분을 메서드로 공통화할 수 있지만, 해당 메서드를 항상 직접 호출해야 한다.
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request, response);
ViewPath 중복
String viewPath = "/WEB-INF/views/new-form.jsp";
/WEB-INF/views/ 와 .jsp가 반복되므로, 다른 뷰 템플릿(예: Thymeleaf)으로 변경하려면 전체 코드를 수정해야 하는 문제가 발생한다.
사용하지 않는 코드
컨트롤러에서 다음과 같은 코드가 항상 포함되지만, 사용되지 않는 경우도 있다.
HttpServletRequest request, HttpServletResponse response
이러한 코드는 테스트 케이스 작성 시에도 불필요한 복잡성을 유발한다.
공통 처리가 어렵다
기능이 복잡해질수록 컨트롤러에서 공통으로 처리해야 하는 부분이 많아진다. 단순히 공통 기능을 메서드로 분리하는 방식도 있지만, 해당 메서드를 항상 호출해야 하며, 실수로 호출하지 않으면 문제가 발생할 수 있다.
이 문제를 해결하려면 컨트롤러 호출 전에 공통 기능을 처리하는 수문장 역할이 필요하다. 이를 위해 프론트 컨트롤러(Front Controller) 패턴을 도입하면 중복을 줄이고 구조를 개선할 수 있다. 스프링 MVC의 핵심도 바로 이 프론트 컨트롤러에 있다.
정리
서블릿과 JSP만을 사용한 개발 방식에는 유지보수성과 확장성의 한계가 존재했다. 이를 해결하기 위해 MVC 패턴이 등장했으며, 컨트롤러, 모델, 뷰의 역할을 분리함으로써 코드의 구조를 명확하게 하고 유지보수를 용이하게 만들었다.
하지만 MVC 패턴에도 중복 코드와 공통 처리의 어려움이 남아 있다. 이러한 문제를 해결하기 위해 프론트 컨트롤러 패턴을 적용하여 더욱 효율적인 구조를 만들 수 있다.
'코딩 도구 > 백엔드 개발 (Backend Development)' 카테고리의 다른 글
웹 서버와 웹 애플리케이션 서버(WAS) (0) | 2025.02.28 |
---|---|
서블릿과 HTTP 요청/응답 (0) | 2025.02.24 |
[Spring] 빈 스코프 (0) | 2025.02.21 |
[Spring] 빈 생명주기 콜백 (0) | 2025.02.19 |
[Spring] 의존관계 자동 주입 (0) | 2025.02.18 |