영원 웹 개발과 일상

DevTip - UUID vs Auto Increment

#[DevTip] UUID vs Auto Increment

👓 UUID 가 뭐죠

UUID 는 간단하게 범용 고유 식별자라고 생각하면 편할것 같습니다.

예를 들어 내가 뭔가 만들 때마다 식별할 수 있는 고유값을 만들고 싶다면 사용하면 됩니다.

문서를 만들고 문서의 고유 식별자를 만들 때도, 회원가입을 하고 유저의 고유 식별자를 만들 때도

UUID 를 만드는 함수 하나 가져와서 그냥 쓰면 만사 ok.

물론 UUID 는 유일을 보장 한다는 것은 아닙니다.. UUID 는 실질적으로 유일함 을 목적으로 하고 있고 실제로 대부분의 상황에서 그러합니다.

이게 가능한 이유가 UUID 는 16 바이트의 문자로 이루어집니다. 비교해보자면 c 언어에서 integer 타입은 대략 -21억 ~ 21억 사이로 표현이 가능합니다. 반면 UUID 는 10의 38승까지, 정확히 340,282,366,920,938,463,463,374,607,431,768,211,456 개가 생성 가능합니다.

감이오시쥬~??

👓 Auto increment primary keys ??

Auto increment primary key 는 프로그램적으로 문제가 없는 한, 유일을 보장 합니다.

다만 너무 많은 id가 생성되면 아닐 보장하지 않을 수도 있습니다. 하지만 우리는 40억개 이상 생성하지 않을꺼야!! 라고 생각하고… 또한 키를 Integer 가 아니라 더 큰 타입으로도 생성할 수 있기 때문에…

단순히 1부터 시작해서 숫자를 늘려가거나, 원하는 숫자의 식별자를 만들어내는 방식입니다.

🍗 UUID vs Auto Increment

단점 먼저!

UUID

  • 가장 치명적인 단점은 성능에 저하를 일으킨다는 겁니다. 예들들어 각각 primary key 가 3,2,4,1,5 인 데이터를 삽입하고 검색의 효율을 위해 id를 정렬 한다고 칩시다. 그럼 1,2,3,4,5 순서로 저장이 되겠습니다. 자 이제 저 숫자가 16바이트의 엄청 큰 문자열이라고 생각해봅시다. 정렬하는 비용이 생각보다 많이 들 것입니다.
  • 사람이 보기 힘듭니다.
  • 필요 이상으로 공간을 많이 차지 합니다.

Auto Increment

  • Auto Increment 방식은 분산 시스템에서 적합하지 않습니다. 게임서버를 예로 들어봅시다. 서버 A와 서버 B 를 통합하려 합니다. 그런데 서버 A와 서버 B를 별개로 두었기 때문에 서버 A 에 있는 Id가 서버 B 에도 존재할 수 있습니다. 통합하려면 상당히 고생해야할지도 모릅니다 ^^;;

장점은?

UUID

  • Auto Increment 와는 반대로 분산 시스템에서 괜찮습니다.
  • 개발 환경에 독립적입니다. 어떤 디비를 쓰던 상관 없이 그냥 uuid 생성 함수 가져와서 쓰면 됩니다. 즉 DB를 바꿀 때 그냥 Id 갖다 박으셔도 됩니다.

Auto Increment

  • 빠릅니다.
  • 눈에 보기 쉽습니다. 로그를 분석하는데 “509ca884-67cc-…’” 어쩌고 나오면 갑자기 머리 아파집니다.

사실 id 숫자가 40억개 이상 쓸 일이 없을거야!! 하면 그냥 Auto Increment 쓰셔도 무방합니다.

필요에 따라 UUID 를 쓰세요!! 꼭 UUID 일 필요는 없습니다. 상황에 맞게 쓰시면 될거 같네요!


피드백은 항상 환영입니다!!


leetcode Multiply Strings 문제풀기

#[leetcode][43] Multiply Strings 문제풀기!



👓 문제 요약

숫자 두개를 문자열로 줄테니 곱해줘!

근데 숫자가 엄청 커 ㅎㅎ;;;

자세한 문제 설명과 릿코드 홈페이지 참고. 문제풀러가기

🔑 문제 풀이

BigInteger 를 쓰면 매우 쉽지만, 그러라고 문제 푸는거 아니잖아 ? ? ?

저는 학창시절 때 배웠던 곱셈 방식을 이용했습니다!

    1 2 3
    4 5 6
