1. Decorator
- Nest는 Decorator를 적극 활용한다.
- 이를 잘 활용하면 횡단 관심사(cross-cutting concern)를 분리하여 관점 지향 프로그래밍(Aspect Oriented Programming AOP)을 적용한 코드를 작성할 수 있다.
횡단 관심사 : 모든 핵심관심사항에 공통적으로 들어가는 코드/로직
https://choi3950.tistory.com/32
-우선 Decorator를 사용하기 위해 tsconfig.json파일에서 다음 옵션을 true로 지정해 주어야 한다.
tsconfig.json
{
"compilerOptions": {
...
"experimentalDecorators":true
...
}
}
- Decorator는 @expression과 같은 형식으로 사용된다.
- 여기서 expression은 decorating된 선언(decorator가 선언되는 클래스, 메서드)에 대한 정보와 함께 런타임에 호출되는 함수여야 한다.
- 다음 코드를 보면 test 메서드의 데코레이터 팩토리(데코레이터 함수를 감싸는 wrapper 함수)로 deco를 선언했다.
- deco 함수를 데코레이터로 사용하기 위해서는 함수의 인자를 다음과 같이 정의해야 한다. (설명은 나중에)
fucntion deco(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log('데커레이터 평가됨');
}
class TestClass {
@deco
test() {
console.log('함수 호출됨')
}
}
const t = new TestClass();
t.test();
- 이제 클래스를 생성하고 test 메소드를 호출하면 다음과 같은 결과가 출력된다.
데커레이터가 평가됨
함수 호출됨
- 만약 decorator에 인수를 넘겨서 decorator의 동작을 변경하고 싶다면 decorator를 리턴하는 함수를 만들어 주면 된다.
fucntion deco(value: string) {
console.log('데커레이터 평가됨');
return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log(value);
}
}
class TestClass {
@deco('HELLO')
test() {
console.log('함수 호출됨')
}
}
const t = new TestClass();
t.test();
데커레이터가 평가됨
HELLO
함수 호출됨
Decorator 합성
- 여려 개의 Decorator를 사용한다면 수학의 함수 합성과 같이 Decorator를 합성하게 된다.
- 다음 Decorator 선언의 합성 결과는 수학적으로는 f(g(x))와 같다.
@f
@g
test()
- 여러 Decorator를 사용할 때는 다음과 같은 단계가 수행된다.
1. 각 Decorator의 표현은 위에서 아래로 평가 된다.
2. 그런 다음 결과는 아래에서 위로 함수로 호출 된다.
function first() {
console.log("첫번째 함수가 평가되었습니다.");
return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("첫번째 함수가 호출되었습니다.");
};
}
function second() {
console.log("두번째 함수가 평가되었습니다.");
return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("두번째 함수가 호출되었습니다.");
};
}
class TestClass {
@first()
@second()
test() {
console.log('test 함수 호출됨');
}
}
const t = new TestClass();
t.test();
첫번째 함수가 평가되었습니다.
두번째 함수가 평가되었습니다.
두번째 함수가 호출되었습니다.
첫번째 함수가 호출되었습니다.
test 함수 호출됨
타입스크립트가 지원하는 5가지 Decorator
1) 클래스 Decorator
- 클래스Decorator는 말 그대로 클래스 앞에 선언된다.
- 클래스 Decorator는 클래스의 생성자에 적용되어 클래스의 정의를 읽거나 수정할 수 있다.
- 선언 파일과 선언 클래스 내에서는 사용할 수 없다.
//클래스 Decorator 팩터리이다. 생성자 타입을 상속받는 제네릭 타입 T를 가지는 생성자를 팩터리 메서드의 인수로 전달하고 있음.
function reportableClassDecorator<T extends { new (...args: any[]) }>(constructor: T)
{
//클래스 Decorator 생성자를 리턴하는 함수여야 함.
return class extends constructor {
//해당 클래스 Decorator 적용되는 클래스에 새로운 reportingURL이라는 새로운 속성을 추가한다.
reportingURL = 'http://www.example.com';
};
}
@reportableClassDecorator
class BugReport {
type = 'report';
title = 'test';
constructor(t: string) {
this.title = t;
}
}
const bug = new BugReport();
console.log(bug);
{type = 'report', title = 'test', reportingURL = 'http://www.example.com'}
- 결과를 보면 BugReport 클래스에 선언되지 않았던 새로운 속성이 추가되었다.
하지만 클래스의 타입이 변경되는것은 아님!
bug.reportingURL과 같이 직접 사용할 수 없다는 의미
2) 메서드 Decorator
- 메서드 Decorator는 메서드 바로 앞에 선언된다.
- 메서드의 속성 설명자에 적용되고, 메서드의 정의를 읽거나 수정할 수 있다.
-위에서 deco 메서드 Decorator에서 봤던 것처럼 메서드 Decorator는 다음 세 개의 인수를 가진다.
1. target: 정적 멤버가 속한 클래스의 생성자 함수이거나 인스턴스 멤버에 대한 클래스의 프로토타입
2. propertykey: 멤버의 이름
3. description: 멤버의 속성, PropertyDescriptor 타입을 가진다.
3) 접근자 Decorator
- 접근자 Decorator는 말 그대로 접근자 앞에 선언한다.
- 접근자의 속성 설명자에 적용되고 접근자의 정의를 읽거나 수정할 수 있다.
속성 설명자 : 객체의 속성들은 그 자체로 객체 내부의 정보와 기능을 표현한다. 이 객체가 읽기 전용인지, 나열될 수 있는지 등의 정보를 의미한다. Js에서는 이러한 속성의 세부적인 성질을 직접 설정하거나 조회할 수 있는 방법을 제공하는데 이때 사용되는 특수한 객체가 속성 설명자 이다.
- 다음 예시는 특정 맴버의 속성 설명자 값에 접근하는 코드이다.
function Enumerable(enumerable: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.enumerable = enumerable;
}
}
class Person {
// name은 외부에서 접근이 불가능한 Private 멤버.
constructor(private name: string) {}
// 게터 getName 함수는 열거가 가능하도록 한다.
@Enumerable(true)
get getName() {
return this.name
}
//세터 setName함수는 열거가 불가능하도록 한다.
@Enumerable(false)
set setName(name: string) {
this.name = name;
}
}
const person = new Person('KIM');
for(let key in person) {
console.log(`${key}: ${person[key]}`);
}
- 결과를 출력하면 getName은 출력되지만 setName은 열거하지 못하게 되었기 때문에 for문에서 Key로 받을 수 없다.
name: KIM
getName: KIM
4) 속성 Decorator
- 속성 Decorator는 클래스의 속성 바로 앞에 선언된다.
- 클래스의 속성이라 함은 클래스에 바인드 되는 모든 변수가 클래스 속성이다.
- 앞어서 다룬 메서드, 접근 제어자와 달리 속성 데코레이터 함수는 전달받는 인자가 총 2가지 이다.
1. target : 정적 멤버가 속한 클래스의 생성자 함수이거나 인스턴스 멤버에 대한 클래스의 프로토 타입
2. prop : 멤버의 이름
- 이친구는 나중에 추가적으로 좀 더 알아봐야 할것같습니다...
5) 매개변수 Decorator
- 매개변수 Decorator는 생성자 또는 메서드의 매개변수에 선언되어 적용된다.
1. target
2. prop
3. parameter_index : 매개변수가 함수에서 몇번째 위치에 선언되었는지를 나타내는 인덱스.
- 매개변수 Decorator는 단독으로 사용하는것 보다 Decorator와 함께 사용할 때 유용하게 쓰인다.
2. MVC 패턴
- MVC 패턴이란 Model-View-Controller의 약자로 애플리케이션을 세 가지 역할로 구분한 개발 방법론이다.
등장배경
- 우리가 간단한 게시판 사이트를 만드는 경우에는 한 파일 안에서 DB에 접속하고, 사용자에게 보여질 HTML 부분을 작성하면 되지만
- 네이버 사이트와 같은 대규모 사이트를 만드는 경우에는 위와 같은 방식으로 만들고 운영하기에는 힘들것이다.
- 요소와 기능들이 많아지고, 구조가 이것저것 얽힐수록 코드도 무진장 길어지고 난해해 질것이다.
- 프로젝트가 거대해지고 복잡해질때는 특정 기준으로 분리, 모듈화해서 접근하곤 하는데 (국가 기관을 입법, 사법, 행정으로 나누듯이)
- 웹 사이트에서는 Model, View, Controller. 즉 MVC란 접근법이 많이 사용된다.
1) MODEL
- 애플리케이션의 정보, 데이터를 나타낸다.
- DB, 처음 정의하는 상수, 초기화, 값, 변수 등을 뜻함.
- 비즈니스 로직을 처리한 후 모델의 변경사항을 컨트롤러와 뷰에 전달한다.
비즈니스 로직 : 회원가입 기능을 예시로 들었을때 중복 아이디가 있는지 없는지를 검사하기 위한 일련의 과정들을 비즈니스 로직, 검사 결과를 유저에게 단순히 텍스트나 다이얼 로그로 알려주는 것을 View 영역(Presentation)이라고 한다.
모델은 다음과 같은 규칙을 가지고 있다.
1 . 사용자가 편집하길 원하는 모든 데이터를 가지고 있어야 한다.
2. 뷰나 컨트롤러에 대해 어떤 정보도 알지 말아야 한다. -> 데이터 변경이 일어났을때 모델에서 화면 UI를 직접 조정해서 수정할 수 있도록 뷰를 참조하는 내부 속성 값을 가지면 안 된다.
3. 변경이 일어나면, 변경 통지에 대한 처리 방법을 구현해야만 한다. -> 데이터 변경 발생시 누군가(뷰/데이터 변경으로 인한 화면 변경, 컨트롤러/데이터 변경으로 인한 업데이터 로직)에게 전달해야 함.
2) VIEW
- 사용자에게 보여지는 부분, 즉 유저 인터페이스(User interface)를 의미한다.
- 쉽게 말해 데이터의 및 객체의 입력, 그리고 출력을 담당한다. -> 데이터를 기반으로 사용자들이 볼 수 있는 화면.
뷰에서는 다음과 같은 규칙들이 있다.
1. 모델이 가지고 있는 정보를 따로 저장해서는 아니된다. -> 뷰의 역할은 단순히 변경된 데이터내용을 화면에 표시하는 것.
2. 모델이나 컨트롤러와 같이 다른 구성 요소들을 몰라야 한다.
3. 변경이 일어나면 변경 통지에 대한 처리방법을 구현해야만 한다. -> 화면에서 사용자가 화면에 표시된 내용을 변경하게 될 경우 변경된 내용을 모델에게 통지할 로직이 필요하다.
3) CONTROLLER
- 모델과 뷰 사이를 이어주는 다리 역할을 한다.
- 위 규칙들을 보면 모델이나 뷰는 서로의 존재를 몰라야 한다.
- 변경사항을 외부로 알리고 수신하는 방법만 존재한다.
- 컨트롤러는 이를 중재하기 위해 모델과 뷰에 대해 알고 있어야 한다.
- 모델이나 뷰로부터 변경 내용을 통지 받으면 이를 각 구성 요소에게 통지해야 한다.
- 사용자가 어플리케이션을 조작하여 발생하는 변경 이벤트들을 처리하는 역할을 수행한다.
컨트롤러는 다음과 같은 규칙을 가지고 있다.
1. 모델이나 뷰에 대해서 알고 있어야 한다.
2. 모델이나 뷰의 변경을 모니터링 해야 한다.
그래서 왜 씀?
- 유지보수의 편리성 때문.
- 최초 설계를 꼼꼼하게 진행한 시스템이라도 유지보수가 발생하기 시작하면 각 기능간의 결합도(coupling)가 높아지는 경우가 발생한다.
- 결합도가 높아진 시스템은 유지보수 작업 시 다른 비즈니스 로직에 영향을 미치게 되므로 사소한 변경이 의도치 않은 버그를 유발할 수 있다.
-MVC 패턴을 가진 각 시스템의 각 컴포넌트는 자신이 맡은 역할만 수행 후, 다른 컴포넌트로 결과만 넘겨면 되기 때문에 결합도를 낮출 수 있다.
- 하지만 복잡한 대규모 프로그램의 경우 다수와 뷰와 모델이 컨트롤러를 통해 연결되기 때문에 컨트롤러가 불필요하게 커지는 현상이 발생한다.
- 복잡한 화면을 구성하는 경우에도 동일한 현상이 발생하는데 이를 'Massive-View-Controller'라고 한다.
https://junhyunny.github.io/information/design-pattern/mvc-pattern/
MVC(Model, View, Controller) Pattern
<br /><br />
junhyunny.github.io
3. Nest.js 찍먹
- NestJS는 Node.js에 기반을 둔 웹 API 프레임워크로서 Express 또는 Fastify 프레임워크를 래핑하여 동작한다. (Fastify가 속도가 빠르다는 장점이 있지만, Express가 가장 널리 사용되고 있고, 수많은 미들웨어가 NestJS와 호환되기 때문.)
Node.js 쓰면 되지 왜 Nest.js 씀?
- Node.js는 손쉽게 사용할 수 있고 뛰어난 확장성을 가지고 있다.
- 하지만 과도한 유연함으로 인해 소프트웨어의 품질이 일정하지 않고, 알맞은 라이브러리를 찾기 위해 사용자가 많은 시간을 할애해야 한다.
- 반면 Nest는 DB, 객체 관계 매핑(object-relational mapping, ORM), 설정, 유효성 검사 등 수많은 기능들을 기본 제공하면서 필요한 라이브러리를 쉽게 설치하여 기능을 확장할 수 있는 Node의 장점을 그대로 가지고 있다.
Express vs Nest
- Nest는 Express를 기본으로 채택하고 그 위에 여러 기능을 미리 구현해 놓은 것이다.
- Express는 가볍게 테스트용 서버를 띄우는 용도로 사용하면 좋다.
- 아이디어를 빠르게 검증하는데 좋지만, 단순하고 자유도가 높은 만큼 자기에 맞는 라이브러리를 찾기 위해 직접 찾아야 한다.
- Nest는 미들웨어, IoC, CQRS등 이미 많은 기능을 프레임 워크 자체에 포함한다.
- 원하는 기능이 있다면 다른 라이브러리를 적용해서 사용하면 된다.
Nest 디핑 소스 만들기
- Nest를 설치해 봅시다.
1) Node.js 설치
- Nest는 Node를 기반으로 한다. 따라서 Node도 설치해야 하는데,
노드는 알아서 깔아옵시다.
2) Nest 프로젝트 생성
- 우선 Nest.js 서버를 구성하기 위해 @nest/cli를 설치해보자.
$ npm i -g @nestjs/cli
i : install 의 약어
-g : 컴퓨터의 글로벌 환경에 설치하겠다는 의미. 모든 dir에서 해당 패키지를 실행할 수 있음. (글로벌 환경에서 패키지가 설치되는 경로로는 npm root -g 명렬어로 확인할 수 있다.)
- 설치가 끝났으면 프로젝트 생성을 해보자.
$ nest new proj-name
-생성이 끝난다면 보일러플레이트 코드가 생성될 것이다.
3) 서버를 실행
- 서버를 실행하기 위해 프로젝트가 설치된 경로로 이동한 후 다음 명령어를 입력하여 실행시켜 보자.
$ yarn install or npm install
$ yarn run start:dev
운영이 아닌개발 단계 에서는 :dev명령어를 추가로 붙여 이용하는것이 좋다 .( 소스 코드 변경을 감지하여 코드 저장할때마다 서버를 다시 구동할 수 있다.)
-브라우저 로컬 서버(http://localhost:3000/)에 접속하여 잘 동작하는지 확인해 보자.
'Back-End > Nest.js' 카테고리의 다른 글
내장 로거 (0) | 2023.02.13 |
---|---|
파이프와 유효성 검사 (0) | 2023.02.01 |
동적 모듈을 활용한 환경 변수 구성 (0) | 2023.01.25 |
멋사 스터디 2주차 HTTP, RESTFUL,웹 프레임워크 (0) | 2023.01.10 |
TypeScript (0) | 2023.01.02 |