[ Project ] 개발 시작 구조

Shin·2022년 3월 20일
0
post-thumbnail

📁 Express 3계층 설계[ 3-Layer architecture ] 구조 만들기

설계란?

  • 프로그래밍에서의 코드 설계는 코드와 파일, 그리고 폴더 구조를 설계하는 것을 말합 니다.

만약 적절한 설계를 하지 않고 코드를 작성하게 될 경우 여러가지 문제가 발생할 수 있습니다.

  • 코드가 몇백 줄(혹은 몇천 줄)이 되기 때문에, 수정할 코드가 있을 때 해당 부분을 찾기 힘듭니다. 따라서 유지보수가 어려워집니다.

  • 코드와 코드 사이 (함수와 함수 사이 등) 어떤 관계가 있는지 한 눈에 알아보기 힘듭니다.

  • 각 코드(함수, 객체 등)의 역할과 기능이 명확하게 구분되어 있지 않으므로, 기능별로 테스트(유닛 테스트)를 진행하는 것이 어려워집니다.

  • 하나의 파일을 동시에 여러 사람이 수정하는 것은 힘들기 때문에, 분업이 어려워 집니다.

  • 새로운 기능을 추가하고자 할 때, 기존에 존재하는 코드의 어느 부분을 수정하고 혹은 새로 작성해야 하는지 알아내기 힘듭니다. 즉, 확장성이 부족한 코드가 됩니다.

위 문제들을 해결하기 위해 다양한 코드 구조 설계가 만들어졌는데, 저는 그 중 3계층 구조 설계를 사용하기로 했습니다!

3계층 구조 설계란 3개 구조로 나누어 설계하는 것을 말합니다.

Control layer (컨트롤러): 사용자의 요청(request)을 분석한 후, 알맞은 서비스로 해당 요청을 전달해 준 다음, 서비스의 결과를 다시 응답(response)하는 층입니다.
즉, 라우팅(Routing)이 이루어지는 층입니다.
express의 경우,req.params(), req.body(), res.status(), res.send()와 같은 코드가 작성됩니다.

Service layer(서비스): 컨트롤러로부터 전달된 요청에 로직을 적용하는 층입니다.
이 때 로직이라는 것은, 예를 들어 로그인 서비스의 경우 다음과 같습니다.
아래와 같은 로직을 if-else 등의 코드로 구현할 수 있습니다.

Model layer(데이터): 서비스 층에서 데이터베이스 접근이 필요한 경우가 있는데, 이 때 데이터 관련 코드가 작성되는 층입니다. Mongoose의 경우 Model.find({})와 같은 코드가 작성됩니다.
로그인 서비스를 예시로 보면, 요청으로 온 ID가 데이터베이스에 존재하는지, 만약 존재한다면 그 때 데이터베이스 상에 저장된 비밀번호는 요청으로 온 (사용자가 입력한) 비밀번호와 일치하는지 확인해야 합니다.
이 때 서비스 층은 데이터 층에 데이터베이스 확인 요청을 하게 되는 것입니다.

위와 같이 코드를 역할별로 분리하여 각 층에 구현하는 경우, 다음과 같은 장점이 있습니다.

  • 각 역할별로 개발 업무를 분담할 수 있으므로 분업이 용이해집니다.

  • 역할 별로가 아닌 MVP 별로 개발 업무를 분담하는 경우에도, 각 MVP가 어떤 흐름으로 구현되는지 (Controller에서 사용자로부터 요청을 받고, 요청에 대해 Service 층에서 로직을 구현하고, 필요 시 데이터베이스에 접근한 후, 결과를 Controller가 응답합니다) 코드 구조를 보고 이해하기 쉬워집니다.

  • 라우팅 관련 코드는 Controller 폴더에서, 서비스 로직 관련 코드는 Service 폴더에서, 데이터 관련 코드는 Model 폴더에서 구분하여 확인할 수 있으므로, 필요한 코드를 빠르게 찾을 수 있으며, 따라서 유지보수가 용이해집니다.

  • 웹 서비스의 구현 방식을 변경하고자 할 때, 예를 들어 데이터베이스를 Mongodb에서 Mysql로 변경하고자 할 때, 각 폴더는 역할이 분리되어 있으므로, Model 폴더 코드만 변경하면 되고 나머지 Controller, Service 폴더는 변경하지 않아도 됩니다. 유지보수가 용이해집니다.

  • 코드가 기능별로 구분되어 있으므로, 기능별로 테스트(유닛 테스트)를 진행하기 용이해집니다.

