MVC가 뭘까

Lee Jooam·2022년 4월 15일
0
post-thumbnail

처음 웹개발을 접했을 때 MVC, MVT, MVVM 등 다양한 패턴이 존재한다고 들었다. 하지만 각각의 패턴이 대체 왜 생겼고 정확히 무엇인지는 몰랐다.

이번 기회에 알아야 할 부분들을 정리해봐야겠다.

Why MVC?

Model, View, Controller

MVC가 출현한 계기는 간단하다. 인간이 개발을 조금 더 편하고 효율적으로 하려고 나온 디자인 패턴 중 하나다.

컴퓨터 공학에서 디자인 패턴은 프로그램 개발 상황에서 자주 나오는 문제들을 해결하기 위해 고안된 특정한 방법을 말한다. 보통 구조적인 문제를 해결하는데 큰 역할을 한다.

쉽게 말하자면, 했던 일을 반복하고 쓸데없는 내용을 덧붙이지 않는 등 개발을 깔끔하게 진행하기 위해 생긴 것이다. 과거의 개발자들이 만들어 낸 노하우인 만큼 그 무게는 무시할 수 없다.

Model

전반적인 데이터에 대한 형식, 데이터가 어떻게 저장될지, 데이터를 어떻게 불러올지 등 데이터 자체에 대한 내용들이다.

모델은 오직 데이터의 구성에만 신경쓴다. 그 데이터가 어떻게 처리될지, 사용자에게 어떻게 보여질지는 관심사가 아니다.

View

뷰는 직접적으로 사용자에게 보여지는 부분이다. '컨트롤러'를 통해 불러온 데이터를 사용자에게 렌더링한다.

뷰도 모델이나 컨트롤러가 어떻게 동작하는지는 관심사가 아니다. 오직 자신이 받은 데이터를 렌더링하는 것만 신경쓴다.

Controller

컨트롤러는 뷰와 모델에 명령을 내린다.

컨트롤러는 뷰와 모델을 이름에 맞게 control한다. 사용자(클라이언트)가 뷰를 통해 요청을 생성하면 컨트롤러는 그 요청을 받아 모델에 전달한다.

모델이 요청을 수행하고 새로운 값을 반환하면 컨트롤러는 그것을 뷰에게 알린다. 그리고 뷰는 새로운 응답을 기준으로 화면을 재구성한다.

컨트롤러는 각각의 계층을 조정하는 만큼 각 계층에서 어떤 작업이 벌어지는지 알아야한다.

예시

글로만 봐서는 체감이 안 되서 직접 구현해보기로 했다. 간단한 리스트 형태로 폼 submit 시 추가, 리스트 클릭 시 삭제 기능이 있는 작업물이다.

MVC_example MVC_example MVC_example
// model.js

export const db = {
};

export class Post {
  constructor(id, title, author, content) {
    this.id = id;
    this.title = title;
    this.author = author;
    this.content = content;
  }

  static writePost(post) {
    db[post.id] = post;
  }

  static deletePost(id) {
    delete db[id];
  }
}

모델을 설정하는 파일이다. db라는 변수로 state를 나타내게 하고 각각의 속성을 가지는 Post 객체를 저장한다.

// view.js

export function render(state, target) {
  target.innerHTML = Object.keys(state)
    .map(
      (id) =>
        `<li class='post' data-id=${id}>
        <div class="meta">
            <span class='title'>${state[id].title}</span>
            <span class='author'>${state[id].author}</span>
        </div>
        <span class='content'>${state[id].content}</span>
    </li>`
    )
    .join("");
}

렌더링을 담당할 view 파일이다. 인자로 들어온 state를 기준으로 li 요소들을 target 인자에 innerHTML로 넣어준다.

// controller.js

import { db, Post } from "./model.js";
import { render } from "./view.js";

function init() {
  const posts = document.querySelector(".posts");

  setEventHandler();
  render(db, posts);
}

function setEventHandler() {
  const submitForm = document.querySelector(".form");
  const posts = document.querySelector(".posts");

  submitForm.addEventListener("submit", (e) => {
    e.preventDefault();

    const [title, author, content] = [
      e.target[0].value,
      e.target[1].value,
      e.target[2].value,
    ];

    const post = new Post(new Date().getTime(), title, author, content);
    Post.writePost(post);

    render(db, posts);
    e.target.reset();
  });

  posts.addEventListener("click", (e) => {
    const id = e.target.closest("li").dataset.id;
    Post.deletePost(id);

    render(db, posts);
  });
}

init();

HTML 파일과 직접적으로 연결되는 contoller 파일이다. 각각의 기능에 event handler를 설정하고 발생한 event마다 view의 render 함수를 실행한다.

너무 막 만든 느낌이다. :<

<!-- index.html -->

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script type="module" src="./controller.js" defer></script>
    <link rel="stylesheet" href="./style.css" />
  </head>
  <body>
    <div class="root">
      <ul class="posts"></ul>
      <form class="form">
        <div class="meta">
          <input class="title" name="title" type="text" placeholder="제목" />
          <input
            class="author"
            name="author"
            type="text"
            placeholder="작성자"
          />
        </div>
        <textarea class="content" name="content" placeholder="내용"></textarea>
        <button type="submit">제출</button>
      </form>
    </div>
  </body>
</html>

index.html 파일이다. 초기 렌더링 후 controller.js의 조정에 따라 화면 구성이 달라진다.

후기

만들어보기까지 했지만 확실하게는 아직 모르겠다. 좀 더 찾아보니 view에서만 고정된 값들을 처리해서 렌더링하고, 유동적인 값들은 model에서 처리하고 controller가 전달해준다고 한다.

그렇다면 html 파일 자체는 건드리지 말아야하는 건가? root 컨테이너만 만들고 뷰에서 나머지 고정 값들을 전달해주는 것도 좋겠다.

profile
프론트엔드 개발자로 걸어가는 중입니다.

2개의 댓글

comment-user-thumbnail
2022년 4월 17일

:)

1개의 답글

관련 채용 정보