백엔드 웹 개발에서 가장 대표적인 MVC 패턴을 제대로 이해하기 위해서는 먼저 소프트웨어 디자인 패턴에 대한 이해가 필요하다.
디자인 패턴
디자인 패턴(Design Pattern)은 처음에는 건축학적 관점에서 출발한 개념이었으나 1994년 GoF(Gang of Four)의 <<Design Patterns: Elements of Reusable Object-Oriented Software>>를 통해 소프트웨어 설계에서 공통적으로 발생하는 문제에 대한 재사용 가능한 솔루션으로 제시되었다. 물론 완벽한 설계란 없으며 시대의 흐름에 따라 달라질 수 있지만, 시행착오를 통해 스스로 터득해야 할 문제를 정리해둔 솔루션이 있다면 당연히 검토할 가치가 있는 것이다.
GoF의 디자인 패턴은 생성, 구조, 행동, 동시실행 등의 문제에 대해 여러 패턴을 제시하고 있으며 UML 클래스 다이어그램을 이용해 구조를 표현하고 있다. UML이란 Unified Modeling Language의 약어로 객체지향 설계와 구현을 지원하기 위해 만들어진 일종의 모델링 언어다. 프로그래밍 언어와 같은 형태는 아니고 시스템 분석, 설계에 필요한 내용을 여러 다이어그램 형태로 정의한 규격이다.
추상 팩토리 패턴
Factory는 '공장'이라는 의미로 디자인 패턴에서 객체를 생성하는 역할을 의미한다. '추상적'이라는 의미를 가진 Abstract는 자바의 추상 클래스(Abstract Class)에도 사용되는 표현으로 구체적인 내용의 구현을 하위 객체에 위임하는 모델이다. 따라서 추상 팩토리(Abstract Factory)는 객체를 생성하는 것을 별도로 구현하되 관련된 구체적인 구현을 하위 클래스에서 담당하게 하는 설계 모델로 이해할 수 있다.
아래 그림은 객체 생성에 대한 문제 해결을 위한 추상 팩토리 패턴(Abstract Factory Pattern)의 UML 클래스 다이어그램이다.
객체지향 프로그래밍은 클래스로부터 여러 객체를 생성하고 이들을 활용하는 구조다. 따라서 프로그램에서 객체를 직접 생성하는 것이 당연하면서도 프로그램에 종속성을 만드는 요인이 되기도 한다. 예를 들어 데이터베이스 연동 프로그램에서 다음과 같은 코드가 있다고 가정한다.
ProductDAO dao = new ProductDAO();
dao.insertDB(p);
...
- ProductDAO 클래스는 데이터베이스 연동을 구현한 클래스다.
- insertDB() 메서드는 인자로 상품 객체를 전달받아 DB에 저장한다.
위 코드는 별다른 문제가 없어 보이지만 ProductDAO라는 클래스에 대한 종속성을 만들게 된다. 예를 들어 현재 시스템에서 오라클(Oracle) 데이터베이스를 사용하고, ProductDAO 역시 오라클에 맞게 제작된 클래스라 가정했을 때 이 경우 데이터베이스를 MySQL 또는 다른 데이터베이스로 교체할 경우 ProductDAO를 MySQL에 맞게 다시 구현해야 한다. 그런데 프로그램이 상황에 맞게 오라클 혹은 MySQL에서 실행되어야 한다면 현재 프로그램의 전반적인 구조를 수정할 수밖에 없을 것이다. 추상 팩토리 패턴은 이러한 경우 유용하게 사용할 수 있다. 직접적인 객체 생성 대신 팩토리(Factory) 클래스에 객체 생성을 위임하는 구조이기 때문이다.
다음 코드는 패턴 구조를 적용한 경우 클라이언트에서 팩토리를 사용하는 부분만 예로 든 것이다. 패턴 적용에 대한 이해를 돕기 위한 것으로 전체 패턴을 구현한 것이 아니다.
ProductDAO dao = DAOFactory.create("oracle");
dao.insertDB(p);
...
- ProductDAO: 추상 클래스 또는 인터페이스다. ProductDAO 추상 클래스를 상속받는 OracleDAO, MySQLDAO 등의 클래스가 존재한다.
- DAOFactory: 오라클이나 MySQL용으로 구현된 ProductDAO 타입의 객체를 생성해서 리턴한다.
위의 예시와 같이 create()의 인자로 특정 인스턴스를 요청할 수도 있고 .xml 설정 파일 등을 이용해 코드 수정 없이 확장 가능한 구조도 가능하다.
최근에는 개발자가 직접 애플리케이션 실행을 위한 모든 환경을 설계하고 개발하는 형태가 아니라 프레임워크, 컨테이너 기반으로 개발하기 때문에 직접적인 패턴 구형에 대한 고민을 줄어 들었다. 하지만 소프트웨어 설계에서 디자인 패턴은 여전히 중요한 개념이다.
MVC 패턴
MVC 패턴이란 Model-View-Controller의 약어로 주로 GUI(Graphical User Interface) 기반의 애플리케이션 개발에 사용되는 디자인 패턴이다. 지금은 백엔드 기반의 웹 애플리케이션 개발의 기본 모델이 되었으며 모바일 앱 및 프론트엔드 기반 웹 애플리케이션 개발이 늘어나면서 MVP(Model-View-Presenter), MVVM(Model-View-ViewModel)과 같은 패턴도 널리 사용되고 있다.
이러한 패턴의 공통적인 목적은 화면과 데이터 처리를 분리하여 코드 간 종속성을 줄이는 데 있다. 즉 구성요소 간 역할을 명확하게 하여 코드를 쉽게 분리하고 협업이 용이하게 만드는 것이다.
모델
모델(Model)은 데이터를 처리하는 영역이다. 일반적으로 데이터베이스와 연동을 위한 DAO(Data Access Object) 클래스와 데이터 구조를 표현하는 DO(Data Object), 엔티티 클래스 등으로 구성된다.
모델은 뷰나 컨트롤러에 독립적인 구조로 데이터베이스 처리를 필요로 하는 여러 애플리케이션에서 공유할 수 있으며 웹 애플리케이션이 아닌 경우에도 사용할 수 있는 형태다.
DAO, DO는 필수적인가?
효과적인 DB 연동 구현을 위해 JPA(Java Persistence API)를 사용하는 경우 DAO는 생략되거나 구현 범위가 축소될 수 있다. 또한 하나의 화면 구성을 위해 여러 데이터베이스 혹은 외부 서비스 등과 연계해야 하는 경우 이들을 통합하기 위해 별도의 서비스 객체를 두거나 DO 이외에 DTO(Data Transfer Object)등을 사용하기도 한다.
뷰
뷰(View)는 화면 구성을 담당하는 영역이다. 뷰에서 데이터를 직접 가져오는 방식은 권장하지 않고 주어진 데이터를 출력하는 용도로만 사용하는 것이 바람직하다. 뷰 영역의 구현을 위해 뷰 템플릿 엔진이 사용되며 JSP 역시 이러한 뷰 템플릿 엔진 중 하나다. HTML 이외에 EL, JSTL 등을 사용해 컨트롤러로부터 전달받은 데이터를 출력하고 HTML, CSS 등을 통해 화면을 디자인한다. 뷰는 기본적으로 모델, 컨트롤러와의 종속성이 없도록 구현해야 한다.
스프링 프레임워크에서 주로 사용하는 타임리프, 전통적인 프리마커 등이 대표적인 뷰 템플릿 엔진이며 구현에 따라 서로 다른 뷰 템플릿 엔진을 사용해도 무방하다.
컨트롤러
컨트롤러(Controller)는 MVC 패턴의 핵심으로 모든 사용자 요청의 중심에 위치한다. 사용자 요청은 특정 뷰에 바로 전달되지 않고 컨트롤러를 통해야 하며, 컨트롤러는 사용자 요청에 따라 모델을 통해 데이터베이스와 연동하여 데이터를 처리하고 뷰에 전달한다. 뷰로 전달하기 위해 데이터가 들어 있는 DO 혹은 List<DO> 형태의 객체를 request에 저장한 후 포워딩한다.
컨트롤러는 특정 뷰를 지정해야 하기 때문에 뷰와 종속관계가 발생할 수 밖에 없다. 따라서 프로젝트의 규모가 클수록 컨트롤러는 복잡해지고 관리가 어려워지는 문제가 있다.
컨트롤러의 구현은 JSP, 서블릿 모두 가능하며, 간단한 기능을 구현할 때는 JSP가 유리하지만 규모 확장과 향후 스프링 프레임워크로의 확장 등을 고려한다면 서블릿 기반의 구현을 권장한다.
컨트롤러를 구성하는 세 가지 방법이 있다.
첫 번째는 사용자 요청마다 컨트롤러를 만드는 것이다. 예를 들어 로그인 기능을 구현하려면 'loginForm.html'로 데이터를 입력받고 LoginController에서 처리하고 결과를 보여주는 'main.jsp'가 필요한데, 각각의 기능 구현을 동일한 방식으로 처리하게 되면 기능(예: 회원 가입, 정보 수정 등)마다 컨트롤러를 만들어야 한다.
두 번째로 특정 모듈 단위로 하나의 컨트롤러 안에서 여러 요청 단위를 구분해 처리할 수 있다. 예를 들어 MemberController 안에서 로그인, 회원 가입, 정보 수정 등을 처리할 수 있다.
마지막으로 프론트 컨트롤러를 따로 두어 모든 요청을 하나의 컨트롤러로 모은 다음 요청에 따라 구현 컨트롤러를 호출하도록 구성할 수도 있다.
서블릿만으로 컨트롤러 구현이 가능할까?
단순하게 서블릿만으로 컨트롤러를 구현하는 것은 어렵지 않지만 실제 개발에서는 시스템 전반을 통합할 수 있는 컨트롤러 구조를 설계해서 일종의 프레임워크 개념으로 만들어둘 필요가 있다. 따라서 이러한 부분은 개인 혹은 회사에서 개발하거나 스프링 프레임워크와 같이 오픈소스 프레임워크를 사용하게 된다.
'Programming > Web' 카테고리의 다른 글
[Web] 데이터베이스(Database) (0) | 2022.10.24 |
---|---|
[Web] 서블릿 컨트롤러 설계 (0) | 2022.10.23 |
[Web] JSTL(JSP Standard Tag Library) (0) | 2022.10.22 |
[Web] 커스텀 태그와 EL (0) | 2022.10.22 |
[Web] 액션 태그 (useBean, include, forward) (0) | 2022.10.21 |