그래서 이런 3계층 구조 설계를 사용하기 위해 현재 폴더구조를 아래와 같이 설정했습니다.

└───src
    ├───db           # Model layer
    │   ├───models
    │   └───schemas
    ├───middlewares
    ├───routers     # Control layer
    └───services    # Service layer

💻 수상 내역 [Award ] 부분 DB 설계 진행

처음 설계할 때 User DB에 배열로 수상 내역을 넣는 식으로 진행 했으나 Award 부분 관리를 하는데 User DB 부분을 같이 봐야하는 점이 불편해서 User Model 과 Award Model을 따로 나눈 후 Award 모델에서 User모델을 참조하게 하여 진행하였습니다.

import mongoose from "mongoose";
const Schema = mongoose.Schema;
const model = mongoose.model;
const AwardSchema = new Schema({
  id: {
    type: String,
    unique: true,
    required: true,
  },
  title: {
    type: String,
    required: true,
  },
  description: String,
  author: {
    type: Schema.Types.ObjectId,
    ref: "User",
    required: true,
  },
});
const AwardModel = model("Award", AwardSchema);
export { AwardSchema, AwardModel };

그리고 담당한 다른 파트인 Education [학력 부분 API ] 의 모델도 Award Model 처럼 설정해주었습니다.


💾 GitLab 이슈를 Commit 메세지로 닫기

Gitlab 이슈를 생성 하게 되면 이슈 번호가 지정되는데, Commit 을 할 때 특정 명령어와 이 이슈번호를 사용하면 Commit을 할 때 이슈를 자동으로 닫게 할 수 있습니다.

만약 이슈 번호가 #79번 일때, "close #79" 또는 "fix #79" 처럼 입력하게 된다면 commit 을 하면 이슈도 자동으로 닫히게 됩니다.

만약 다른 방식으로 닫게 하고 싶거나 추가하고 싶다면 config/gitlab.ymlissue_closing_pattern 에 지정하면 됩니다.


📒 느낀점

DB 설계를 그냥 머리에서 떠오르는 대로 시작했더니 결국 DB를 다시 뜯어고치는 일이 생겼다.

처음부터 DB 설계를 짜고, 진행할 일 들을 미리 구상했으면 뜯어고치는 일을 없애거나 최소화 할 수 있을 것 같아 다음번엔 꼭 진행할 예정에 맞춰 설계를 한 후, 스키마를 작성해야겠다.

그리고 이슈를 작성하고, commit 하고, merge 한 후, 이슈를 직접 닫아 줬었는데 GitLab에서 작성한 이슈를 commit 으로 자동으로 닫게 할 수 있다는걸 알고 역시 아는 만큼 편하고 효율성 높게 작업할 수 있다는 걸 다시 한번 느껴 내가 사용하는 툴 들의 기능을 한번 더 공부해봐야겠다.

처음 3계층 구조 설계로 폴더를 나눈 후 코드를 작성하는데 여기서 작성하고 저기서 작성하고 처음에는 헷갈리고 힘들었지만, 적응하고 나니 내가 원하는 부분을 편집할 때 딱 그 부분만 가서 수정하면 되는 것을 몸으로 느끼자 평소에 한 곳에 짜는 것 보다 훨씬 편하게 느껴졌다.

앞으로 다른 프로젝트를 진행할 때는 다른 구조도 사용해봐야겠다.

profile
누군가의 선택지가 될 수 있는 사람이 되자

0개의 댓글