ㅡㅡㅡㅡㅡ
    7 3 8
  6 1 5 0
4 9 2 0 0
ㅡㅡㅡㅡㅡ
5 6 0 8 8

이런 식으로 중간 단계를 두어 123 * 6, 123 * 5, 123 * 4 를 한 후 한 자리씩 더해주었습니다.

🥽 소스코드 및 소스해석

var multiply = function (num1, num2) {
  let answer = "";
  if (num1 === "0" || num2 === "0") return "0";

  for (let i = num2.length - 1; i >= 0; i--) {
    answer = strPlus(answer, subMultiply(num1, num2[i], num2.length - i - 1));
  }
  return answer;
};

const subMultiply = (str1, target, pos) => {
  let result = [];
  let carryOut = 0;
  for (let i = str1.length - 1; i >= 0; i--) {
    let value = +str1[i] * target + carryOut;
    carryOut = parseInt(value / 10);
    result.push(value % 10);
  }
  if (carryOut !== 0) {
    result.push(carryOut);
  }
  let gather = "";
  for (let i = result.length - 1; i >= 0; i--) {
    gather += result[i];
  }
  for (let i = 0; i < pos; i++) {
    gather += "0";
  }
  return gather;
};
const strPlus = (str1, str2) => {
  // str2가 커야한다
  if (str1.length > str2.length) {
    let temp = str1;
    str1 = str2;
    str2 = temp;
  }
  if (str1.length === 0) return str2;
  let result = [];
  let carryOut = 0;
  let diff = str2.length - str1.length;
  for (let i = str2.length - 1; i >= 0; i--) {
    let str1Int = i - diff >= 0 ? +str1[i - diff] : 0;
    let value = str1Int + +str2[i] + carryOut;
    carryOut = parseInt(value / 10);
    result.push(value % 10);
  }
  if (carryOut !== 0) {
    result.push(carryOut);
  }
  let gather = "";
  for (let i = result.length - 1; i >= 0; i--) {
    gather += result[i];
  }
  return gather;
};

🔨 문제 후기

제가 쓴 코드는 상당히 지저분한 코드입니다 ㅜㅜ..

저번에도 말했지만 간결할 수록 버그도 적어진다!!

분명 줄일 수 있는, 간결해질 수 있는 방법이 있을 것이다. 함수화를 한다던가? 한번 찾아보고 코드를 줄이면 문서를 다시 수정하겠습니다!


leetcode Trapping Rain Water 문제풀기

#[leetcode][42] Trapping Rain Water 문제풀기!



👓 문제 요약

내가 말이야.. 특이한 목욕탕을 만들고 싶거든.. 근데 물이 얼마나 필요할지 잘 모르겠어.. 니가 좀 구해줄래?

자세한 문제 설명과 릿코드 홈페이지 참고. 문제풀러가기

🔑 문제 풀이

대표적으로 이런 문제는 대부분 2 pointer 문제더라!!

일단 물 높이를 생각해봅시다!!. 인풋이 [2 ,0 ,0 ,3] 이렇게 주어지면, 왼쪽 기둥은 높이가 2, 오른쪽 기둥은 3 이다. 따라서 물을 다 채우면 왼쪽이 오른쪽 보다 낮기 때문에 높이 2까지만 채워집니다.

이 원리를 이용해 왼쪽에서 오른쪽 방향으로 하나씩 참고하는 포인터와 반대로 오른쪽에서 왼쪽 방향으로 참고하는 포인터를 생성합니다!.

만약 왼쪽에서 하나씩 보다가 현재 기둥이 오른쪽에서 참조하는 기둥의 높이보다 낮거나 같으면 한 칸 물을 채워주고, 반대로 오른쪽 기둥이 더 낮으면 오른쪽에서 물을 채워주는 형식으로 진행합니다. 채워주는 양은 현재 물의 높이 - 현재 기둥의 높이라고 생각하면 되겠습니다!. 물을 낮은 곳 부터 차근차근 채워나간다고 생각하면 편하겠군요.

왼쪽에서 먼저가던 오른쪽으로 가던 어느쪽으로 기준을 잡던 상관이 없지만 저는 왼쪽으로 기준 삼았습니다!.

그래서 제가 어떻게 풀었냐면 !!

물을 채울 때 높이가 가장 중요하다. 물의 높이는 왼쪽 기둥과 오른쪽 기둥의 높이를 비교하여 낮은 값과, 이때까지 물의 높이 중 더 큰 값을 선택하면 됩니다. 알아보기 쉽게 다음과 같이 표현했습니다.

