12월 21, 2025
40 분 읽기

주니어 Node.js 백엔드 개발자 면접 질문

interview
career-advice
job-search
entry-level
주니어 Node.js 백엔드 개발자 면접 질문
Milad Bonakdar

Milad Bonakdar

작성자

JavaScript 기본기, 비동기 코드, 이벤트 루프, Express, REST API, 데이터베이스, 보안, 테스트, 디버깅을 다루는 주니어 Node.js 백엔드 면접 질문 35개를 연습하세요.


소개

이 종합 가이드에는 Node.js 백엔드 개발의 기본 사항을 다루는 35개의 엄선된 인터뷰 질문이 포함되어 있습니다. 이러한 질문은 주니어 백엔드 개발자가 실제 인터뷰에서 실제로 접하는 질문입니다. 각 질문에는 주요 기술 회사 및 스타트업의 수백 건의 실제 인터뷰 분석을 기반으로 한 철저한 답변, 희귀도 평가 및 난이도 등급이 포함되어 있습니다.

첫 번째 백엔드 역할을 준비하든 프런트엔드 개발에서 전환하든 이 가이드는 JavaScript 기본 사항부터 API 설계, 데이터베이스 관리, 보안 모범 사례 및 배포 전략에 이르기까지 모든 것을 다룹니다.


JavaScript 기본 사항 (8개 질문)

1. JavaScript에서 var, let, const의 차이점을 설명하세요.

답변:

  • var: 함수 범위, 호이스팅되며 undefined로 초기화됨, 동일한 범위 내에서 다시 선언 가능, 현대 코드에서는 거의 사용되지 않음
  • let: 블록 범위, 호이스팅되지만 선언될 때까지 임시 데드 존(TDZ)에 머물러 있음, 동일한 범위 내에서 다시 선언할 수 없음, 재할당 가능
  • const: 블록 범위, 호이스팅되지만 TDZ에 있음, 선언 시 초기화해야 함, 재할당할 수 없음(단, 객체/배열 내용은 변경 가능)

예제:

// var - 함수 범위
function example() {
  if (true) {
    var x = 1;
  }
  console.log(x); // 1 (블록 외부에서 접근 가능)
}

// let - 블록 범위
if (true) {
  let y = 2;
}
console.log(y); // ReferenceError

// const - 재할당 불가
const z = 3;
z = 4; // TypeError

const obj = { name: 'John' };
obj.name = 'Jane'; // OK - 속성 변경
obj = {}; // TypeError - 재할당 불가

모범 사례: 기본적으로 const를 사용하고, 재할당해야 할 때는 let을 사용하며, 현대 JavaScript에서는 var를 절대 사용하지 마세요.

희귀도: 흔함 난이도: 쉬움


2. 클로저란 무엇이며 Node.js에서 실제 예제를 제공하세요.

답변: 클로저는 내부 함수가 외부(둘러싸는) 함수의 범위에 있는 변수에 접근할 수 있는 경우입니다. 외부 함수가 반환된 후에도 마찬가지입니다. 내부 함수는 이러한 변수를 "닫습니다".

실제 Node.js 예제:

// 미들웨어 팩토리 패턴
function createAuthMiddleware(secretKey) {
  // secretKey는 반환된 함수에 의해 "닫혀" 있습니다.
  return function(req, res, next) {
    const token = req.headers.authorization;
    if (validateToken(token, secretKey)) {
      next();
    } else {
      res.status(401).json({ error: 'Unauthorized' });
    }
  };
}

// 사용법
const authMiddleware = createAuthMiddleware(process.env.JWT_SECRET);
app.use('/api/protected', authMiddleware);

장점:

  • 데이터 개인 정보 보호 (secretKey에 직접 접근할 수 없음)
  • 함수 팩토리
  • 모듈 패턴 구현
  • 비동기 작업에서 상태 유지

희귀도: 흔함 난이도: 중간


3. this 키워드를 설명하고 화살표 함수에서 어떻게 다른지 설명하세요.

답변: this는 실행 컨텍스트를 나타냅니다. 그 값은 함수가 어떻게 호출되는지에 따라 달라집니다.

