[Node.js_4기] TIL : Layered Architecture Pattern (yy/mm/dd)

2024. 2. 19. 20:33공부/내배캠 TIL

목차

 

1. 학습 내용

2. 내용 정리

3. 예제

4. 생각 정리

 

1. 학습 내용 

 

1. 아키텍쳐 패턴

2. 계층형 아키텍처 패턴

 

2. 내용 정리 

 

01. 아키텍쳐 패턴

1) 개념

소프트웨어 구조를 구성하기 위한 기본적인 형태 제시

각각의 시스템과 그 역할이 정의되어 있고, 시스템 사이의 관계와 규칙등이 포함되어 있다.

검증된 구조로 안정적인 개발이 가능, 복잡한 도메인 문제 해결시 큰 이득을 얻을 수 있다.

 

2) 예시

MVC (Model, View, Controller)

계층형 아키텍처 패턴 (Controller, Service, Repository)

클린 아키텍처 패턴 (소프트웨어를 내부 도메인으로 향하는 의존성을 가진 여러 계층으로 분리)

마이크로 서비스 아키텍처 패턴 (시스템을 작고 독립적인 배포 가능한 서비스로 분할)

 

3) 아키텍처 패턴 도입 전 고민해야 할 것

- 아키텍처 패턴 도입에 대한 확실한 이유 필요(개발 이점, 비용 절감 등)

- 해당 아키텍처 패턴의 장단점을 명확하게 인지

- 계층을 추가하기 위해 들이는 노력과 시간 투자에 가치가 있을 정도로 어플리케이션과 도메인이 복잡한 경우에만 도입.

(가벼운 프로젝트에 도입시 의미없는 코스트 소모)

 

02. 계층형 아키텍처 패턴

1) 계층형 아키텍처 패턴 :

시스템을 여러 계층으로 분리하여 관리. 각 계층을 명확하게 분리하고, 자신 바로 아래 계층에만 의존하게 만듦.

단순하고 대중적이며 비용도 적게 드는 표준 아키텍처. 패턴 도입에 대한 확신이 없을 경우 좋은 선택지

- > 각 계층이 높은 응집도를 가지면서, 결합도는 최소화 하는 것이 핵심.

 

2) 장점

- 관심사를 분리하여 현재 코드의를 명확하게 인지 가능

- 계층간 독립적이기 때문에 모듈 교체시 코드 수정이 용이

- 계층별 단위테스트가 가능하여 테스트코드를 더 용이하게 구성 가능

 

3) 구성

_1. 컨트롤러 : 요청을 수신하고 결과를 반환해주는 역할.

= 클라이언트의 요청 수신, 처리는 서비스에게 위임 / 클라이언트에게 응답을 반환

_2. 서비스 : 비즈니스 로직이 수행되는 부분(핵심)

= 요청을 처리(기능이 계속 확장되는 문제가 발생할 수 있음), 저장소에게 데이터를 요청 / 서비스 결과를 컨트롤러에 전달

_3. 저장소 : 실제 DB와 통신하는 계층

= DB관리(연결, 해제, 자원 관리), CRUD 담당. / 데이터를 서비스에게 전

 

logical flow )

클라이언트가 어플리케이션에 요청 -> 요청을 알맞은 컨트롤러가 수신 -> 컨트롤러가 서비스 호출 -> 서비스가 저장소에게 데이터 요청 -> 서비스는 데이터를 가공하여 컨트롤러에 전달 -> 컨트롤러가 서비스 결과물을 클라이언트에게 전달

 

3. 예제 

 

라우터

import express from 'express';
import { PostsController } from '../controllers/posts.controller.js';

const router = express.Router();
const postsController = new PostsController();

router.get('/', postsController.getPosts);
router.post('/', postsController.createPost);

export default router;

 

컨트롤러

import { PostsService } from '../services/posts.service.js'; // 서비스에 의존

export class PostsController {
  postsService = new PostsService(); 
  
  getPosts = async (req, res, next) => {
    try {
      const posts = await this.postsService.findAllPosts();
      return res.status(200).json({ data: posts });
    } catch (err) {
      next(err);
    }
  };

  createPost = async (req, res, next) => {
    try {
      const { nickname, password, title, content } = req.body;
      const createdPost = await this.postsService.createPost(
        nickname,
        password,
        title,
        content,
      );
      return res.status(201).json({ data: createdPost });
    } catch (err) {
      next(err);
    }
  };
}

 

서비스

import { PostsRepository } from '../repositories/posts.repository.js'; // 저장소에 의존

export class PostsService {
  postsRepository = new PostsRepository();

  findAllPosts = async () => {
    const posts = await this.postsRepository.findAllPosts();

    posts.sort((a, b) => {
      return b.createdAt - a.createdAt;
    });

    return posts.map((post) => {
      return {
        postId: post.postId,
        nickname: post.nickname,
        title: post.title,
        createdAt: post.createdAt,
        updatedAt: post.updatedAt,
      };
    });
  };

  createPost = async (nickname, password, title, content) => {
    const createdPost = await this.postsRepository.createPost(
      nickname,
      password,
      title,
      content,
    );
    return {
      postId: createdPost.postId,
      nickname: createdPost.nickname,
      title: createdPost.title,
      content: createdPost.content,
      createdAt: createdPost.createdAt,
      updatedAt: createdPost.updatedAt,
    };
  };
}

 

저장소

import { prisma } from '../utils/prisma/index.js'; // DB와 직접 연결

export class PostsRepository {
  findAllPosts = async () => {
    const posts = await prisma.posts.findMany();

    return posts;
  };

  createPost = async (nickname, password, title, content) => {
    const createdPost = await prisma.posts.create({
      data: {
        nickname,
        password,
        title,
        content,
      },
    });

    return createdPost;
  };
}

 

4. 생각 정리 

 

이전에 스터디에서 잠깐 봤던 프로그래밍 아키텍처에 대한 공부를 했습니다.

코드가 꼬여있던 이전의 프로젝트를 리팩토링 하는 것이 이번주의 과제입니다.

라우터 js파일에 서비스와 저장소 코드가 함께 들어가 있던 코드를 수정하는 중입니다만...

TypeError: Cannot read properties of undefined (reading 'map')
    at UsersService.findEmailUser (file:///C:/Users/DongWon/Desktop/sparta/PROJECT/Layered_architecture_prac/src/services/users.service.js:8:21)
    at async signUp (file:///C:/Users/DongWon/Desktop/sparta/PROJECT/Layered_architecture_prac/src/controllers/users.controller.js:55:30)

다양한 오류가 터져나오고 있습니다.

이번주도 일찍 자긴 글렀습니다...