Math.max(fixH, Math.min(height[left], height[right]));
// fixH가 물의 높이다.

그런 다음 왼쪽 오른쪽 어디를 채울지 선택해 채우면 된다!!.!

🥽 소스코드 및 소스해석

var trap = function (height) {
  let answer = 0;
  let left = 0;
  let right = height.length - 1;
  let fixH = 0;
  while (left < right) {
    fixH = Math.max(fixH, Math.min(height[left], height[right]));
    if (height[left] <= fixH) {
      answer += fixH - height[left];
      left++;
    } else {
      answer += fixH - height[right];
      right--;
    }
  }
  return answer;
};

🔨 문제 후기

재미있다.

처음에 저는 상당히 긴 코드를 작성했었습니다. 제가 워낙 설계하지 않고 풀다보니 깔끔하게 풀지를 못해서 중간에 값을 변경하고 또 변경하다가 문제를 통과했습니다.

다른분들이 푼 아주 깔끔한 소스를 보고 약간의 자괴감이 드는 한편 또 깨닳음이 있었습니다.

코드가 간결해 질수록 버그도 적어진다!!

앞으로 간결하게 코드를 작성하도록 노력해야할 듯 합니다 !!


leetcode Combination Sum II 문제풀기

#[leetcode][40] Combination Sum II 문제풀기!



👓 문제 요약

숫자들을 줄게. 그 숫자들을 조합해서 내가 원하는 숫자가 나오는 조합을 찾아줘!

단, 그 찾은 조합끼리 중복이 있으면 안돼!! 그리고 특정 숫자를 내가 준 개수보다 더 많이 쓰면 안돼!!!!

자세한 문제 설명과 릿코드 홈페이지 참고. 문제풀러가기

🔑 문제 풀이

모든 경우를 다 체크해서 만들어진다? 그 결과가 중복되지 않는다? 그럼 push 한다.

라는 방법이 있지만, 이 방법으로는 이미 풀어봤기 때문에 다른 방법을 찾아봤다!

그래서 제가 어떻게 풀었냐면 !!

정답에 중복이 되는 이유는 같은 숫자들끼리 아무런 구별 없이 길을 만들어 지나왔기 때문!!

같은 숫자를 쓰는 길은 한 번만 지나가게 하면 된다.!!!! 뚜둔

예를 들어

[1, 2, 2 ,2 ,5] , 5 라는 값이 주어졌다 하면,

1, 2, 5 를 지나가는 길은 오직 한 번만 체크하면 된다. 두 번째 2도 체크하고, 세 번째 2도 체크 할 필요가 없다.

🥽 소스코드 및 소스해석

var combinationSum2 = function (candidates, target) {
  candidates.sort((a, b) => a - b); // 오름차순
  let answer = [];
  /**
   * @param {number[]} candidates
   * @param {number[]} path
   * @param {number} start
   * @param {number} target
   */
  const dfs = (_candidates, path, start, _target) => {
    // 다음 값도 체크해야한다!
    if (_target === 0) {
      answer.push(path);
      return;
    }
    if (_target < 0 || start > _candidates.length - 1) return;

    let next = start;
    while (_candidates[start] === _candidates[next]) next++;

    dfs(_candidates, path, next, _target);

    path.push(_candidates[start]);
    dfs(_candidates, [...path], start + 1, _target - _candidates[start]);
    path.pop();
  };
  dfs(candidates, [], 0, target);

  return answer;
};

🔨 문제 후기

재미있다.

다른 사람의 풀이 보는 것도 재미있다. 세상에는 천재는 넘치고 내 시간은 부족하다.


NestJS 블로그 만들기 - CRUD 로 시작하자.

2. NestJS 블로그 만들기 - CRUD 로 시작하자.


👌 NestJS 블로그 만들기 시리즈의 목적

저는 NestJS 전문가가 아닙니다. 저 또한 NestJS 로 어플리케이션을 만들려고 한지 한달이 채 되지 않았습니다.

다만 제가 공부하면서 습득하고 이해한 내용을 바탕으로 간단한 어플리케이션을 만들며 기본적인 지식을 여러분께 같이 공유하는 것이 제 목적입니다.

대부분의 정보는 NestJS Doc , Github 를 참고하고 있습니다.

