오늘은 Java의 메인 디자인 패턴인 MVC 패턴에 대해 포스팅하려 합니다. 면접 단골 질문이기도 해서 지난날 면접 준비하면서 열심히 외웠던 기억이 나네요.. 한동안 Node로 프로젝트를 진행하다가 다시 Java Spring 프로젝트를 맡게 되어서 다시 한번 MVC 패턴에 대해 짚고 넘어가려고 합니다. 그럼 MVC 패턴에 대해 알아볼까요?
MVC 패턴이란?
역사👣
과거에도 많은 개발자분들이 코딩을 했었고, 초창기에는 한 파일에 모든 코드를 넣었다고 합니다. 그러다 보니 기능을 수정할 때, 그 코드를 찾는 것이 힘든 것은 물론이거니와 하나의 코드를 수정하면 대부분의 코드를 수정해야 하는 경우가 빈번히 발생했다고 합니다. 이 말은 즉슨, 유지보수가 불편했다 라고 생각하시면 될 것 같습니다.
그렇게 시간이 흐르다 보니 많은 개발자분들이 불편함을 느끼고 해당 문제를 해결하려고 노력했습니다. 그 노력의 결과가 현재의 MVC 패턴입니다. 이 패턴을 하나의 공식처럼 만들어서 논문으로 발표했고 오늘날의 유지보수가 편한 패턴 중 하나로 자리매김하였습니다.
유지보수가 편한 코드? 😄
특정 기능을 추가하거나 수정할 때 가능한 한 최소한의 코드만을 수정해서 기능을 변경할 수 있음을 의미합니다. 최소한의 코드를 변경하려면 기본적으로 변하는 것과 변하지 않는 것을 분리해야 하는데, 이러한 것들을 디자인 패턴이라고 부릅니다. 또한 개발자 입장에서 가독성이 좋아야 유지보수가 편한 것은 당연합니다.
빵 공장🏭
이해를 좀 더 돕기 위해 빵 공장을 예시로 들어보려 합니다. 빵 공장에서 하는 일은 빵을 만들고 포장을 하며 각 배송업체별로 빵의 개수를 맞춰 박스에 담습니다. 또, 배송업체 직원에게 보여줄 리스트도 만들어야 합니다. 이 모든 과정을 한 공간에서 행한다면 복잡하지 않을까요? 설령 요즘 유행하는 포켓몬 빵처럼 빵 안에 스티커도 함께 있다면 어떤 빵에 스티커가 들어가 있는지 확인하는 작업도 필요할 것입니다.
만약 빵안에 스티커가 들어갔던 제품이 스티커를 빼 달라는 요청이 들어오면 공장에서는 빵에 스티커를 넣는 작업을 했던 작업자에게 요청사항을 전달하면 됩니다. 다른 작업자들은 신경 쓰지 않아도 될 문제이기 때문입니다. 하지만 그 복잡한 환경에서 스티커를 넣는 작업자들만 쏙쏙 찾아가서 전달하기는 어려워 보입니다.
결론적으로 개발적인 측면에 봤을 때, 유지보수가 좋지 않은 환경이 될 것입니다. 빵 공장을 빵을 만드는 사람, 빵에 스티커를 넣는 사람, 빵을 포장하는 사람, 배송업체에 전달하는 사람 등 각자 역할에 맡게 그룹화시키면 좀 더 체계화가 되는 것은 당연합니다.
개발도 매한가지입니다. 저도 처음에 한 파일에서 진행하는게 훨씬 더 편했었고, 나누는 작업조차 어렵게 느껴졌는데요. 추후에 개발을 진행하다 보면 '과거에는 도대체 어떻게 한 거지?' 생각이 들 정도로 지금의 시스템이 편합니다. 그럼 MVC의 탄생 배경을 알아봤으니, MVC 패턴이 무엇인지 알아볼까요?
정의📝
MVC 패턴은 Model-View-Controller 의 약어로 주로 GUI 기반의 애플리케이션 개발에 사용된 디자인 패턴입니다. 화면과 데이터 처리를 분리해 코드 간의 종속성을 줄이고 구성 요소 간의 역할을 명확하게 함으로써 코드 분리가 쉽고 협업을 용이하게 하는 장점을 가지고 있습니다.
위에 사진은 MVC 패턴을 간략하게 표현한 사진입니다. 아래의 본문 내용을 읽기 전에 흐름을 파악해보시면 본문 내용을 보다 쉽게 이해하실 수 있습니다 😀
Model
모델(Model)은 데이터를 처리하는 영역입니다. 실제 프로젝트에서는 데이터베이스와 연동하는 DAO(Data Access Object) 와 데이터 구조를 표현하는 DO(Data Object) || Entity로 구성이 됩니다. 쉽게 말해, 아까 예시를 들었던 빵 공장에서 '빵'에 해당합니다.
모델은 뒤에 설명할 View와 Controller에 의존하지 않아야 한다는 특징이 있습니다. 또한 JPA(Java Persistance API)를 사용하는 경우에는 DAO는 생략 될 가능성도 있습니다.
👆 JPA에 대해 궁금하신 분은 클릭해주세요!
View
뷰(View)는 사용자에게 보이는 화면이라고 생각하시면 됩니다. 흔히 UI(User interface)라고 부릅니다. 아래에서 설명할 Controller로 부터 전달된 데이터의 출력과 HTML, CSS 등을 통해 화면의 디자인을 처리하는 영역입니다. 기본적으로 모델, 컨트롤러와의 종속성 없이 구현해야 합니다.
Controller
컨트롤러(Controller)는 MVC 패턴의 핵심으로 모든 사용자 요청의 중심에 위치합니다. 쉽게 말해 사용자가 어떠한 작업을 수행시에(Ex: 회원가입-아이디 중복체크 버튼 클릭) 특정 뷰로 요청이 가는 것이 아니라, 컨트롤러에서 우선적으로 요청을 받아들입니다.
위의 예시처럼 사용자가 아이디 중복체크를 클릭했을 때, 해당 아이디가 현재 존재하는지 여부를 알기 위해선 데이터베이스를 조회하는 작업이 필요합니다. 뷰는 단지 사용자에게 보이는 화면단이기 때문에, 컨트롤러에서 이 작업 요청을 받아들이고 이후에 데이터베이스를 조회해서 결과값을 다시 뷰에게 전달하는 과정을 밟습니다.
이때, 컨트롤러는 특정 뷰를 지정해야 하기 때문에(Ex: 회원가입 화면) 뷰와 종속관계가 발생할 수밖에 없는 구조입니다. 따라서 프로그램의 규모가 커질수록 컨트롤러의 역할이 상당히 커지기 때문에 복잡해지고 관리가 어려워집니다.
그래서 Service단이 존재합니다. Service단은 컨트롤러의 비중을 줄여주기 위해서 실무에서 많이 사용합니다. 이 부분도 MVC 패턴이 생겨난 이유처럼 유지보수를 위해 생겨났다고 생각하시면 이해하기 쉬울 것 같습니다. 하지만 이 포스팅은 MVC를 주로 다루고 있기 때문에, 자세한 설명은 넘어가도록 하겠습니다.
순서📑
다시 한번 위에 그림을 보겠습니다. 클라이언트(사용자)는 프로그램에 아이디 중복 검사를 요청합니다. 그러면 우선적으로 컨트롤러가 그 요청을 받아들이고 데이터베이스를 조회해서 결과값을 받습니다(Ex: 중복된 아이디입니다)
그럼 그 컨트롤러는 데이터를 뷰에게 보내줍니다. 그리고 뷰를 통해 사용자는 아이디가 중복되었는지 아닌지에 대한 결과를 알 수 있게 됩니다. 이제 전반적인 흐름을 이해하게 되었습니다. 흐름 과정에서 MVC 패턴의 장점을 대략적으로 유추할 수 있겠지만, 다시 한번 짚어볼까요?
MVC 장점
- 디자이너와 개발자의 분업이 가능하며 확장면에서 용이하다.
- 단순하고 직관적이다.
- 코드 재사용이 증가한다.
- Model, View, Controller 가 분리되어 있어서, 내가 필요한 부분만 쉽게 찾아내거나 수정할 수 있다.
- 한마디로 유지보수가 좋다.
MVC 예제
사용자가 찾는 빵이 있는지 없는지에 대한 간단 예제입니다. 빵의 이름이 겹치거나 하는 예외 로직들은 구현하지 않겠습니다.
1. Model
package Binco;
@Getter
@NoArgsConstructor
public class Bread {
private Long id; // 빵 고유 번호
private String name; // 빵 이름
public Bread(Long id, String bread){
this.id = id;
this.name = name;
}
}
@Getter : LomBok 라이브러리를 이용해 getter를 생성했습니다. 아직 롬복에 대해 모르시다면, 아래 코드를 대신 생성해주는 라이브러리라고 생각하시면 됩니다.
public Long getId() {
return id;
}
public String getName() {
return name;
}
@NoArgsConstructor : @Getter와 마찬가지로 LomBok 라이브러리를 이용해 기본생성자를 대신 생성합니다.
public Bread() { }
첫 번째로, 모델이 있어야 유저와 프로그램 간의 대화가 이루어지기 때문에 모델을 생성해주었습니다. 해당 예시는 편의상 롬복 라이브러리를 사용했고, 실무에 투입되면 springboot를 사용하는 회사라면 롬복은 거의 필수적으로 사용하기 때문에, 미리 알아두시면 좋을 것 같습니다
2. Controller
간단 예시이기 때문에 사용자가 찾는 빵의 이름을 사용자가 입력해서 컨트롤러로 데이터를 넘기는 과정은 생략하겠습니다.
package Binco;
@Controller
public class BreadController {
private final BreadService breadService; // DB를 조회하는 Service 단 입니다.
@GetMapping("/search/bread")
public String searchBread(@PathVariable String name, Model model){
boolean result = breadService.findByName(name);
model.addAttribute("result", result);
}
}
이 코드는 설명이 조금 필요할 것 같습니다. 첫 번째로 @Controller는 모델에서 썼던 롬복 라이브러리의 기능 중 하나입니다. 직관적으로 알 수 있듯이, Controller의 역할을 부여했다고 보시면 됩니다.
코드를 올리지는 않았지만 BreadService는 빵 관련 Service단 입니다. 대게 Controller 단에서 import 하여 사용합니다. 하단에 findByName이라는 함수는 말 그대로 이름을 통해 해당 빵의 존재 여부를 확인하고 그 값을 true(빵이 존재) / false(존재하지 않음)으로 반환한다고 가정하였습니다.
@GetMapping은 get 방식으로 넘어오는 url들을 받아들이는 롬복 기능이라고 생각하시면 됩니다.
@PathVariable은 파라미터로 넘어오는 값들을 받아 들입니다. 이번 예제에서는 빵의 이름을 받아온다고 가정했기 때문에 name을 받아들입니다.
Model은 Controller에서 View단으로 데이터를 넘길 때 사용합니다. 이번 예제에서는 빵의 유무를 true / false로 체크해 데이터를 전송해줍니다.
3.View
...생략
<c:choose>
<c:when test ="${result}">
<p>해당 빵은 존재합니다</p>
</c:when>
<c:otherwise>
<p>해당 빵은 존재하지 않습니다</p>
</c:otherwise>
</c:choose>
JSP , JSTL을 이용해서 View를 구성했습니다. c 태그를 이용해서 result 값이 true 이면 해당 빵이 존재한다고 보여주고, 그게 아니라면 해당 빵은 존재하지 않는다고 띄워줍니다.
JSP, JSTL을 모르셔도 'View에서는 컨트롤러에서 넘겨준 데이터를 뿌려주는구나'라고만 이해하셔도 됩니다.
👨👩👦👦 오픈채팅방 운영
취업을 준비하는 예비 개발자분들을 위한 질문&답변할 수 있는 공간을 만들었습니다. 취업과 이직을 하기 위해서 어떤 걸 중점적으로 준비해야 하는지부터 포트폴리오&이력서 작성법 등 다양한 질문들을 받고 답변을 드립니다. 참여하셔서 다양한 정보 얻고 가시면 좋을 것 같네요😁
참여코드 : 456456
https://open.kakao.com/o/gVHZP8dg
👨💻 전자책 출간
아울러 제가 🌟비전공자에서 2년만에 보안 전문 중견기업으로 이직 한 방법들을 정리한 전자책을 출간 하게 되었습니다. 어떤 걸 공부해야 하는지, 이직을 위해서 무엇을 준비해야 하는지, 제가 받았던 기술 면접 리스트 등 다양한 목차로 구성되어 있습니다. 또한, 구매 시 1:1 채팅을 이용하여 포트폴리오 첨삭을 도와드리고 있습니다. 🐕전자책으로 얻은 모든 수익은 유기견 센터 '팅*벨 입양센터'에 후원될 예정입니다. 관심 있으신 분들은 아래 링크를 참고해주세요😁
마치며
지금까지 Java MVC 디자인 패턴에 대해 알아보았습니다. 서두에서 언급했듯이, 신입개발자들의 주요 단골 질문이기도 하며 저도 MVC패턴 질문을 많이 받은 기억이 있습니다. 그만큼 가장 기본적인 상식이기 때문에, 혹시 모르셨다면 이번 기회에 꼭 알고 가셨으면 합니다. 또한, 지금은 MVC 패턴은 Controller의 비중이 너무 큰 문제점이 있어서 이러한 문제점을 보완하기 위한 MVVM, MVP 패턴도 등장하였습니다. MVVM, MVP는 추후에 포스팅하겠습니다.
JAVA 관련 포스팅
* [ 객체 지향 프로그래밍(OOP)이란? ]
* [ 추상 클래스 VS 인터페이스 ]
* [ JPA 영속성 컨텍스트 핵심요약 ]
* [ JPA의 정의와 장 ·단점 ]
'TIL' 카테고리의 다른 글
AOP(Aspect-Oriented Programming) 파헤치기 (0) | 2022.06.22 |
---|---|
TDD 정의 및 암호 검사기 예시 (0) | 2022.05.25 |
Java Enum 클래스 (0) | 2022.05.19 |
Java 추상 클래스와 인터페이스 구분 (0) | 2022.05.18 |
객체 지향 프로그래밍(OOP)이란? (0) | 2022.05.16 |