24 min to read
벡엔드 면접 대비 node 질문 정리
npm 이란
npm (Node Package Manager)은 자바스크립트 환경에서 패키지 관리를 위한 도구로 오픈소스 패키지나 라이브러리를 쉽게 설치하고 관리할 수 있습니다
패키지 매니저의 종류로는 npm, yarn, pnpm등이 있으며 npm은 기본적으로 설치되기때문에 추가 설치가 필요없다는 장점이 Yarn은 Facebook이 npm의 단점을 보완하기 위해 개발한 패키지 매니저입니다.
yarn은 성능과 안정성을 중점적으로 개선한 것으로 설치 속도가 빠르다는 장점이 pnpm은 효율적인 디스크 사용과 빠른 설치를 목표로 설계된 패키지 매니저입니다. pnpm은 의존성을 하드 링크(Hard Link)를 사용하여 저장하고, 패키지가 중복 설치되는 것을 방지 한다는 장점이 있습니다
Hoisting이란 무엇인지
호이스팅이란 자바스크립트에서 변수와 함수의 선언이 최상단으로 끌어올려지는것처럼 보이는 것으로 코드 실행 전 함수와 변수를 스캔하고 렉시컬 환경이라고 불리는 자바스크립트 데이터 구조내 환경에 추가됩니다 이렇게 수집된 정보 덕분에 자바스크립트 엔진은 코드가 실행되기 전에 이미 해당 환경의 변수명을 알고 있게 됩니다
var로 선언된 함수는 선언만 호이스팅이 되고 초기화는 호이스팅이 되지 않기 떄문에 선언 전참조하면 undefined가 되지만 const, let은 선언이 호이스팅이 되는것은 똑같지만 초기화 전에 참조하면 TDZ로 인해 오류가 발생합니다
es(ecma script)
es란 에크마 스크립트로 자바스크립트에서 지켜야 할 규칙이고 자바스크립트는 이 규칙을 지키는 언어이다
es6는 에크마 스크립트의 표준 6판이며 전의 에크마 스크립트에 비해 새로운 기능과 개선된 문법을 포함하고 있습니다
-
let, const let은 블록스코프를 가지고 재할당이 가능하지만, const는 상수를 선언할때 사용하며 재할당이 불가능합니다
-
구조 분해 할당
-
함수의 기본 매개변수 할당 가능
-
스프레드 연산자
TDZ란
TDZ는 Temporal Dead Zone의 약자로 let과 const키워드로 선언된 변수가 초기화 되기 전까지 접근할 수 없는 영역을 의미 합니다 변수가 블록스코프안에서 선언되지만 초기화 되기 전까지 그 변수를 사용하는 것을 금지하는 것으로 선언전에 변수에 접근하는 것을 금지합니다 const, let, class 등이 TDZ의 영향을 받고, var, function, import등이 영향을 받지 않습니다
-
var, let, const의 차이 var는 함수스코프를 가지며 함수내에서 선언된 변수들이 함수 내부에서만 유효하다 함수 실행이 끝나면 변수가 소멸하지만 const, let은 블록스코프를 가지며 블록({})내에서만 유효합니다
-
함수 선언식과 함수 표현식의 호이스팅 함수 선언식은 호이스팅 되며 선언 이전에 호출해도 정상적으로 동작합니다 함수표현식도 호이스팅이 되지만 선언 이전에 호출하면 에러가 나게 됩니다
실행컨텍스트란?
실행컨텍스트는 자바스크립트 코드가 실행되는 동안 환경정보를 모아놓은 객체로 코드를 실행할때 환경정보를 모아 컨텍스트를 구성하고 이를 콜스택에 올렸다가 가장 위에 있는 컨텍스트와 관련있는 코드를 실행하는 식으로 순서를 보장합니다 실행컨텍스트 객체는 자바스크립트 엔진이 활용할 목적으로 생성할 뿐 확인할 수 없습니다
실행컨텍스트에는 VariableEnvironment와 렉시컬 환경으로 구성되어있으며 VariableEnvironment에는 현재 컨텍스트 내부의 식별자들에 대한 정보와 외부환경 정보, 선언시점의 렉시컬 환경의 스냅샷이 담기고 렉시컬 환경은 기본적으로 동일하지만 변경사항이 실시간으로 반영됩니다 (이 렉시컬 환경 안의 Environment Record에 현재 스코프 내의 변수 함수선언이 담기게 되고 Outer Environment Reference에 외부 스코프에 대한 참조가 담기게 됩니다)
스코프 체인
스코프란 식별자의 유효 범위로 예를 들어 경계 외부에서 선언된 변수는 그 경계 외부뿐만이 아니라 내부에서도 접근이 가능하지만 내부에서 접근한 변수는 오직 내부에서만 접근이 가능합니다
이러한 식별자 유효범위를 안에서 부터 바깥으로 계층적으로 검색하는 것을 스코프체인이라고 합니다
실행컨텍스트의 렉시컬환경의 아우터엔바이어먼트 레퍼런스에 함수가 호출될 당시 렉시컬 환경이 담기는데 선언될 당시의 렉시컬 환경이 담기게 되는데 여기에 상위 함수의 렉시컬 환경이 담기게 되면서 계층적으로 올라가게 됩니다
이런 특성 덕분에 가장 가까운 요소부터 차례대로 접근하고 동일한 이름을 가진 경우 가장 먼저 발견되는 식별자에 접근합니다
CommonJS 모듈 시스템과 ES 모듈의 차이점
JavaScript 모듈 시스템은 크게 CommonJS와 ES Module(ESM)로 나뉘게 됩니다
CommonJS는는 require()와 module.exports를 사용하고 ES Module은 import와 export를 사용하게 됩니다
CommonJS는 동기적으로 모듈을 로드하고 require()를 호출할 때, 해당 모듈이 즉시 로드되고 실행됩니다. 이 방식은 런타임에 모듈을 동적으로 로드할 수 있지만, 큰 파일을 동기적으로 로드할 경우 성능에 영향을 줄 수 있습니다.
es모듈은 비동기적으로 로드한다는 특징이 있으며 대형 모듈이나 네트워크로부터 로드된 모듈을 효율적으로 처리할 수 있습니다.
CommonJS는 런타임 시점에서 모듈을 로드하므로 정적 분석이 불가능해 컴파일러가 모듈의 종속성을 미리 분석하기 어렵습니다
반면 ES 모듈은 정적 분석이 가능하기 때문에, 모듈 종속성을 미리 파악할 수 있습니다. 컴파일러는 어떤 모듈이 사용되는지 미리 알 수 있어, 불필요한 코드를 제거하는 트리 셰이킹(Tree Shaking) 최적화를 적용할 수 있습니다.
트리세이킹
트리 셰이킹은 사용되지 않는 코드를 제거하는 최적화 기법입니다. 컴파일러가 모듈 간의 의존성을 분석하고 실제로 사용되지 않는 코드(예: 불필요한 함수나 변수)를 빌드 결과물에서 제거할 수 있어 성능을 항샹시킬 수 있습니다
자바스크립트 엔진의 실행방식
자바스크립트는 단일 스레드(single-threaded) 기반 언어로, 한 번에 하나의 작업만 처리할 수 있습니다. 하지만 비동기 작업을 처리할 때는 이벤트 루프(Event Loop)와 콜백 큐(Callback Queue), 마이크로태스크 큐를 활용해 작업을 처리합니다
콜스택은 자바스크립트의 엔진에서 함수 실행을 위해 사용하는 스택구조로 LIFO로 가장 최신에 추가된 실행컨텍스트부터 실행이 됩니다 비동기 함수들은 콜백큐에 들어가 실행되는 것이 아니라 등록만 되고 각 비동기 작업의 특정 조건이 만족될때 비동기 함수의 이벤트 핸들러를 이벤트 큐에 넣습니다 그 후 이벤트 루프는 콜스택이 비어있는지 확인하고 promise나 try catch등이 들어가는 마이크로테스크 큐를 먼저 확인하고 있으면 콜스택으로 옮겨 실행하고 마이크로 테스크큐가 비어있으면 콜백큐를 확인해 맨 위부터 순서대로 콜스택으로 옮겨 실행합니다
콜백함수
콜백함수란 다른 코드에게 인자로 넘겨줌으로써 제어권을 위임하고 제어권을 위임받은 코드는 그 코드의 로직에 의해 콜백함수를 실행합니다 콜백함수도 함수여서 this가 전역객체를 보지만 제어권을 넘겨받은 코드에서 별도로 지정시 그 대상을 봅니다
콜백은 익명함수로 전달하는 과정이 반복되어 들여쓰기 수준이 너무 깊어지는 콜백지옥 현상이 일어나기도 합니다 가장 간단한 방법은 익명함수를 기명함수로 바꾸는 것이지만 재사용하지 않을 함수면 굳이 별도로 만들 필요가 없고 가독성이 떨어지게 됩니다
es6에 도입된 promise는 resolve 또는 reject로 호출된 함수가 있을경우 실행되기 전까지 then이나 오류구문으로 넘어가지 않습니다
es2017애 도입된 async/await는 비동기 작업을 하려는 함수 앞에 async를 붙이고 비동기 작업이 필요한 위치마다 await를 붙입니다 await를 붙이면 해당 내용을 promise로 자동전환해 해당내용이 resolve된 이후 다음으로 진행됩니다
자바스크립트의 클로저
어떤 함수 A에 선언한 변수 a를 참조하는 내부 함수 B를 외부로 전달할 경우 A의 실행컨텍스트가 종료된 이후에도 a가 사라지지 않는 현상
외부함수가 종료되더라도 내부함수의 실행컨텍스트의 상위함수의 렉시컬 환경에 필요로 해 가비지 컬렉터의 수집대상에서 제외되고 메모리에 유지되게 됩니다
자바스크립트의 렉시컬 환경(Lexical Environment)은 함수가 선언된 위치를 기준으로 변수를 기억합니다. 내부 함수는 외부 함수의 변수에 접근할 수 있는 스코프 체인을 유지하며, 이로 인해 외부 함수가 종료되어도 내부 함수는 여전히 외부 함수의 변수를 사용할 수 있습니다.
이를 통해 내부 변수는 외부변수의 메서드에 접근할 수 있게 되고 데이터보호등에 사용됩니다
프로토 타입
자바스크립트는 프로토타입 기반 언어로 모든 객체는 자신의 부모 객체, 즉 프로토타입 객체에 대한 숨겨진 속성([[Prototype]])를 가지고 있습니다. 이 프로토타입 객체를 통해 해당 객체는 부모 객체의 속성이나 메서드를 사용할 수 있습니다. 이 과정을 프로토타입 체인이라고 부르며, 객체에서 속성이나 메서드를 찾을 때, 해당 객체에 없으면 프로토타입 체인을 따라 상위 객체를 탐색합니다.
프로미스란
프로미스란 자바스크립트에서 비동기 작업을 처리하기 위해 사용되는 객체로 미래에 완료될 작업을 나타냅니다 프로미스는 세가지 상태를 가질 수 있으며 대기, 이행, 거부 상태를 가질 수 있습니다
Arrow Function
Arrow Function은 ES6에 새로 도입된 함수 정의 방식입니다 기존의 함수 선언 방식보다 간결하고, this 바인딩 방식에서 중요한 차이점을 가지고 있습니다.
- this 바인딩 Arrow Function은 자신만의 this를 가지지 않고, 외부 스코프의 this를 그대로 사용하게 됩니다 이로인해 this 바인딩이 더 예측 가능해지고, bind 메서드를 사용할 필요가 줄어듭니다. Arrow Function은 arguments 객체를 가지지 않습니다. 대신, 나머지 매개변수(rest parameters)를 사용해야 합니다.
arguments란 자바스크립트의 모든 함수내에서 사용할 수 있는 지역변수로 함수에 전달된 인수(arguments)들의 배열 비슷한 객체입니다 arguments 객체를 사용하면 함수가 호출될 때 전달된 인수의 목록을 확인하거나 사용할 수 있습니다.
async/await 이란 무엇인지
자바스크립트에서 비동기 작업을 처리하기 위해 사용하는 문법으로, 비동기 코드를 마치 동기 코드처럼 읽기 쉽고 간결하게 작성할 수 있게 해줍니다
async 키워드를 함수 앞에 붙이면 그 함수는 자동으로 Promise를 반환하는 함수가 되고 await는 Promise가 처리될 때까지 기다렸다가 그 결과를 반환합니다
‘==’와 ‘===’ 연산자의 차이
==와 ===는 자바스크립트에서 두 값을 비교하는 연산자이지만 둘은 차이가 있습니다 ==는 동등연산자로 두값을 비교할때 타입변환을 수행한 후 비교하게 됩니다 둘의 타입이 다르더라고 자동으로 타입을 변환한 후 비교를 합니다
===는 일치연산자로 두 값을 비교할떄 타입변환을 수행하지 않고 엄격하게 비교를 합니다 비교시 두 값이 타입까지 같아야 true를 반환합니다
자바스크립트에서 객체끼리의 비교하는 방법은 조금 다른 점이 자바스크립트에서 모든 객체는 참조 타입으로 객체 비교를 하면 두 객체의 참조를 비교합니다
두 객체가 구조적으로 같더라도 서로 다른 메모리 공간 차지하는 경우 false를 반환하고 동일한 메모리 참조를 가리킬 때만 === 연산자는 true를 반환합니다
이를 해결하기 위해서는 객체의 속성을 하나씩 비교하는 방식을 사용해 비교할 수 있습니다 ***
Express의 개념과 대안
- express란
express는 경량의 웹 애플리케이션 프레임워크 중 하나로 웹 서버 및 api를 쉽게 구축할 수 있습니다 express의 대안으로는 koa, Fastify, nest등이 있습니다
Koa는 express의 개발팀이 만든 프레임 워크로 async/await 패턴을 사용합니다 Fastify는 매우 빠른 프레임워크로 json을 자동으로 분석하기 때문에 속도가 빠릅니다 nest는 Angular에서 영감을 받은 프레임워크로 모듈기반 아키텍쳐와 의존성 주입을 지원합니다
왜 express를 선택했는지 express는 2021년 기준 점유율 89%으로 압도적이고 다른 3개에 비해 생태계가 잘 구성되어있어 정보를 얻기 쉬워 선택했습니다
Express와 nest.js의 차이
express에서 라이프사이클에 관한 부분을 개발자가 직접 설정을해줘야하지만 nest는 애플리케이션의 라이프 사이클을 자동으로 관리하는 기능을 제공한다
express는 async/await에서 발생하는 에러를 개별적으로 에러 처리 핸들러를 사용해야 하지만 nest에서는 예외 필터를 만들어 중앙에서 자동으로 처리할 수 있습니다
Express는 개발자가 직접 의존성 관리 및 주입을 처리해야 하지만 NestJS는 의존성 주입(DI)을 프레임워크의 핵심으로 제공하며 의존성을 자동으로 관리해줍니다
또한 AOP를 보다 더 쉽게 사용할 수 있습니다
nest.js
nest는 express를 기반으로 만들어진 프레임워크로 express와 달리 모듈시스템을 통해 애플리케이션을 구조화하고 의존성 주입을 사용해 테스트 가능하고 유지보수하기 쉬운 코드를 작성할 수 있습니다
nest의 특징으로는 모듈화를 통해 애플리케이션을 모듈단위로 나누어 독립적으로 개발하고 유지 보수 할 수 있으며 DI(의존성 주입)을 통해 컨포넌트간의 의존성을 관리해 코드의 재사용을 가능하게 해줍니다
- 의존성 주입 의존성은 객체지향 프로그래밍에서 한 클래스가 다른 클래스나 모듈의 기능을 필요로 하는 관계로 하나의 객체가 다른 객체를 사용할때 그 객체에 의존한다고 말합니다
의존성 주입은 클래스나 모듈이 필요로 하는 의존성을 외부에서 주입하는 패턴으로 객체가 직접 의존성을 생성하지 않고 외부에서 필요한 의존성을 주입받습니다
이를 통해 클래스간의 결합도를 낮추고 의존성을 외부에서 주입받기 때문에 런타임시 다른걸로 대체 할 수 있습니다
의존성 주입에는 생성자를 사용하는 생성자 주입 방식과 세터메서드를 사용해 주입받는 세터 주입 방법이 있습니다
생성자란 클래스의 인스턴스가 생성될때 호출되는 특별한 메서드로 객체의 초기 상태를 설정하고 초기화 작업을 진행합니다
nest와 node의 차이점 모듈화를 통해 쉬운 개발이 가늘하고 의존성 주입을 통해 코드의 재사용성을 향상시키고 테스트가 쉽게 만들어줍니다
또한 AOP를 보다 더 쉽게 사용할 수 있게 해준다 ***
AOP
관점 지향프로그래밍으로 흩어진 관심사를 모듈화하여 핵심 비즈니스 로직과 분리하는 프로그래밍 패러다임 이다
애플리케이션을 개발할 때, 로깅, 보안, 트랜잭션 관리, 예외 처리와 같은 기능들은 여러 모듈에 걸쳐 필요하지만, 이들을 각 모듈에 반복적으로 작성하면 코드가 복잡해지고 유지보수가 어려워짐
이러한 문제를 해결하기 위해, 공통된 기능을 하나의 모듈로 분리하여 필요한 부분에 적용하는 방법
nest는 AOP를 쉽게 적용할 수 있으며 Interceptors나 Guards 같은 기능을 통해 로깅, 인증, 권한 검증 등의 기능을 손쉽게 구현 가능하다
AOP의 주요 개념
횡단 관심사(Cross-Cutting Concern): 애플리케이션 전반에 걸쳐 공통적으로 필요한 기능(로깅, 보안, 트랜잭션 등)을 의미
Aspect (관점): 횡단 관심사를 모듈화한 것을 의미하며, 이 모듈은 특정 기능(예: 로깅)을 수행하는 코드 집합
Advice (어드바이스): 언제(메서드 실행 전, 후 등) 횡단 관심사를 적용할지에 대한 행동을 정의한 부분
Pointcut (포인트컷): 특정 메서드나 클래스에 횡단 관심사를 적용할 위치를 정의한 표현식
Join Point (조인 포인트): 어드바이스가 실행될 수 있는 특정 시점이나 위치(메서드 호출, 예외 발생 등)
nest에서 DI의 장점
DI를 통해 의존성을 클래스에 주입하고 모듈의 독립성을 높여 코드의 재사용성을 향상시킬 수 있고 테스트시 모킹된 의존성을 주입해 테스트를 쉽게 작성할 수 있습니다
express에서는 DI를 기본적으로 제공하지 않지만 생성자와 모듈을 사용해 의존성을 주입할 수 있습니다
이벤트 루프
이벤트 루프는 자바스크립트 런타임이 비동기 작업을 처리하는 방식입니다. 자바스크립트는 싱글 스레드 언어이지만, 비동기 작업을 비동기적으로 처리하여 메인 스레드의 블로킹을 방지합니다.
태스크 큐 는 비동기적으로 실행된 콜백함수가 보관되는 영역으로 이벤트 루프가 콜백큐와 콜스택의 상태를 체크해 콜스택이 빈 상태가 되면 프로미스의 then, catch등이 대기하는 마이크로테스크 큐를 먼저 확인하고 대기중인 작업을 옮기고 마이크로 테스크큐가 비어있다면 태스크 큐에 있는 첫번째 콜백을 콜스택으로 이동시키게 됩니다
single-threaded
Node.js는 자바스크립트 런타임으로, 싱글 스레드(Single-threaded) 기반으로 합니다. Node.js가 한 번에 하나의 작업만 처리할 수 있는 단일 스레드를 사용한다는 것이지만 node는 이벤트 루프와 비동기 프로그래밍을 사용해 싱글 스레드의 단점인 낮은 처리량과 시간을 보완합니다 프로세스는 운영체제로부터 자원을 할당받은 작업의 단위로 메모리에 올라와 실행되고 있는 프로그램이고 스레드는 이런 프로세스로부터 할당받은 자원을 이용하는 실행흐름의 단위입니다
Blocking VS Asynchronous
둘은 서로 비슷해보이지만 다른 개념으로 동기와 비동기는 요청한 작업의 완료 여부를 신경써서 작업을 순차적으로 실행할지 아닐지이고 Blocking은 현재 작업이 차단되냐 아니냐의 차이입니다
- 동기와 비동기
둘의 차이는 호출되는 함수의 리턴값 확인 유무로 Synchronous(동기)는 요청한 작업에대한 완료여부(리턴값)을 따져 처리하고 Asynchronous(비동기)는 요청한 작업의 완료여부를 확인하지 않는다
- 블로킹과 논블로킹
블로킹과 논블로킹은 호출된 함수가 호출한 함수에게 제어권을 주느냐에 따라 구분합니다 제어권은 프로그램 실행중에 함수의 코드나 프로세스의 실행흐륾을 제어할 수 있는 권리로 제어권을 주면 함수를 실행할 권리가 없어 실행이 멈추게 됩니다
블로킹
논블로킹
- 동기+ 블로킹
함수A는 함수B의 리턴값이 필요해(동기) 제어권을 b함수에 보내주고 실행이 완료되어 리턴값이 돌아올때 까지 기다린 후 다음 함수를 실행합니다
- 동기+논블로킹
a함수는 b함수를 호출하지만 제어권을 주지않고 자신은 계속 실행합니다 하지만 리턴값이 필요하기 때문에 주기적으로 b함수에게 실행을 완료했는지 물어보게 됩니다
- 비동기 + 논블로킹
비동기 방식이기 때문에 요청한 작업의 리턴값이 왔는지 여부를 신경쓰지 않고 계속 진행하고 제어권을 주지 않고 있다가 호출한 함수에 넘겨준 콜백함수를 실행합니다
- 비동기 + 블로킹
a함수는 b함수의 리턴값을 신경쓰지 않고 콜백함수를 사용하지만 b함수에게 제어권을 넘깁니다
제어권을 넘겨서 제어권을 다시 받을때까지(b함수가 끝나 다시 제어권을 받을때까지) 멈추게 된다 다시 제어권이 오면 다시 함수를 실행합니다
모든 요소에 인덱스를 걸지 않는 이유
성능, 저장공간, 인덱스 유지 관리의 부담때문입니다 인덱스가 많아질수록 작업을 할때마다 인덱스를 갱신해야 하고 각 인덱스는 별도의 데이터구조로 저장되며 이는 추가적인 데이터 공간을 차지하게 됩니다
깊은 복사와 얉은복사의 차이
-
깊은복사 객체의 모든 프로퍼티의 값을 재귀적으로 복사합니다 복사된 객체는 원본객체와 달리 독립된 메모리 공간을 가집니다 복된 객체와 원본객체는 서로 영향을 미치지 않습니다 재귀함수를 사용하거나 JSON.stringify()를 사용해 구현할 수 있습니다
-
얉은 복사 객체의 프로퍼티 값을 복사한다 복사된 객체는 원본 객체와 같은 참조를 공유하기 떄문에 복사된 객체의 프로퍼티를 변경하면 원본객체의 프로퍼티도 변경됩니다 Object.assign()과 스프레드 연산자를 사용해 얉은 복사를 할 수 있습니다
JS의 passed by value 와 passed by reference
-
값에 의한 전달 원시타입(number, string)등은 값에 의한 전달방식으로 동작합니다 원시타입은 값이 한번 정해지면 바뀌지 않기 때문에 값을 변경하려면 새로운 값을 재할당해야한다 다른 변수에 복사할떄 pass by value방식을 사용해 변수에 저장된 값이 복사되어 전달됩니다
-
참조에 의한 전달 객체타입은 원시타입과 반대로 값을 바꿀 수 있어 메모리의 크기를 사전에 저장할 수 없어 객체타입과 다르게 값을 저장하지 않고 메모리의 주소를 저장하게 됩니다 따라서 다른 변수에 복사할때 값이 아니라 저장하고 있던 메모리 주소를 전달한다
스트림(Stream)
스트림은 대량의 데이터를 효율적으로 처리하기 위한 인터페이스로 대규모 데이터나 실시간 데이터 처리에 주로 사용됩니다
데이터를 한 번에 모두 메모리에 로드하지 않고 청크(chunk) 단위로 데이터를 처리합니다
한번에 큰 용량의 파일을 처리할려고 한다면 한번에 큰 용량의 공간을 사용해야 해 성능에 문제가 생길 수 있습니다.
하지만 스트림을 사용하게 되면 데이터를 잘라 이용할 수 있어 한 번에 전체 데이터를 메모리에 적재할 필요 없이 효율적으로 대용량 파일을 다룰 수 있습니다. 이를 통해 메모리 사용을 크게 줄이고, 성능을 최적화할 수 있습니다.
- 스트림의 4가지 유형 Readable 스트림: 외부 소스로부터 데이터를 읽어들입니다
Writable 스트림: 데이터를 외부로 씁니다.
Duplex 스트림: 읽기와 쓰기 모두 가능한 스트림입니다
Transform 스트림: 데이터를 읽으면서 동시에 데이터를 변환할 수 있는 스트림입니다
JWT
JWT는 인증받은 사용자에게 토큰을 발급해주고 서버에 요청을 할떄 http 헤더에 토큰을 보내 인증받은 사용자 인지 확인합니다 서버에서는 들어온 토큰을 검증할때 헤더에서 jwt를 추출하고 시그니쳐와 유효성을 검증합니다 또한 jwt는 만료기간이 있으며 만료된 토큰을 재발급하기 위해 서버의 엑세스 토큰과 함께 만료기간이 더 긴 리프래시 토큰을 발급해 엑세스 토큰이 만료되었을때 리프래시 토큰을 사용해 새 엑세스 토큰을 발급합니다
mvc 패턴
MVC 패턴은 소프트웨어 디자인 패턴 중 하나로, 애플리케이션을 세 가지로 분류해 개발과 유지보수를 쉽게 하기 위해 사용합니다 모델은 애플리케이션의 핵심 데이터와 비즈니스 로직을 담당합하고 뷰는 사용자의 인터페이스를 담당하고 사용자의 입력을 받아 컨트롤러로 전달합니다 컨트롤러는 사용자의 입력을 받아 모델이나 뷰를 업데이트 하고 모델과 뷰 사이 상호작용을 관리합니다 컨트롤러를 3개로 분리해 컨트롤러 레포지토리 서비스로 분리 할 수도 있습니다
RDBMS의 정규화
정규화란 데이터베이스 설계에서 중복을 제거하고 데이터 중복을 최소화하여 데이터베이스를 보다 효율적으로 설계하는 과정입니다 정규화를 사용해 데이터의 일관성, 유보수성을 개선해 무결성을 유지 할 수 있습니다
- 단계
- 제 1 정규화(칼럼이 하나의 값을 가지도록 테이블을 분해, 원자값을 가지게)
- 제 2 정규화(기본키가 복합키일 경우 구성하는 속성 중 일부에게 종속되는 부분 종속 제거)
- 제 3 정규화(x-> y, y->z 일때, x->z인 이행함수 제거, 테이블내에 모든 속성이 기본키에 종속해야함)
- 보이스-코드 정규화(BCNF, 결정자 후보키가 아닌 함수 종속 제거)
Primary Key, Foreign Key
-
Primary Key 데이터테이블에서 각 레코드를 고유하게 식별하는데 사용하는 열로 중복이 없어야 하고 null값을 가질 수 없습니다
-
Foreign Key 하나의 테이블에서 다른 테이블의 기본키를 참조하는 키 두 테이블간의 관계를 설정하며 두 테이블을 서로 이어준다
HTTP 메서드
HTTP 메서드란 클래이언트가 웹서버에 요청하는 목적 및 종류를 알리는 수단
- 종류
- get 리소스 조회 메서드 전달하고 싶은 데이터는 url의 쿼리스트링을 통해 전달
-
post 리소스 셍성 메서드 서버의 상태를 변경할 수 있고 데이터는 body에 담겨짐 get방식과 비교해 데이터가 url에 명시되지 않으므로 더 안전함
-
put 리소스 수정 메서드 만일 리소스가 있으면 수정하고 리소스가 없다면 새로 만든다 수정만 있는 patch와는 다름 데이터는 body에 담겨짐
-
delete 리소스 삭제 메서드
-
head 서버의 리소스의 헤더 정보 요청시 사용
CORS(교차 출처 자원 공유)
브라우저는 보안상의 이유로 같은 출처에서만 리소스를 공유할 수 있다라는 규칙을 가지고 있는 sop 규칙을 따르고 있습니다 하지만 출처가 달라도 상호작용이 필요할때가 있습니다 그래서 CORS 헤더에 출처를 등록해 서로 상호작용을 할 수 있게 합니다
프로토콜 + 호스트+포트 3가지가 같은 같은 출처
#### 쿠키, 세션의 개념과 차이 쿠키란 브라우저에 데이터를 저장하는 것으로 서버가 클라이언트의 사이의 매개체입니다 브라우저는 서버에서 받은 쿠키를 저장했다가 동일한 서버에서 요청이 다시 들어왔을떄 쿠키를 같이 전송합니다 쿠키는 클라이언트에서 쿠키의 정보를 쉽게 변경 삭제할 수 있기 때문에 삭제와 가로채기가 가능합니다
세션이란 서버측에서 관리되는 정보로 각 클라이언트가 가지는 셔센 ID를 통해 식별합니다 세션데이터는 서버에 저장되기 때문에 클라이언트의 접근이 불가해 쿠키보다 안전하지만 아이디가 탈취되면 세션이 탈취될 수 있습니다
#### TCP/UDP 둘 모두 데이터 전송 프로토콜이지만 둘은 서로 다른 접근 방식을 사용합니다
-
tcp 연결 지향적 프로토콜로 신뢰성과 순서를 보장합니다 또한 흐름 제어와 혼잡 제어를 지원합니다
-
udp 비연결형 프로토콜로 데이터 전송의 신뢰성이나 순서를 보장하지 않습니다 약간의 데이터 손실이 있지만 빠른 전송 속도가 필요할때 사용합니다 실시간 스트리밍등에서 사용합니다
프로세스와 쓰레드
프로세스는 운영체제로부터 자원을 할당받은 작업의 단위로 메모리에 올라와 실행되고 있는 프로그램이고 스레드는 이런 프로세스로부터 할당받은 자원을 이용하는 실행흐름의 단위입니다 기본적으로 각각의 프로세스는 최소 1개의 스레드 보유 프로그램 ->프로세스 -> 스레드
멀티프로세스와 멀티쓰레드
멀티 프로세스 여러 프로세스를 생성해 병렬로 작업을 수행하는 방식으로 각 프로세스는 독립적인 공간을 가지고 있으며 서로간 데이터공유를 하지 않습니다 그렇기 때문에 서로 통신은 파이프, 소켓등을 사용해 이루어집니다
멀티 스레드 일반적으로 프로세스는 하나의 스레드를 가지고 작업을 수행하지만 멀티스레드는 하나의 프로세스에서 둘이상의 스레드가 작업하는 것을 말합니다 스레드는 프로세스의 메모리 공간을 공유하기 때문에 스레드간의 통신이 효율적이지만 메모리를 공유하기 때문에 데드락이 발생할 수 있습니다
CPU 부하가 큰 작업이 Node.js 애플리케이션에서 이벤트 루프를 차단하여 서버가 멈추는 문제 해결
노드는 단일 스레드이고 이벤트 루프에는 한번에 하나의 프로세스만 발생합니다 하지만 cpu를 많이 사용하는 코드가 있으면 이 코드가 다른 프로세스가 실행되는걸 막을 수 있음 하지만 work thread를 사용해 멀티스레드 환경을 구축할 수 있습니다 하나의 메인 스레드를 두고 워커 스레드를 둬서 워커 스레드에서 작업을 분배할 수 있고 각각은 이벤트 루프와 v8엔진이 존재해 격리된 코드를 실행할 수 있습니다
Child Processes를 사용해 새로운 작업 프로세스를 생성해 새로운 node.js환경을 만들 수 있습니다
타입스크립트가 자바스크립트로 변환되는 과정
타입스크립트는 자바스크립트로 변환을 해서 실행함 타입스크립트 코드를 실행하면 컴파일러를 통해 ast 코드로 파싱되고 타입체커를 사용해 타입을 체크합니다 타입체크가 완료된 후 이 ts ast 코드를 js코드로 변환하고 이 자바스크립트 코드를 바이트코드로 변환후 자바스크립트 런타임에서 실행됩니다
ast란 추상구문 트리로 소스코드의 구조를 트리 형태로 표현한것으로 함수의 선언이나 코드의 일관성을 검사할 수 있습니다
자바스크립트와 타입스크립트의 차이
자바스크립트와 타입스크립트의 차이는 타입스크립트의 타입시스템과 컴파일링 이라고 생각합니다
자바스크립트에서 변수의 타입은 런타임 시 결정되기 때문에 예상치 못한 곳에서 오류가 발생할 경우 프로그램이 멈출 수도 있지만 타입스크립트는 변수와 함수의 타입을 컴파일 시 타입의 오류를 발견할 수 있어 안전하게 코드를 작성할 수 있습니다
타입시스템을 통해 코드를 더 명확하게 정의하고 의도하지 않은 오류를 발견할 수 있고. 타입 어노테이션을 통해 코드의 타입을 명시 할 수 있어 어떤 데이터를 처리하는 지 이해가 쉽고 협업시 오류를 줄일 수 있습니다 이를 통해 코드의 안전성과 유지보수성을 높일 수 있습니다
자바스크립트의 악점
-
실행시간에 결정되는 변수 타입 자바스크립트는 변수의 타입이 실행시간(런타임)에 결정되기 때문에 오류가 발생하면 유지보수가 힘듭니다
-
약한 타입체크 자바스크립트는 타입체크를 변수와 상수를 구분하는 정도만 지원하기 때문에 실수로 인해 변수의 타입이 바뀔 수 있습니다
-
물렁한 객체 자바스크립트에서 객체의 특성과 구조가 동적으로 변경될 수 있음을 의미합니다 이는 오류를 발생시킬 수 있습니다
-
오타 변수명이나 함수명을 잘못 입력하면 오류가 발생할 수 있습니다 다른 언어에서는 이를 컴파일러에서 잡아줍니다
ORM
- orm이란 객체와 관계형 데이터베이스의 데이터를 자동으로 매핑해주는 것으로 객체지향프로그래밍은 클래스를 사용하고 관계형 데이터베이스는 테이블을 사용한다
이때 둘의 불일치가 발생하는데 이를 orm이 자동으로 객체간의 관계를 바탕으로 sql문을 생성하여 불일치를 해결해 준다
-
orm의 장점 sql문이 아닌 직관적인 코드로 데이터를 조작할 수 있어 개발자가 객체지향프로그래밍하는데 집중 할 수 있다 재사용성 및 편리성이 증가한다
-
orm의 단점 orm은 sql문을 추상화하고 객체모델을 사용하기 때문에 직접 로우쿼리로 작성하는 것보다 성능이 떨어진다 sql문법이 아닌 orm의 문법을 따로 배워야 하기 때문에 시간이 더 걸릴 수 있다
-
프리즈마의 장점 프리즈마 스튜디오를 통해 디비에 있는 데이터를 꺼내 볼수 있고 매핑이 잘되어있는지 확인할 수 있다 또한 타입스크립트로의 마이그레이션 시 데이터베이스 스키마를 기반으로 TypeScript 타입을 자동으로 생성하기때문에 Sequelize보다 더 편리하고 데이터베이스 마이그레이션시 프리즈마는 자동으로 마이그레이션 파일을 지원하지만 Sequelize는 수동으로 관리해야 합니다
### typescript의 타입시스템 TypeScript는 자바스크립트에 정적 타입 체계를 추가한 언어로, 컴파일 시점에 타입 오류를 검출하여 더 안전한 코드를 작성할 수 있게 해줍니다. 객체 지향 프로그래밍(OOP) 지원과 뛰어난 도구 통합 덕분에 대규모 애플리케이션 개발에 적합하며, 코드의 유지보수성과 가독성을 크게 향상시킵니다. 기존 자바스크립트 프로젝트에 점진적으로 도입할 수 있다는 장점도 있습니다.
타입스크립트의 타입시스템 기본타입 12개
- Boolean: 참과 거짓
- string: 문자열
- Array: 배열타입 []을 쓰거나 <>배열타입 사용
- Tuple: 배열의 길이가 고정되고 각 요소의 타입이 지정되어있는 형식
- Enum: 특정 값들의 집합
- object: 객체뿐만이; 아니라 배열 함수까지
- Any: 모든 타입에서 허용한다는 의미, 타입을 알 수 없을떄 사용
- unknown: any처럼 모든 값을 허용, any타입은 연산 진행 후 맞지 않으면 undefined를 발생시키지만 unknown은 어떤값인지 모르기때문에 연산을 진행하지 않는다
- never: 타입스크립트에서 잘못된 것을 알려주기 위한 키워드로 절대 발생할 수 없는 타입을 나타낸다
-
void: 함수에 반환값이 없을떄 사용
- 타입스크립트의 특수 타입
-
union type: 를 사용해 여러 타입 중 하나일 수 있음을 나타낸다 - 인터섹션: &을 사용해 2개 이상의 타입을 조합해 새로운 타입을 만든다
- interface: 객체의 구조를 정의한다
- Generics: 다양한 타입에 대해 재사용 가능한 컨포넌트를 만들 수 있다
-
git brunch 전략
git brunch 전략이란 여러 개발자가 하나의 저장소에 작업시 서로 협업을 더 효율적으로 하기 위해 브런치 전략을 정한다
- git flow 전략
5개로 나뉜다
- master: 기준이 되는 브런치. 배포용
- develop: 개발용 브런치, 각자 작업한 기능을 mearge
- feature: 새로운 기능을 개발할때 사용, develop 에서 분기 후 완료시 다시 develop mearge
- Release: 배포를 위한 master브런치로 내보내기 전 먼저 검사 하는 브런치
- hotfix: 배포 후 에러 발생시 긴급하게 수정하는 브런치
master에서 develop를 분기한 후 기능 구현 위해 각자 featuer에서 만든 후 develop에 merage 한다
(주기적으로 다른 개발자들의 코드를 develop에서 merage하기)
주기적으로 배포 전 검사 위해 release 브런치로 옮기고 테스트완료되면 master와 develop에 merge한다
- git hub flow
git brunch를 git hub에서 쓰기 힘들어 나온 전략이다
- main brunch: 배포용 브런치로 최종적으로 이 브런치로 병합된다
- feature brunch: 새로운 기능이나 버그작업등을 위해 분기해서 만든 브런치, 완료시 다시 main에 merge
자바스크립트의 프로토 타입이란
모든 객체들은 메서드와 속성을 상속받기 위한 템플릿으로 프로토 타입 객체를 갖습니다 자바스크립트는 프로토 타입 객체지향 프로그래밍 언어로 모든 객체들이 메소드와 속성들을 상속 받기 위한 템플릿으로써 프로토타입 객체(prototype object)를 가집니다
프로토타입의 객체도 상위 프로토 타입 객체로 부터 메서드와 속성을 상속받을 수 있고 이를 프로토타입 체인이라고 부르며 다른 객체에 정의된 메서드와 속성을 사용할 수 있습니다
nestJS
nestjs에서 기본 구조는 모듈, 컨트롤러, 서비스, 프로바이더 모듈은 전체 어플리케이션의 구조를 만드는 메타데이터 제공 컨트롤러는 http 요청 처리, 서비스는 비즈니스 로직 처리, 프로바이더는 nest에서 의존성을 주입 할 수 있다
의존성 주입이란 필요한 의존성을 스스로 생성하는 대신 외부에서 제공받는 패턴으로 모듈의 서비스를 다른 서비스에 주입해 사용할 수 있습니다
@Injectable() 데코레이터를 통해 프로바이더임을 선언하고 이 데코레이터가 작용된 클래스를 다른 클래스에 의존성으로 주입할 수 있습니다
파이프는 유효성검사와 변환을 담당하고 가드는 특정 경로에 대한 접근을 제어하는데 사용합니다
@nestjs/microservices 를 통해 nestr에서 메시지 전송 전략을 사용해 마이크로 서비스를 구현할 수 있다
프레임워크(Framework), 라이브러리(Library), 패키지(Package)
프레임워크는 직접 코드의 흐름을 제어하며 개발자는 프레임워크가 정해준 방식에 따라 코드를 작성하게 됩니다
라이브러리는 특정 기능을 수행하는 코드의 모음으로 개발자가 필요할때에 호출해 사용합니다 제어권이 개발자에게 있고 언제 어떤 라이브러리를 활용할지 직접 정합니다
패키지는 모듈들의 그룹화한덕으로 관련 코드를 관리하고 재사용하는 단위입니다
인터페이스와 타입 별칭
타입스크립트에서 인터페이스는 객체의 구조를 정의하는데 사용되고 타입별칭은 모든 타입을 정의할 수 있습니다
인터페이스는 확장할 수 있어 객체 타입간의 관계 정의하기에 유용합니다
타입 별칭은 유니온 타입, 함수 타입 등 다양한 타입을 정의할 수 있습니다
유니온 타입과 인터섹션 타입
유니온 타입은 여러 타입 중 하나를 가질 수 있는 타입으로 그 중 하나의 타입을 가질 수 있는 or과 같은 역할을 하지만 인터섹션 타입은 여러 타입을 만족하는 타입을 나타냅니다
인터섹션은 여러 타입을 합성하여 새로운 타입을 만들 때 유용합니다.
타입 가드(Type Guard)
타입 가드는 런타임에 타입을 좁히기 위해 사용하는 조건문입니다.
typeof, instanceof, 또는 사용자 정의 함수 등을 사용하여 타입을 판별할 수 있습니다.
타입 가드는 타입스크립트가 코드 내에서 특정 타입을 안전하게 처리할 수 있게 도와줍니다
타입 추론(Type Inference)
타입스크립트의 타입 추론 시스템은 변수를 선언할 때 명시적으로 타입을 지정하지 않아도, 컴파일러가 그 타입을 추론하는 기능입니다.
NestJS에서 모듈
관련 기능들을 그룹화하여 관리하는 단위로 모듈은 하나 이상의 컨트롤러와 서비스를 포함하며, 서로 독립적인 기능 단위로 나뉩니다.
모듈 간의 의존성을 명확히 정의하고, 필요한 경우 인터페이스나 프로바이더를 사용하여 결합도를 낮춰야 합니다.
미들웨어(Middleware)와 인터셉터
미들웨어는 요청이 컨트롤러에 도달하기 전에 실행되는 함수로, 요청을 가로채어 인증, 로깅 등을 처리합니다
인터셉터는 요청 또는 응답을 가로채는 역할을 하며, 주로 응답 데이터 가공 또는 성능 측정에 사용됩니다
미들웨어는 주로 요청 처리 전 단계에서 사용되고, 인터셉터는 요청과 응답의 흐름을 제어하는 데 사용됩니다.
제너릭
제너릭이란 수, 클래스 또는 인터페이스에서 타입을 매개변수로 받을 수 있도록 하는 기능으로 타입에 의존하지 않고 여러 타입에 대해 동작하는 코드를 작성할 수 있습니다.
타입에 의존하지 않는 코드를 작성할 수 있어, 여러 타입에 대해 동일한 함수나 클래스를 사용할 수 있고 제너릭을 사용하면 컴파일 시점에 타입을 검사할 수 있기 때문에, 런타임 오류를 방지할 수 있습니다.
제네릭 타입 매개변수는 전달된 타입에 따라 동적으로 타입을 결정합니다. 즉, T로 어떤 타입이 들어오면 그 타입에 대해 타입 검사를 정확하게 할 수 있습니다
하지만 any는 어떤 타입도 허용하므로, 타입 안전성이 없습니다.
제네릭을 사용할 때, 모든 타입에 대해 동작하는 것이 아니라 특정 타입에 대한 제약을 두고 싶을 때 제네릭 제약 조건(Constraints)을 사용합니다.
T extends SomeType 형태로 제약을 설정하면, T는 반드시 SomeType의 하위 타입이어야 한다는 제약 조건을 걸 수 있어 없다면 에러를 발생시킵니다
제어의 역전
일반적으로 개발자가 애플리케이션의 동작 흐름을 직접 제어합니다. 예를 들어, 객체를 직접 생성하고, 메서드를 호출하며, 프로그램이 어떻게 실행될지를 결정합니다.
하지만 제어의 역전에서는 객체 생성이나 실행 흐름을 개발자가 제어하지 않고, 프레임워크 또는 외부 컨테이너가 제어합니다.
즉, 객체의 생성, 의존성 주입, 메서드 호출 등이 개발자가 아닌 외부 주체에 의해 이루어지므로 제어의 흐름이 역전된다고 볼 수 있습니다.
제어의 흐름을 외부 주체에 넘김으로써, 객체는 자신의 주요 로직에만 집중하고, 객체 생성이나 의존성 관리 등의 부수적인 책임은 프레임워크가 맡습니다.
애플리케이션의 흐름을 외부에서 제어하므로, 의존성을 동적으로 변경하거나 모듈을 교체하는 등 유연하게 시스템을 설계할 수 있습니다.
제어의 역전 vs. 의존성 주입
제어의 역전(IoC): 소프트웨어 설계 원칙으로, 제어 흐름을 개발자가 아닌 외부 주체가 담당하는 개념을 말합니다.
의존성 주입(Dependency Injection, DI): 제어의 역전의 구체적인 구현 방법 중 하나로, 객체가 의존성을 스스로 생성하지 않고 외부에서 주입받는 방식입니다. 주로 컨테이너나 프레임워크에서 의존성을 주입해줍니다.
Comments