이 시리즈는

  • CRUD 기능
  • Postgresql DataBase 연결
  • Auth
  • 메시지 큐
  • 기타 기능 (카톡 공유, 카톡으로 로그인하기 등)

의 내용을 다룰 것 입니다.

요구사항은 다음과 같습니다.

requirement

지속적으로 업데이트 할 예정이니 제 Github repository를 참고해주세요.

사용하는 IDE 는 VSCode 입니다.

이후 추가할 사항이나 유용한 팁이 있다면 더 추가하겠습니다.

궁금한 사항이나 제가 틀렸다고 생각하는 부분이 있다면 언제든 피드백 해주세요.


🛴 NestJS 어플리케이션 시작하기.

NestJS 는 Javascript 기반 Typescript 언어를 주로 다룹니다. Javascript 환경을 위해서 Node.js 가 설치되어 있는지 먼저 확인해주세요.

Node.js 설치하기

NestJS 설치를 위해 다음 명령어를 터미널에서 실행해주세요.

$ npm i -g @nestjs/cli

설치가 정상적으로 되었다면 이제 프로젝트 폴더를 만들어 봅시다. project-name 은 원하시는데로 하면 됩니다. 저희는 nestjs-practice 라고 지어보죠.

$ nest new nestjs-practice

패키지 매니저는 npm 을 사용하겠습니다. (그대로 엔터 눌러주면 됩니다.)

👓구조 살펴보기

src
  app.controller.spec.ts
  app.controller.ts
  app.module.ts
  app.service.ts
  main.ts

src 폴더에는 앱의 코드들이 모여있다고 생각하시면 됩니다. 각 역할을 보자면

  • app.controller.spec.ts : spec 이 붙은 파일들은 테스트 파일입니다. 지금은 무시하셔도 됩니다.
  • app.controller.ts : 앱의 request 와 response 를 담당하는 라우팅 관련 파일입니다.
  • app.module.ts : 앱을 구성하는 구조의 메타데이터를 담당하는 파일입니다.
  • app.service.ts : 앱의 비지니스 로직을 담당하는 파일입니다.

앞으로 모든 앱의 구성요소들은 위와 같은 형태로 만들어질거에요!!

최상의 폴더의 다른 파일들은 구성 요소를 담당하는 녀석이에요. 예를 들면 typescript 환경설정 파일 또는 패키지 의존성 관리파일 같은 것들이에요.!!

🔨기능 만들어보기

nest cli 는 정말 유용한 기능들을 많이 지원합니다. nest generate 기능을 이용하면 자주 사용하는 용도의 템플릿을 생성할 수 있습니다. 다음은 nest generate | g 를 이용해 만들 수 있는 명령어들입니다.

  ┌───────────────┬─────────────┬──────────────────────────────────────────────┐
  │ name          │ alias       │ description                                  │
  │ application   │ application │ Generate a new application workspace         │
  │ class         │ cl          │ Generate a new class                         │
  │ configuration │ config      │ Generate a CLI configuration file            │
  │ controller    │ co          │ Generate a controller declaration            │
  │ decorator     │ d           │ Generate a custom decorator                  │
  │ filter        │ f           │ Generate a filter declaration                │
  │ gateway       │ ga          │ Generate a gateway declaration               │
  │ guard         │ gu          │ Generate a guard declaration                 │
  │ interceptor   │ in          │ Generate an interceptor declaration          │
  │ interface     │ interface   │ Generate an interface                        │
  │ middleware    │ mi          │ Generate a middleware declaration            │
  │ module        │ mo          │ Generate a module declaration                │
  │ pipe          │ pi          │ Generate a pipe declaration                  │
  │ provider      │ pr          │ Generate a provider declaration              │
  │ resolver      │ r           │ Generate a GraphQL resolver declaration      │
  │ service       │ s           │ Generate a service declaration               │
  │ library       │ lib         │ Generate a new library within a monorepo     │
  │ sub-app       │ app         │ Generate a new application within a monorepo │
  │ resource      │ res         │ Generate a new CRUD resource                 │
  └───────────────┴─────────────┴──────────────────────────────────────────────┘

예들 들면

nest g module catiscute

위 명령어는 catiscute 라는 모듈을 자동으로 생성해줍니다. 어때요 정말 유용하죠? !!

자아아아 저기 저기 CRUD 보이시나요? resource 라는 명령어를 이용하시면 CRUD 에 필요한 템플릿을 얻을 수 있습니다.!!!!! 우후 ~ 박수박수 진짜 어메이징 합니다. 여러분 이 명령어로 바로 템플릿 얻는 거는 진짜 놀라운거에요!!