일반 함수:

const obj = {
  name: "Server",
  greet: function() {
    console.log(this.name); // "Server"
  }
};
obj.greet(); // this = obj

const greet = obj.greet;
greet(); // this = undefined (엄격 모드) 또는 전역

화살표 함수:

const obj = {
  name: "Server",
  greet: () => {
    console.log(this.name); // undefined (어휘 범위)
  }
};
obj.greet(); // this = 어휘 범위 (Node.js에서 모듈 범위)

주요 차이점: 화살표 함수는 자체 this를 갖지 않으며, 둘러싸는 범위에서 상속받습니다.

희귀도: 흔함 난이도: 중간


4. Promise란 무엇이며 콜백과 어떻게 다른가요?

답변: Promise는 비동기 작업의 최종 완료 (또는 실패)를 나타냅니다.

콜백 패턴 (콜백 지옥):

getUser(userId, (err, user) => {
  if (err) return handleError(err);
  getPosts(user.id, (err, posts) => {
    if (err) return handleError(err);
    getComments(posts[0].id, (err, comments) => {
      if (err) return handleError(err);
      // 중첩된 콜백 - 읽기 어려움
    });
  });
});

Promise 패턴:

getUser(userId)
  .then(user => getPosts(user.id))
  .then(posts => getComments(posts[0].id))
  .then(comments => console.log(comments))
  .catch(err => handleError(err));

장점:

  • 콜백 지옥 방지
  • .catch()를 통한 더 나은 오류 처리
  • 연결 가능한 작업
  • Promise.all()을 사용하여 병렬 작업 가능

희귀도: 흔함 난이도: 쉬움-중간


5. async/await이란 무엇이며 코드 가독성을 어떻게 향상시키나요?

답변: async/await은 Promise를 기반으로 구축된 구문 설탕으로, 비동기 코드가 동기 코드처럼 보이도록 만들고 동작하도록 합니다.

예제:

// Promise 사용
function fetchUserData(userId) {
  return fetchUser(userId)
    .then(user => {
      return fetchPosts(user.id)
        .then(posts => {
          return { user, posts };
        });
    })
    .catch(error => console.error(error));
}

// async/await 사용 (더 깔끔함)
async function fetchUserData(userId) {
  try {
    const user = await fetchUser(userId);
    const posts = await fetchPosts(user.id);
    return { user, posts };
  } catch (error) {
    console.error(error);
  }
}

주요 사항:

  • async 함수는 항상 Promise를 반환합니다.
  • await는 Promise가 해결될 때까지 실행을 일시 중지합니다.
  • 오류 처리를 위해 try/catch를 사용합니다.
  • 순차적인 작업을 더 명확하게 만듭니다.

희귀도: 흔함 난이도: 중간


6. 객체와 배열에 대한 구조 분해 할당을 설명하세요.

답변: 구조 분해 할당은 배열에서 값을 추출하거나 객체에서 속성을 추출하여 개별 변수에 할당합니다.

배열 구조 분해 할당:

const [first, second, ...rest] = [1, 2, 3, 4, 5];
// first = 1, second = 2, rest = [3, 4, 5]

// 요소 건너뛰기
const [primary, , tertiary] = ['red', 'green', 'blue'];
// primary = 'red', tertiary = 'blue'

객체 구조 분해 할당:

const user = { name: 'Alice', age: 25, email: '[email protected]' };

const { name, age, city = 'NYC' } = user;
// name = 'Alice', age = 25, city = 'NYC' (기본값)

// 변수 이름 변경
const { name: userName, age: userAge } = user;

// 중첩된 구조 분해 할당
const { address: { street, zip } } = person;

함수 매개변수:

function createUser({ name, email, role = 'user' }) {
  // 구조 분해 할당된 매개변수 사용
}

희귀도: 흔함 난이도: 쉬움-중간


7. 스프레드 연산자와 나머지 매개변수란 무엇인가요?

답변:

스프레드 연산자 (...) - 반복 가능한 객체를 확장합니다.

// 배열
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]

// 객체 (얕은 복사)
const user = { name: 'Alice', age: 25 };
const updatedUser = { ...user, age: 26 }; // 불변 업데이트

