Node.js 인터뷰 질문 31

질문: Node.js에서 오류 우선 콜백 패턴(Error-First Callback Pattern)에 대해 설명해주세요.

답변:

오류 우선 콜백 패턴(Error-First Callback Pattern)은 Node.js에서 비동기 작업의 결과를 처리하는 표준적인 방식입니다. 이 패턴은 Node.js 코어 모듈과 대부분의 NPM 패키지에서 일관되게 사용되며, 비동기 작업의 오류 처리를 효과적으로 할 수 있게 해줍니다.

기본 원칙

오류 우선 콜백 패턴의 기본 원칙은 다음과 같습니다:

  1. 콜백 함수의 첫 번째 매개변수는 오류 객체를 위해 예약되어 있습니다.
  2. 오류가 발생하면 첫 번째 매개변수에 오류 객체가 전달됩니다.
  3. 오류가 발생하지 않으면 첫 번째 매개변수는 null 또는 undefined가 됩니다.
  4. 성공적인 결과 데이터는 두 번째 이상의 매개변수로 전달됩니다.

간단한 예시

// 오류 우선 콜백 패턴을 사용하는 함수 정의
function readFile(path, callback) {
  fs.readFile(path, "utf8", (err, data) => {
    // 오류가 발생하면 콜백의 첫 번째 매개변수로 전달
    if (err) {
      return callback(err);
    }

    // 성공 시 첫 번째 매개변수는 null, 두 번째 매개변수로 데이터 전달
    callback(null, data);
  });
}

// 함수 사용
readFile("/path/to/file.txt", (err, data) => {
  if (err) {
    console.error("파일 읽기 오류:", err);
    return;
  }

  console.log("파일 내용:", data);
});

Node.js 코어 모듈 예시

Node.js의 코어 모듈들은 오류 우선 콜백 패턴을 따릅니다. 예를 들어, fs 모듈의 메서드들은 다음과 같이 사용됩니다:

const fs = require("fs");

// 파일 읽기
fs.readFile("/path/to/file.txt", "utf8", (err, data) => {
  if (err) {
    console.error("파일 읽기 오류:", err);
    return;
  }

  console.log("파일 내용:", data);
});

// 파일 쓰기
fs.writeFile("/path/to/file.txt", "Hello, World!", (err) => {
  if (err) {
    console.error("파일 쓰기 오류:", err);
    return;
  }

  console.log("파일 쓰기 완료");
});

자신만의 함수에서 오류 우선 콜백 사용하기

사용자 정의 비동기 함수에서도 이 패턴을 적용할 수 있습니다:

function getUserData(userId, callback) {
  // 데이터베이스 조회 등의 비동기 작업 가정
  if (!userId) {
    // 유효하지 않은 입력일 경우 오류 객체 전달
    return callback(new Error("유효하지 않은 사용자 ID"));
  }

  // 비동기 작업 시뮬레이션
  setTimeout(() => {
    // 사용자 데이터 조회 성공 가정
    const userData = {
      id: userId,
      name: "홍길동",
      email: "hong@example.com",
    };

    // 성공 시 null과 함께 데이터 전달
    callback(null, userData);
  }, 1000);
}

// 함수 사용
getUserData("user123", (err, user) => {
  if (err) {
    console.error("사용자 데이터 조회 오류:", err);
    return;
  }

  console.log("사용자 정보:", user);
});

// 오류 상황 테스트
getUserData(null, (err, user) => {
  if (err) {
    console.error("사용자 데이터 조회 오류:", err);
    return;
  }

  console.log("사용자 정보:", user);
});

오류 우선 콜백 패턴의 장점

  1. 일관성: Node.js 생태계 전반에 걸쳐 동일한 패턴을 사용함으로써 코드의 일관성을 유지합니다.
  2. 명확한 오류 처리: 오류 처리 로직이 명확하게 분리되어 있어 가독성이 향상됩니다.
  3. 흐름 제어: 오류가 발생했을 때 즉시 함수 실행을 중단하고 적절한 오류 처리를 할 수 있습니다.

오류 우선 콜백 패턴의 단점

  1. 콜백 지옥: 여러 비동기 작업을 순차적으로 처리해야 할 경우 콜백이 중첩되어 '콜백 지옥'이 발생할 수 있습니다.
  2. 오류 전파 복잡성: 중첩된 콜백에서 오류를 상위 레벨로 전파하는 것이 복잡해질 수 있습니다.
  3. 코드 가독성 저하: 콜백이 많아질수록 코드의 가독성이 떨어질 수 있습니다.

대안: Promise와 async/await

오류 우선 콜백 패턴의 단점을 극복하기 위해 최신 Node.js에서는 Promise와 async/await를 사용할 수 있습니다:

// Promise 사용
const fs = require("fs").promises;

fs.readFile("/path/to/file.txt", "utf8")
  .then((data) => {
    console.log("파일 내용:", data);
  })
  .catch((err) => {
    console.error("파일 읽기 오류:", err);
  });

// async/await 사용
async function readFileAsync() {
  try {
    const data = await fs.readFile("/path/to/file.txt", "utf8");
    console.log("파일 내용:", data);
  } catch (err) {
    console.error("파일 읽기 오류:", err);
  }
}

readFileAsync();

Promise와 async/await를 사용하면 코드가 더 깔끔해지고 오류 처리도 직관적으로 할 수 있지만, Node.js의 많은 레거시 코드와 라이브러리에서는 여전히 오류 우선 콜백 패턴이 널리 사용되고 있으므로 이 패턴을 이해하는 것이 중요합니다.

콜백 함수를 Promise로 변환하기

기존의 오류 우선 콜백 기반 함수를 Promise로 래핑하여 사용할 수 있습니다:

const fs = require("fs");

// 오류 우선 콜백 함수를 Promise로 래핑
function readFilePromise(path) {
  return new Promise((resolve, reject) => {
    fs.readFile(path, "utf8", (err, data) => {
      if (err) {
        reject(err);
      } else {
        resolve(data);
      }
    });
  });
}

// Promise 사용
readFilePromise("/path/to/file.txt")
  .then((data) => {
    console.log("파일 내용:", data);
  })
  .catch((err) => {
    console.error("파일 읽기 오류:", err);
  });

// Node.js의 util.promisify 사용
const util = require("util");
const readFile = util.promisify(fs.readFile);

readFile("/path/to/file.txt", "utf8")
  .then((data) => {
    console.log("파일 내용:", data);
  })
  .catch((err) => {
    console.error("파일 읽기 오류:", err);
  });

결론

오류 우선 콜백 패턴은 Node.js에서 비동기 작업의 결과를 처리하는 표준적인 방식입니다. 이 패턴은 일관된 오류 처리 방법을 제공하지만, 복잡한 비동기 흐름에서는 가독성 문제를 일으킬 수 있습니다. 최신 JavaScript의 Promise와 async/await를 사용하면 이러한 문제를 해결할 수 있지만, Node.js 생태계의 많은 부분에서 여전히 오류 우선 콜백 패턴이 사용되므로 이 패턴의 원리와 사용법을 이해하는 것이 중요합니다.

results matching ""

    No results matching ""