MVC패턴은 "디자인 패턴"중 하나이다.
"디자인 패턴"이란 프로그램이나 어떤 특정한 것을 개발하는 중에 발생했던 문제점들을 정리해서 상황에 따라 간편하게 적용해서 쓸 수 있는 형태로 만든 것을 말한다.
어떤 앱을 만든다고 가정했을 때, 앱을 유지보수하고 다른 이들과 공유를 하면서 만들어야 할 때 좀더 쉽고 깔끔하게 만들 수 있는 방법을 고안하지 않는다면, 우리는 클래스 함수들을 일일이 다 만들어야 하고,
라이브러리나 프레임워크가 그걸 보완하는 경우라고 볼 수 있다.
예를들어 그냥 jQuery를 이용한다면 $('#lucid')로 DOM을 선택할 수 있는 것을 그냥 순수 Javascript를 사용한다면 document.getElementsByid('lucid')로 길게 써가며 찾아야 하지만 어떤 data를 만들고 이 data를 수정할 로직을 짤 때, data를 보여주는 부분을 만들 때 로직이 분리가 안되어 있고 한꺼번에 정의가 되어 있다면 유지보수 하기 힘들 것이다.
그걸 돕기 위해 "디자인 패턴" 이 나오는 것이고 좀더 쉽고 편리하게 사용할 수 있게 만든 특정한 방법들을 디자인 패턴이라고 한다. 그 디자인 패턴이라는 것은 여러가지가 있지만 그중의 하나가 MVC 패턴이다.
모델-뷰-컨트롤러(Model-View-Controller, MVC)는 소프트웨어 공학에서 사용되는 소프트웨어 디자인 패턴이다.
이 패턴을 성공적으로 사용하면, 사용자 인터페이스로부터 비즈니스 로직을 분리하여 애플리케이션의 시각적 요소나 그 이면에서 실행되는 비즈니스 로직을 서로 영향없이 쉽게 고칠 수 있는 애플리케이션을 만들 수 있다.
MVC는 Model, View, Controller의 약자이다. 하나의 어플리케이션, 프로젝트를 구성할 때 그 구성요소를 세가지의 역할로 구분한 패턴이다.
위의 그림처럼 사용자가 controller를 조작하면 controller는 model을 통해서 데이터를 가져오고 그 정보를 바탕으로 시각적인 표현을 담당하는 View를 제어해서 사용자에게 전달하게 된다. 저건 하나의 로직을 설명하기 위해 만든 그림이고 사실 MVC 패턴의 구조는
위의 그림이 더 어울린다고 보면 된다.
애플리케이션의 정보, 데이터를 나타낸다. 데이터베이스, 처음의 정의하는 상수, 초기화값, 변수 등을 뜻한다. 또한 이런 DATA, 정보들의 가공을 책임지는 컴포넌트를 말한다. 이 모델은 다음과 같은 규칙을 가지고 있다.
즉, 화면안의 네모박스에 글자가 표현된다면, 네모박스의 화면 위치 정보, 네모박스의 크기정보, 글자 내용, 글자의 위치, 글자의 포맷 정보 등을 가지고 있어야 한다는 것이다.
데이터 변경이 일어났을 때 모델에서 화면 UI를 직접 조정해서 수정할 수 있도록 뷰를 참조하는 내부 속성값을 가지면 안 된다.
모델의 속성 중 텍스트 정보가 변경이 된다면, 이벤트를 발생시켜 누군가에게 전달해야 하며, 누군가 모델을 변경하도록 요청하는 이벤트를 보냈을 때 이를 수신할 수 있는 처리 방법을 구현해야 합니다. 또한 모델은 재사용 가능해야 하며 다른 인터페이스에서도 변하지 않아야 한다.
input 텍스트, 체크박스 항목 등과 같은 사용자 인터페이스 요소를 나타낸다. 다시 말해 데이터 및 객체의 입력, 그리고 보여주는 출력을 담당한다. 데이터를 기반으로 사용자들이 볼 수 있는 화면이다.
뷰에서는 다음과 같은 규칙이 있는데
화면에 글자를 표시하기 위해, 모델이 가지고 있는 정보를 전달받게 될텐데, 그 정보를 유지하기 위해 임의의 뷰 내부에 저장하면 안된다. 단순히 네모 박스를 그리라는 명령을 받으면, 화면에 표시하기만 하고 그 화면을 그릴 때 필요한 정보들은 저장하지 않아야 한다.
그냥 뷰는 데이터를 받으면 화면에 표시해주는 역할만 가진다고 보면 됨.
컨트롤러는 모델과 뷰를 연결 시켜주는 다리 역할을 함과 동시에 도메인 객체들의 조합을 통해 프로그램의 작동 순서나 방식을 제어한다. controller는 view와 model이 각각 어떤 역할과 책임이 있는지 알고 있어야 한다.
웹 프로그래밍에서는 Controller에서 service layer를 분리하여 domain 로직이 수행되는 곳과 view의 요청을 매핑하는 곳을 독립적으로 관리할 수 있다.
view
뷰는 사용자의 동작과 연관되어 있는 부분이 많고, 비교적 자주 변경되는 부분이라 웹 애플리케이션 개발에서 많은 시간이 소요되는 영역이다. 때문에 뷰를 TDD로 개발하는 것은 효율이 낮을 뿐만 아니라 쉽지도 않다. 그리고 뷰에는 다양한 요소들이 혼재되어 있다. 그럼에도 보통은 이를 분리해서 생각하지 않고 뷰라는 한 가지 개념으로만 접근하기 때문에 더욱 어렵게 느껴지게 된다.
Controller
결론부터 얘기하면 컨트롤러에 대한 TDD 작성은 비교적 수월하다. MVC모델에서 컨트롤러를 테스트하는 가장 간단한 방법을 소개하면 뷰로부터 넘어오는 요청(Request)를 가상으로 만들어주고, 그 결과에 해당하는 응답이 예상과 일치하는지 판단하면 된다.
모델 테스트보다는 귀찮고 복잡하지만 controller를 테스트 하는 것도 충분히 가능하고, 프레임워크를 쓰면 manual로 하는 것 보다 훨씬 수월하게 할 수 있다고 한다.
Model
MVC에서는 모델과 뷰를 완전히 분리하는 방식으로 작성할 것을 권장한다.
모델이 통신하는 컨트롤러와의 관계도 사실 자세히 살펴보면 모델이 컨트롤러를 호출하는 경우는 없다. 모델은 오로지 무언가의 호출에 응답할 뿐이고, MVC 모델의 웹 애플리케이션에서는 컨트롤러가 모델을 호출하는 역할을 맡고 있을 뿐이다. 혹자는 이런 방식을 객체 지향 원칙 중 하나인 헐리우드 법칙(Don't ask me, I'll tell you)이라고 부르기도 한다. 모델은 웹 애플리케이션 구성요소 중 가장 TDD가 쉽게 적용되는 부분이고, 또 적용해야 하는 부분이다.
위키에 나온 controller의 정의만 보더라도 위 물음에는 대답이 명확히 나온다.
MVC의 뷰는 여러 개의 컨트롤러(Controller)를 가지고 있다. 사용자는 컨트롤러를 사용하여 모델의 상태를 바꾼다. 컨트롤러는 모델의 mutator(setter) 함수를 호출하여 상태를 바꾼다. 이때 모델의 상태가 바뀌면 모델은 등록된 뷰에 자신의 상태가 바뀌었다는 것을 알리고 뷰는 거기에 맞게 사용자에게 모델의 상태를 보여준다. -wikepedia-
따라서 controller는 하나일 필요가 없다. 프로그램이 실행될 때 로직이 병렬적으로 분기된다면 controller를 여러개 둬도 상관없다. 오히려 그게 더 깔끔한 설계가 될 수 있다.
적용 예시 코드↓
처음 메인 기능을 선택하는 입출력 화면이 나오고, 유저의 입력에 따라서 각 controller가 실행된다.
public void run() {
PosNumber posNumber;
do {
posNumber = getPosWithValidation();
PosController controller = posNumber.getController();
controller.controlAction(tables, menus);
// posNumber에 따라서 각각의 controller가 실행됨.
} while (posNumber.isNotExit());
}
각 컨트롤러는 Interface를 구현하는 방식으로 만들면, 유저 입력에 따라 if문으로 분기하여 controller를 실행하는 번거로움을 제거할 수 있고, 다형성을 이용하여 유지보수 및 확장할 때도 이점을 확보할 수 있다.
// PosController Interface
public interface PosController {
void controlAction(Tables tables, Menus menus);
}
사용자가 보는 페이지, 데이터처리, 그리고 이 2가지를 중간에서 제어하는 컨트롤, 이 3가지로 구성되는 하나의 애플리케이션을 만들면 각각 맡은 바에만 집중을 할 수 있게 된다. 도메인을 작은 역할 단위로 분리하여 설계하는 것도 일종의 분업이라고 할 수 있지만 전체적인 구조에서도 MVC패턴은 분업을 만들어 낼 수 있다.
서로 분리되어 각자의 역할에 집중할 수 있게끔하여 개발을 하고 그렇게 애플리케이션을 만든다면, 유지보수성, 애플리케이션의 확장성, 그리고 유연성이 증가하고, 중복코딩이라는 문제점 또한 사라지게 된다.
그렇지 않다. MVC 패턴도 수많은 디자인 패턴중 단순하고 명료해서 기본적으로 많이 사용되는 패턴일 뿐, 한계점도 당연히 가지고 있다.
한 Model은 다수의 View를 가질수 있고 반대로 Controller를 통해서 한 View에 연결되는 Model도 여러 개가 될 수 있다.
이렇게 되면 결과적으로 View와 Model이 서로 의존성을 띄게 된다. 물론 설계를 잘 한다면 Model 간의 의존성 뿐만 아니라 View와 Model 사이에 생기는 의존성도 줄일 수 있지만, 프로그램 특성상 복잡한 화면과 데이터의 구성이 필요한 구성이라면, Controller에 다수의 Model과 View가 복잡하게 연결되어 있는 상황이 생길 수 있다.
이렇게 MVC규모 자체가 너무 복잡하고 비대해져서, 새 기능을 추가할 때마다 의존성을 일일이 해결해야 해서 메소드 분석이나 테스트도 어렵게 된다. 이런 형태의 MVC를 MassiveViewController라고 부르는데, 이는 MVC의 한계를 표현한 용어이기도 한다.
View와 Model을 중재하는 Controller의 비중은 별로 크지 않을 것을오 생각할 수 있지만, 복잡한 화면을 구현하게 되면 Massive View Controller가 될 수 밖에 없다.
Controller는 View와 라이프 사이클이 강하게 연결되어 있어서 분리하기도 어렵고, 유지보수와 테스트가 모두 힘들어진다.
이러한 한계점을 갖고 있기 때문에 MVC로 부터 파생된 다른 패턴들을 공부해보는 것도 나중엔 도움이 될 것 이라고 생각된다.
참고 링크 - https://velog.io/@ljinsk3/MVC-%ED%8C%A8%ED%84%B4
참고 링크 - https://m.blog.naver.com/jhc9639/220967034588