// 함수 인수
const numbers = [1, 2, 3];
Math.max(...numbers); // 3

나머지 매개변수 (...) - 여러 요소를 수집합니다.

// 함수 매개변수
function sum(...numbers) {
  return numbers.reduce((a, b) => a + b, 0);
}
sum(1, 2, 3, 4); // 10

// 배열 구조 분해 할당
const [first, ...remaining] = [1, 2, 3, 4];
// first = 1, remaining = [2, 3, 4]

주요 차이점: 스프레드는 확장하고, 나머지는 수집합니다.

희귀도: 흔함 난이도: 쉬움-중간


8. 일반적인 배열 메서드(map, filter, reduce, forEach)를 설명하세요.

답변:

map - 각 요소를 변환하고 새 배열을 반환합니다.

const doubled = [1, 2, 3].map(x => x * 2); // [2, 4, 6]

filter - 조건과 일치하는 요소를 유지합니다.

const evens = [1, 2, 3, 4].filter(x => x % 2 === 0); // [2, 4]

reduce - 단일 값으로 줄입니다.

const sum = [1, 2, 3].reduce((acc, val) => acc + val, 0); // 6
const grouped = users.reduce((acc, user) => {
  acc[user.role] = acc[user.role] || [];
  acc[user.role].push(user);
  return acc;
}, {});

forEach - 새 배열을 반환하지 않고 반복합니다.

[1, 2, 3].forEach(item => console.log(item));

희귀도: 흔함 난이도: 쉬움


Node.js 기본 사항 (7개 질문)

9. Node.js란 무엇이며 기존 서버 측 언어와 어떻게 다른가요?

답변: Node.js는 Chrome의 V8 JavaScript 엔진을 기반으로 구축된 JavaScript 런타임으로, JavaScript를 서버 측에서 실행할 수 있도록 합니다.

주요 차이점:

  • 단일 스레드 이벤트 루프: 다중 스레드 차단 I/O 대 비차단 I/O 모델 사용
  • 기본적으로 비동기: 작업이 주 스레드를 차단하지 않음
  • JavaScript 어디서나: 프런트엔드와 백엔드에 동일한 언어 사용
  • NPM 생태계: 세계 최대의 패키지 레지스트리
  • 빠른 실행: V8 엔진이 JavaScript를 네이티브 머신 코드로 컴파일

Node.js를 사용해야 하는 경우:

  • 실시간 애플리케이션 (채팅, 게임)
  • API 서버
  • 마이크로 서비스
  • 데이터 스트리밍 애플리케이션
  • I/O 집약적인 애플리케이션

사용하지 않아야 하는 경우:

  • CPU 집약적인 작업 (이미지 처리, 비디오 인코딩)
  • 복잡한 계산이 필요한 애플리케이션

희귀도: 흔함 난이도: 쉬움-중간


10. Node.js에서 이벤트 루프를 설명하세요.

답변: 이벤트 루프는 Node.js가 단일 스레드임에도 불구하고 비차단 I/O 작업을 수행할 수 있도록 하는 메커니즘입니다.

작동 방식:

  1. 콜 스택: 동기 코드 실행 (LIFO)
  2. Node API: 비동기 작업 처리 (fs, http, timers)
  3. 콜백 큐 (매크로 작업): Node API의 콜백 보관
  4. 마이크로 작업 큐: Promise 콜백 보관 (우선 순위 높음)
  5. 이벤트 루프: 스택이 비어 있을 때 큐에서 콜 스택으로 작업 이동

실행 순서:

console.log('1');

setTimeout(() => console.log('2'), 0);

Promise.resolve().then(() => console.log('3'));

console.log('4');

// 출력: 1, 4, 3, 2
// 설명:
// - 동기 코드 (1, 4)가 먼저 실행됩니다.
// - 마이크로 작업 (Promise)은 매크로 작업보다 먼저 실행됩니다.
// - 매크로 작업 (setTimeout)은 마지막으로 실행됩니다.