이제 users 라는 CRUD 기능을 만들어보죠.

nest g res users

를 입력해봅시다. 와우 폴더 보이시나요?? !! 보이시나요!!! 한 가지 더 말하자면 app.module.ts 파일에 자동으로 UsersModule 이 추가되었습니다.!!! 와 미쳐따 미쳐따… 진짜 편리하다 … 🙀

우리는 이제 유저에 관한 기본적인 CRUD 기능을 수행할 수 있습니다. 우후~

한 번 앱을 실행해볼까요??

npm run start

어랏 ?!?!? 저는 이런 에러가 떳습니다. nest 가 생성해준 파일에 우리가 설치하지 않은 node 모듈이 있나보네요!!

1 import { PartialType } from '@nestjs/mapped-types';
                              ~~~~~~~~~~~~~~~~~~~~~~

다음 명령어를 통해 설치해주자구요!!

npm install @nestjs/mapped-types --save

설치가 되면 다시

npm run start

유후~ 이번엔 에러가 없습니다!!!!! 로그를 보시면

[Nest] 35604   - 2021-01-22 11:31:13 ├F10: AM┤   [NestFactory] Starting Nest application...
[Nest] 35604   - 2021-01-22 11:31:13 ├F10: AM┤   [InstanceLoader] AppModule dependencies initialized +24ms
[Nest] 35604   - 2021-01-22 11:31:13 ├F10: AM┤   [InstanceLoader] UsersModule dependencies initialized +2ms
[Nest] 35604   - 2021-01-22 11:31:13 ├F10: AM┤   [RoutesResolver] AppController {}: +8ms
[Nest] 35604   - 2021-01-22 11:31:13 ├F10: AM┤   [RouterExplorer] Mapped {, GET} route +4ms
[Nest] 35604   - 2021-01-22 11:31:13 ├F10: AM┤   [RoutesResolver] UsersController {/users}: +1ms
[Nest] 35604   - 2021-01-22 11:31:13 ├F10: AM┤   [RouterExplorer] Mapped {/users, POST} route +0ms
[Nest] 35604   - 2021-01-22 11:31:13 ├F10: AM┤   [RouterExplorer] Mapped {/users, GET} route +9ms
[Nest] 35604   - 2021-01-22 11:31:13 ├F10: AM┤   [RouterExplorer] Mapped {/users/:id, GET} route +0ms
[Nest] 35604   - 2021-01-22 11:31:13 ├F10: AM┤   [RouterExplorer] Mapped {/users/:id, PUT} route +1ms
[Nest] 35604   - 2021-01-22 11:31:13 ├F10: AM┤   [RouterExplorer] Mapped {/users/:id, DELETE} route +0ms
[Nest] 35604   - 2021-01-22 11:31:13 ├F10: AM┤   [NestApplication] Nest application successfully started +2ms

RouteExplorer 를 보시면 users 에 관련된 매핑들을 볼 수 있습니다!!

이제 편하신 브라우저를 키시고 http://localhost:3000 로 접속하시면!!

아무런 설정 안하셨으면 앱의 기본 포트는 3000 입니다!!

Hello World! 사실 이 페이지를 보는게 목적이 아니기 때문에 링크 뒤에 /users 를 입력해봅시다

가보자구요!! http://localhost:3000/users This action returns all users

가보자구요!! http://localhost:3000/users/1 This action returns a #1 user

모야모야~ 벌써 된거야? 우리 뭐 한것도 없는데??

nest 정말 편한 기능들이 많습니다. 다만 우리가 원하는건 단순히 저런 문자가 아니라 진짜 유저 정보겠죠?

다음 시간에는 데이터베이스에 연결해서 진짜 유저 정보를 만들고 가져오고 수정하고 삭제하고를 배워보겠습니다.

🔨 좀 더 살펴보기

자 근데 우리 여기서 마치면 좀 찝찝하잖아요? 그러셔야 합니다. 그럴거에요. 그래서 준비했습니다!!

코드와 구조를 조금 더 살펴보겠습니다.

users
    │  users.controller.spec.ts
    │  users.controller.ts
    │  users.module.ts
    │  users.service.spec.ts
    │  users.service.ts
    │
    ├─dto
    │      create-user.dto.ts
    │      update-user.dto.ts
    │
    └─entities
            user.entity.ts