이벤트 루프의 단계:

  1. 타이머 (setTimeout, setInterval)
  2. 보류 중인 콜백
  3. 유휴, 준비
  4. 폴링 (새 I/O 이벤트 가져오기)
  5. 확인 (setImmediate 콜백)
  6. 닫기 콜백

희귀도: 흔함 난이도: 어려움


11. 차단 코드와 비차단 코드의 차이점은 무엇인가요?

답변:

차단 코드 - 작업이 완료될 때까지 실행을 중단합니다.

// 동기 파일 읽기 (차단)
const fs = require('fs');
const data = fs.readFileSync('file.txt', 'utf8');
console.log(data); // 파일 읽기를 기다립니다.
console.log('Done'); // 파일 읽기 후에 실행됩니다.

비차단 코드 - 실행을 계속하고 콜백을 통해 결과를 처리합니다.

// 비동기 파일 읽기 (비차단)
const fs = require('fs');
fs.readFile('file.txt', 'utf8', (err, data) => {
  if (err) throw err;
  console.log(data);
});
console.log('Done'); // 파일 읽기가 완료되기 전에 즉시 실행됩니다.

비차단이 중요한 이유:

  • 서버가 여러 요청을 동시에 처리할 수 있습니다.
  • 더 나은 리소스 활용
  • I/O 작업에 대한 성능 향상
  • 확장성

희귀도: 흔함 난이도: 쉬움-중간


12. Node.js 모듈이란 무엇이며 모듈 시스템은 어떻게 작동하나요?

답변: Node.js는 CommonJS 모듈 시스템을 사용합니다 (ES 모듈도 지원됨).

CommonJS (require/module.exports):

// math.js
function add(a, b) {
  return a + b;
}

module.exports = { add };
// 또는
exports.add = add;

// app.js
const { add } = require('./math');
const result = add(2, 3);

ES 모듈 (import/export):

// math.js
export function add(a, b) {
  return a + b;
}

// app.js
import { add } from './math.js';

모듈 유형:

  • 코어 모듈: 내장 (fs, http, path)
  • 로컬 모듈: 사용자 정의 파일
  • 타사 모듈: npm을 통해 설치

모듈 캐싱: 모듈은 처음 require된 후 캐시되므로 후속 require는 동일한 인스턴스를 반환합니다.

희귀도: 흔함 난이도: 쉬움


13. process.nextTick()setImmediate()의 차이점을 설명하세요.

답변:

process.nextTick() - 다른 비동기 작업 전에 현재 단계에서 콜백을 실행합니다.

console.log('1');

process.nextTick(() => {
  console.log('2');
});

Promise.resolve().then(() => {
  console.log('3');
});

console.log('4');

// 출력: 1, 4, 2, 3
// nextTick은 Promise보다 높은 우선 순위를 갖습니다.

setImmediate() - 이벤트 루프의 다음 반복에서 콜백을 실행합니다.

console.log('1');

setImmediate(() => {
  console.log('2');
});

setTimeout(() => {
  console.log('3');
}, 0);

console.log('4');

// 출력: 1, 4, 3, 2 (또는 컨텍스트에 따라 1, 4, 2, 3)

우선 순위 순서:

  1. 동기 코드
  2. process.nextTick() 콜백
  3. Promise 콜백 (마이크로 작업)
  4. setTimeout(0) / setImmediate() (매크로 작업)

사용 사례:

  • nextTick: 콜백이 다른 비동기 작업 전에 실행되도록 보장
  • setImmediate: 실행을 다음 이벤트 루프 반복으로 연기

희귀도: 드묾 난이도: 중간-어려움


14. Node.js에서 전역 객체란 무엇인가요?

답변: Node.js의 전역 객체는 브라우저의 window 객체와 유사하지만 global이라고 합니다.

전역 속성:

// require 없이 어디서나 사용 가능
console.log(__dirname); // 현재 디렉토리 경로
console.log(__filename); // 현재 파일 경로
console.log(process); // 프로세스 객체
console.log(global); // 전역 객체 자체

일반적인 전역 변수:

  • process - 프로세스 정보 및 제어
  • Buffer - 바이너리 데이터 처리
  • setTimeout, setInterval, clearTimeout, clearInterval
  • setImmediate, clearImmediate
  • console - 콘솔 출력

참고: ES 모듈에서는 __dirname__filename을 기본적으로 사용할 수 없습니다. 대신 import.meta.url을 사용하세요.

희귀도: 흔함 난이도: 쉬움


15. Node.js 애플리케이션에서 오류를 어떻게 처리하나요?

답변: Node.js에서 오류 처리는 여러 가지 방법으로 관리할 수 있습니다.

1. 동기 코드에 대한 Try-catch:

try {
  const data = fs.readFileSync('file.txt', 'utf8');
} catch (error) {
  console.error('파일 읽기 오류:', error.message);
}

2. 콜백 오류 패턴:

fs.readFile('file.txt', 'utf8', (err, data) => {
  if (err) {
    return console.error('오류:', err);
  }
  console.log(data);
});

3. Promise 오류 처리:

fetchData()
  .then(data => processData(data))
  .catch(error => console.error('오류:', error));

4. try-catch가 있는 Async/await:

async function handleRequest() {
  try {
    const data = await fetchData();
    return data;
  } catch (error) {
    console.error('오류:', error);
    throw error; // 필요한 경우 다시 던지기
  }
}

5. 전역 오류 처리기:

// 잡히지 않은 예외
process.on('uncaughtException', (error) => {
  console.error('잡히지 않은 예외:', error);
  process.exit(1);
});

// 처리되지 않은 Promise 거부
process.on('unhandledRejection', (reason, promise) => {
  console.error('처리되지 않은 거부:', reason);
});

6. Express 오류 미들웨어:

app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ error: '문제가 발생했습니다!' });
});

희귀도: 흔함 난이도: 중간


Express.js & 웹 프레임워크 (6개 질문)

16. Express.js란 무엇이며 주요 기능은 무엇인가요?

답변: Express.js는 웹 및 모바일 애플리케이션 구축을 위한 강력한 기능 세트를 제공하는 최소한의 유연한 Node.js 웹 애플리케이션 프레임워크입니다.

주요 기능:

  • 라우팅: 엔드포인트 및 HTTP 메서드 정의
  • 미들웨어: 요청-응답 주기 동안 실행되는 함수
  • 템플릿 엔진: 동적 HTML 렌더링 (EJS, Pug, Handlebars)
  • 오류 처리: 중앙 집중식 오류 처리 미들웨어
  • 정적 파일: 정적 자산 제공
  • JSON 파싱: JSON 및 URL 인코딩된 데이터에 대한 내장된 본문 파싱

기본 예제:

const express = require('express');
const app = express();

app.use(express.json());

app.get('/', (req, res) => {
  res.json({ message: 'Hello World' });
});

app.listen(3000, () => {
  console.log('서버가 3000 포트에서 실행 중입니다.');
});

Express를 사용하는 이유:

  • 최소화되고 자유로운 형식
  • 대규모 생태계
  • 배우기 쉬움
  • 유연한 미들웨어 시스템

희귀도: 흔함 난이도: 쉬움


17. Express.js에서 미들웨어란 무엇인가요? 예제를 제공하세요.

답변: 미들웨어 함수는 애플리케이션의 요청-응답 주기에서 요청 객체(req), 응답 객체(res) 및 next 함수에 접근할 수 있는 함수입니다.

미들웨어 유형:

1. 애플리케이션 수준 미들웨어:

app.use((req, res, next) => {
  console.log('요청 수신:', req.method, req.path);
  next(); // 다음 미들웨어로 제어 전달
});

2. 라우트 수준 미들웨어:

app.get('/users', authenticateUser, (req, res) => {
  res.json({ users: [] });
});

3. 오류 처리 미들웨어:

app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ error: err.message });
});

4. 내장 미들웨어:

app.use(express.json()); // JSON 본문 파싱
app.use(express.urlencoded({ extended: true })); // URL 인코딩 파싱
app.use(express.static('public')); // 정적 파일 제공

5. 타사 미들웨어:

const cors = require('cors');
const helmet = require('helmet');

app.use(cors());
app.use(helmet());

사용자 정의 인증 미들웨어 예제:

function authenticateUser(req, res, next) {
  const token = req.headers.authorization;
  if (!token) {
    return res.status(401).json({ error: '토큰이 제공되지 않았습니다.' });
  }
  // 토큰 확인
  req.user = decodedToken;
  next();
}

희귀도: 흔함 난이도: 중간


18. Express 라우팅을 설명하고 라우트를 구성하는 방법을 설명하세요.

답변: 라우팅은 애플리케이션의 엔드포인트(URI)가 클라이언트 요청에 응답하는 방식을 나타냅니다.

기본 라우팅:

app.get('/users', (req, res) => {
  res.json({ users: [] });
});

app.post('/users', (req, res) => {
  const newUser = req.body;
  res.status(201).json(newUser);
});

app.get('/users/:id', (req, res) => {
  const userId = req.params.id;
  res.json({ user: { id: userId } });
});

app.put('/users/:id', (req, res) => {
  // 사용자 업데이트
});

app.delete('/users/:id', (req, res) => {
  // 사용자 삭제
});

라우트 매개변수:

app.get('/users/:userId/posts/:postId', (req, res) => {
  const { userId, postId } = req.params;
  // 라우트 매개변수에 접근
});

쿼리 매개변수:

app.get('/search', (req, res) => {
  const { q, page, limit } = req.query;
  // ?q=nodejs&page=1&limit=10
});

Express Router로 라우트 구성:

// routes/users.js
const express = require('express');
const router = express.Router();

router.get('/', (req, res) => {
  res.json({ users: [] });
});

router.get('/:id', (req, res) => {
  res.json({ user: { id: req.params.id } });
});

module.exports = router;

// app.js
const userRoutes = require('./routes/users');
app.use('/api/users', userRoutes);

희귀도: 흔함 난이도: 쉬움-중간


19. Express에서 파일 업로드를 어떻게 처리하나요?

답변: 파일 업로드는 multer와 같은 미들웨어를 사용하여 처리할 수 있습니다.

기본 파일 업로드:

const multer = require('multer');
const upload = multer({ dest: 'uploads/' });

app.post('/upload', upload.single('file'), (req, res) => {
  // req.file에 파일 정보가 포함되어 있습니다.
  res.json({ 
    filename: req.file.filename,
    originalname: req.file.originalname,
    size: req.file.size
  });
});

여러 파일:

app.post('/upload-multiple', upload.array('files', 10), (req, res) => {
  // req.files는 파일 배열입니다.
  res.json({ uploaded: req.files.length });
});

사용자 정의 저장소 구성:

const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, 'uploads/');
  },
  filename: (req, file, cb) => {
    const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
    cb(null, file.fieldname + '-' + uniqueSuffix);
  }
});

const upload = multer({ 
  storage: storage,
  limits: { fileSize: 5 * 1024 * 1024 }, // 5MB 제한
  fileFilter: (req, file, cb) => {
    if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
      cb(null, true);
    } else {
      cb(new Error('JPEG 및 PNG만 허용됩니다.'));
    }
  }
});

희귀도: 흔함 난이도: 중간


20. CORS란 무엇이며 Express에서 어떻게 처리하나요?

답변: CORS(Cross-Origin Resource Sharing)는 웹 페이지가 웹 페이지를 제공하는 도메인과 다른 도메인에 요청하는 것을 허용하거나 제한하는 보안 기능입니다.

문제: 브라우저는 기본적으로 http://localhost:3000에서 http://localhost:4000으로의 요청을 차단합니다 (다른 출처).

cors 미들웨어를 사용한 해결 방법:

const cors = require('cors');

// 모든 출처 허용 (개발 전용)
app.use(cors());

// 특정 출처 구성
app.use(cors({
  origin: 'https://example.com',
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization']
}));

// 여러 출처
app.use(cors({
  origin: ['https://example.com', 'https://app.example.com']
}));

수동 CORS 헤더:

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', 'https://example.com');
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  
  if (req.method === 'OPTIONS') {
    return res.sendStatus(200);
  }
  next();
});

희귀도: 흔함 난이도: 쉬움-중간