spec 이 붙은 파일은 테스트 파일입니다. 다음에 테스트 할 때 살펴보겠습니다!

dto 에 관한 내용과 entities 에 관한 내용은 다음번에 데이터베이스 연결하고 알아보겠습니다.

그럼 service, controller, module 에 대해서 한번 살펴보죠.

🍔Service

Service 파일은 비지니스 로직을 처리하는 파일이라고 했습니다. UserService 클래스 안을 살펴 보시면 create, findAll, findOne, update, remove 함수들이 있습니다. 여기서 리턴하는 문자열이 우리가 브라우저에서 본 문자들이죠?

그리고 클래스 위에 @Injectable() 이라는 Decorator 가 있습니다.

Decorator 는 기능을 확장할 때 쓰일 수 있는 디자인 패턴입니다. 데코레이터 패턴이 뭔가요?

Injectable 데코레이터는 다른 클래스에 constructor 를 통해 이 클래스를 Inject 하기 위한 데코레이터로 DI(Dependency Injection) 기능을 사용하기 위해 쓰입니다.

Controller 파일을 보면 더 이해가 잘 될겁니다!

🌭Controller

Controller 파일은 라우팅을 처리하는 파일입니다. 일단 UsersController 클래스 안에 constructor 를 보시면. userService타입만 지정했습니다.

그럼에도 불구하고 create 함수에서 이 this.userService.create 를 호출하고 있는데요.

이게 어떻게 가능한 것이냐면 바로 Nest 의 훌륭한 DI 시스템 때문입니다.

DI 는 간단하게 NestJS 의 틀에 맞게 우리가 어떤 값을 지정해주면 NestJS 가 알아서 컨트롤 해주는 기능입니다.우리 UserService 부분에서 Injectable 데코레이터를 통해 UserService 를 Injectable 한 provider 로 지정했습니다.따라서 UserController 클래스 내의 constructor 에서 단순히 userService 의 타입을 UserService 로 지정해줌으로서NestJS가 알아서 this.userService 의 생성과 소멸을 관리하게 됩니다.

와 미쳐따 미쳐따!!! 정말 편하다!!

아직 몇 가지 더 봐야할 것이 있습니다.

바로 @Controller 데코레이터 입니다. 데코레이터에서 “users” 라고 지정해주고 있습니다. 이 말은 바로!

/users 라는 주소로 요청이 들어오면 이 클래스에서 처리하겠다

라는 뜻입니다. 우리는 UserController 를 app 모듈에 갔다 붙였으니 주소는 localhost:3000/users 가 되겠죠??.

이후 UsersController 내의 함수를 보면

@Post, @Get, @Put, @Delete 데코레이터들이 보입니다.

이름에서도 유추할 수 있듯이 /users 에 해당하는 메서드로 들어오면 이 함수에서 처리하겠다. 라는 뜻 입니다.

users 이후 매핑도 지정할 수 있는데요. @Get(“:id”) 라는 데코레이터는 /users/:id 로 들어온 요청을 이 함수에서 처리하겟다 라는 뜻 입니다.

정말 직관적이죠?? 우후~

’:’ 로 시작하는 문자열은 파라메터라는 값으로 인식하겠다는 뜻입니다. findOne 을 보시면 함수 인자 값에 @Param(‘id’) 이라는 데코레이터를 붙여 :id 위치의 값을 id 라는 값에 할당하는 과정을 볼 수 있습니다.

또한 비슷하게 @Body 데코레이터는 request body 의 내용을 변수에 할당하겠다는 뜻 입니다.

정말 쉽다쉽다!!

🥣Module

UsersModule 클래스는 이 users 라는 폴더 안의 모듈을 관리하는 클래스입니다. 이 모듈의 controllers 는 UsersController 클래스를 통해 관리하겠다! 이 모듈의 providers 는 UserService 클래스를 통해 관리하겠다 !!

잘 보시면 배열의 값이므로 복수의 값을 할당할 수 있습니다!!

이 UsersModule 을 app 모듈에서 imports 하고 있기 때문에 app 이 UserModule 을 인식할 수 있던 것 입니다!!

다른 값에 대해서는 이후 포스트에서 다루겠습니다.


자 여러분 정말 쉽고 직관적으로 되어있지 않나요? 제가 NestJS 를 좋아하게 된 이유 이기도 합니다.!!

다음에는 Postgresql 데이터베이스를 이용해 진짜 user 정보를 저장해보자구요!

피드백은 항상 환영입니다!!