21. 대규모 Express.js 애플리케이션을 어떻게 구성하나요?

답변: 유지 관리를 위해 코드를 논리적 모듈 및 폴더로 구성합니다.

권장 구조:

project/
├── src/
│   ├── controllers/
│   │   └── userController.js
│   ├── models/
│   │   └── User.js
│   ├── routes/
│   │   └── userRoutes.js
│   ├── middleware/
│   │   └── auth.js
│   ├── services/
│   │   └── userService.js
│   ├── utils/
│   │   └── helpers.js
│   ├── config/
│   │   └── database.js
│   └── app.js
├── tests/
├── .env
└── package.json

관심사 분리 예제:

컨트롤러 (HTTP 처리):

// controllers/userController.js
const userService = require('../services/userService');

exports.getUsers = async (req, res, next) => {
  try {
    const users = await userService.getAllUsers();
    res.json(users);
  } catch (error) {
    next(error);
  }
};

서비스 (비즈니스 로직):

// services/userService.js
const User = require('../models/User');

exports.getAllUsers = async () => {
  return await User.find();
};

라우트:

// routes/userRoutes.js
const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');

router.get('/', userController.getUsers);
router.post('/', userController.createUser);

module.exports = router;

앱 설정:

// app.js
const express = require('express');
const userRoutes = require('./routes/userRoutes');

const app = express();
app.use(express.json());
app.use('/api/users', userRoutes);

희귀도: 흔함 난이도: 중간


데이터베이스 개념 (5개 질문)

22. SQL과 NoSQL 데이터베이스의 차이점은 무엇인가요?

답변:

SQL (관계형) 데이터베이스:

  • 테이블, 행, 열이 있는 구조화된 데이터
  • 사용하기 전에 스키마를 정의해야 함
  • ACID 준수 (원자성, 일관성, 격리성, 지속성)
  • 예: PostgreSQL, MySQL, SQLite
  • 다음 용도에 적합: 복잡한 쿼리, 트랜잭션, 구조화된 데이터

NoSQL 데이터베이스:

  • 유연한 스키마 또는 스키마 없음
  • 다양한 데이터 모델 (문서, 키-값, 그래프, 열)
  • 수평 확장
  • 예: MongoDB, Redis, Cassandra
  • 다음 용도에 적합: 대규모 애플리케이션, 유연한 스키마, 빠른 개발

비교:

기능SQLNoSQL
스키마고정유연
확장성수직수평
ACID다양
쿼리 언어SQL다양
관계조인포함/참조

SQL을 사용해야 하는 경우:

  • 복잡한 쿼리 및 관계
  • ACID 준수 필요
  • 구조화된 데이터
  • 금융 거래

NoSQL을 사용해야 하는 경우:

  • 빠른 개발
  • 대규모 데이터
  • 유연한 스키마 요구 사항
  • 간단한 쿼리

희귀도: 흔함 난이도: 쉬움-중간


23. Node.js에서 데이터베이스에 어떻게 연결하나요? (MongoDB 예제)

답변: 예제로 Mongoose와 함께 MongoDB를 사용합니다.

기본 연결:

const mongoose = require('mongoose');

// 연결 문자열
const mongoURI = 'mongodb://localhost:27017/mydb';

// 연결
mongoose.connect(mongoURI, {
  useNewUrlParser: true,
  useUnifiedTopology: true
})
.then(() => console.log('MongoDB에 연결됨'))
.catch(err => console.error('연결 오류:', err));

환경 변수 사용:

require('dotenv').config();

mongoose.connect(process.
Newsletter subscription

실제로 효과가 있는 주간 커리어 팁

최신 인사이트를 받은 편지함으로 직접 받아보세요

지원을 멈추세요. 채용되기 시작하세요.

전 세계 구직자들이 신뢰하는 AI 기반 최적화로 이력서를 면접 자석으로 변환하세요.

무료로 시작하기

이 게시물 공유

50% 더 빠르게 채용되세요

전문적이고 AI로 강화된 이력서를 사용하는 구직자는 표준 10주에 비해 평균 5주 만에 일자리를 얻습니다. 기다리지 말고 면접을 시작하세요.