본문으로 건너뛰기
yceffort
PostsSeriesTagsAbout🧪 Research
EN

Tweaks

theme
accent palette
film grain
minimal mode
BACK TO INDEX
◆ ESSAY
--min
--year
KOoriginal

mailMail icongithubtwitter
yceffort
•
© 2026
•
https://yceffort.kr
BACK TO INDEX
◆ ESSAY

개발자가 알아야 하는 4가지 nodejs 디자인 패턴

avatar
yceffort
2021-01-11 · 8분
8min
2021year
KOoriginal
nodejsdesign-patterns

디자인 패턴에는 세가지 유형이 있다.

  • Creational: 객체 인스턴스 생성
  • Structural: 객체 설계 방식
  • Behavioural: 객체가 상호 작용하는 방식

Singleton

클래스의 단일 인스턴스만을 원할 때 이 패턴을 사용한다. 즉, 여러개의 인스턴스를 생성하는 것이 아니라 하나만 생성하는 것이다. 인스턴스가 없다면 새 인스턴스를 생성한다. 인스턴스가 있는 경우에는, 해당 인스턴스를 사용한다.

class DatabaseConnection {
  constructor() {
    this.databaseConnection = 'dummytext'
  }

  getNewDBConnection() {
    return this.databaseConnection
  }
}

class Singleton {
  constructor() {
    throw new Error('Use the getInstance() method on the Singleton object!')
  }

  getInstance() {
    if (!Singleton.instance) {
      Singleton.instance = new DatabaseConnection()
    }

    return Singleton.instance
  }
}

module.exports = Singleton

위에서 보이는 것 처럼, 싱클턴을 구축할 수 있는 많은 예제가 있다. 이 외에 이 설계 패턴을 구현하는 더 짧은 방법이 있다.

class DatabaseConnection {
  constructor() {
    this.databaseConnection = 'dummytext'
  }

  getNewDBConnection() {
    return this.databaseConnection
  }
}

module.exports = new DatabaseConnection()

이것이 작동할 수 있는 이유는 module caching system 이다. module caching system이란, 모듈이 처음 로딩 된 이후에 캐싱이 되는 것을 의미한다. 즉, 위의 예제에서는, 새롭게 exported된 인스턴스는 캐싱이 되며, 이것이 재 사용될 때마다 이 캐쉬댄 내용을 불러온다는 뜻이다.

따라서,Nodejs에서 싱글턴을 구현하는 방법은 위 처럼 두가지로 볼 수 있다.

요약

  • 싱클턴 방식은 단 하나의 클래스 인스턴스가 필요할 때 유용하다.
  • Nodejs에서는, module caching system을 활용해서 export한 모듈을 바로 쓸 수 있다.

팩토리

팩토리 디자인 패턴은, 객체를 생성하는데 사용되는 인터페이스 또는 추상 클래스를 정의 하는 것이다. 이렇게 생성된 인터페이스 및 추상클래스를 사용하여 다른 객체를 초기화 한다. 아래의 예를 살펴보자.

import Motorvehicle from './Motorvehicle'
import Aircraft from './Aircraf'
import Railvehicle from './Railvehicle'

const VehicleFactory = (type, make, model, year) => {
  if (type === car) {
    return new Motorvehicle('car', make, model, year)
  } else if (type === airplane) {
    return new Aircraft('airplane', make, model, year)
  } else if (type === helicopter) {
    return new Aircraft('helicopter', make, model, year)
  } else {
    return new Railvehicle('train', make, model, year)
  }
}

module.exports = VehicleFactory

이렇게 각 클래스 인스턴스를 별개로 만드는 대신에, VehicleFactory를 활용해서 타입을 명시하는 방법을 택할 수 있다. 위 예제를 활용해서, car 인스턴스를 만들려면 아래처럼 실행하면 된다.

// 첫번째 매개변수에서 타입을 지정하고, 나머지는 그대로 변수를 넘긴다.
const audiAllRoad = VehicleFactory('car', 'Audi', 'A6 Allroad', '2020')

팩토리 디자인 패턴을 사용하면 객체의 구조가 객체 그 자체 사이를 디커플링 시킬 수 있다는 장점이 있다. 기존 코드를 손상시키지 않더라도 새 객체를 응용프로그램에 사용할 수 있다. 마지막으로, 인스턴스 생성과 관련된 모든 코드가 한 곳에 있으므로 코드를 더 잘 꾸밀 수 있다.

요약

  • 팩토리 디자인 패턴은 객체 생성을 위한 인터페이스 및 추상 클래스를 제공한다.
  • 동일한 인터페이스 및 추상 클래스를 사용하여 다른 객체를 만들 수 있다.
  • 코드의 구조를 개선하고 유지관리가 더 쉬워 진다.

빌더

빌더 디자인 패턴 또한 마찬가지로 객체 구조와 객체를 분리할 수 있다. 따라서 복잡한 객체를 생성하는 코드를 단순화 한다. 단순한 객체를 만들 때는 과한 기능일 수 있지만, 복잡한 객체를 만들 때는 단순화 하는데 도움을 준다.

class Car {
  constructor(make, model, year, isForSale = true, isInStock = false) {
    this.make = make
    this.model = model
    this.year = year
    this.isForSale = isForSale
    this.isInStock = isInStock
  }

  toString() {
    return console.log(JSON.stringify(this))
  }
}

class CarBuilder {
  constructor(make, model, year) {
    this.make = make
    this.model = model
    this.year = year
  }

  notForSale() {
    this.isForSale = false

    return this
  }

  addInStock() {
    this.isInStock = true

    return this
  }

  build() {
    return new Car(
      this.make,
      this.model,
      this.year,
      this.isForSale,
      this.isInStock,
    )
  }
}

module.exports = CarBuilder

위 패턴을 사용하면 Car 대신에 CarBuilder를 사용하여 객체를 만들 수 있다.

const CarBuilder = require('./CarBuilder')

const bmw = new CarBuilder('bmw', 'x6', 2020).addInStock().build()
const audi = new CarBuilder('audi', 'a8', 2021).notForSale().build()
const mercedes = new CarBuilder('mercedes-benz', 'c-class', 2019).build()

만약에 이런 빌더 패턴 없이 복잡한 객체를 만들게 되면 에러를 발생할 가능성이 커진다.

const bmw = new CarBuilder('bmw', 'x6', 2020, true, true)

뒤 이어 있는 true가 각각 무엇을 의미하는지 알아야 하기 때문에 객체 생성이 복잡해 지고, 에러를 만들어낼 가능성이 커진다. 따라서 빌더 디자인 패턴은 복잡한 객체 생성과 사용을 분리하는데 도움을 준다.

프로토타입

자바스크립트는 프로토타입 기반 언어이기 때문에, 프로토타입으로 상속이 구현되어 있다. 이 말인 즉슨, 모든 객체는 어떤 객체를 상속하고 있다는 뜻이다.

따라서 이른바 예제 객체 라고 불리우는 프로토타입 객체의 값을 복제 하여 새로운 객체를 만든다. 이는 프로토 타입이 새 객체의 일종의 청사진 역할을 하는 것이다. 이 설계 패턴을 활용하면 객체에 정의된 함수가 참조에 의해 생성된다는 이점을 얻을 수 있다. 즉, 모든 객체가 해당 기능의 복사본을 보유하는 것이 아니라 동일한 기능을 가르키게 된다. 간단히 말해, 프로토타입 기능은 프로토타입에 상속된 모든 객체에 사용할 수 있다.

const atv = {
  make: 'Honda',
  model: 'Rincon 650',
  year: 2018,
  mud: () => {
    console.log('Mudding')
  },
}

const secondATV = Object.create(atv)

프로토타입에서 새로운 객체를 생성하기 위해서는, Object.create()를 활용하면 된다. 두번째 객체인 secondATV는 첫번째 객체인 atv와 같은 값을 가지게 된다. mud()를 호출해보면 같은 값을 찍는 것을 알 수 있다.

프로토타입 디자인 패턴을 활용하는 다른 방법은 클래스 안에 프로토타입을 명시하는 것이다.

const atvPrototype = {
  mud: () => {
    console.log('Mudding')
  },
}

function Atv(make, model, year) {
  function constructor(make, model, year) {
    this.make = make
    this.model = model
    this.year = year
  }

  constructor.prototype = atvPrototype

  let instance = new constructor(make, model, year)
  return instance
}

const atv1 = Atv()
const atv2 = Atv('Honda', 'Rincon 650', '2018')

마찬가지로 두 인스턴스 모두 atv 객체에 정의된 항목에 액세스 할 수 있다.

결론적으로, 프로토타입 설계 패턴은 객체가 동일한 기능 또는 속성을 공유하기를 원할 때 유용하다.

요약

  • 자바스크립트는 프로토타입 기반 언어다.
  • 프로토타입 기반 상속을 사용한다.
  • 각 객체는 다른 객체로 부터 상속된다.
  • 새 객체는 프로토타입이라는 일종의 청사진에 따라 생성된다.
  • 프로토타입에 정의된 함수는 모든 새 클래스에서 상속된다.
  • 새 클래스는 개별 복사본을 갖는 대신 동일한 기능을 가리킨다.

관련 글

  • ◆ OG 스크래핑 서버 설계 노트
    #nodejs#security#ssrf

    OG 스크래핑 서버를 Node.js로 짓는다면 (2): SSRF는 어떻게 뚫리는가

    사용자가 준 URL을 서버가 대신 여는 기능은 SSRF의 교과서적 조건을 명세로 갖고 있다. 화이트리스트를 뚫는 우회 여섯 가지를 먼저 보고, 그것을 막는 방어 원리 다섯 개를 Node에서 실제로 돌려본 기록. 손으로 IPv4-mapped를 벗기면 16진 표기에서 뚫리고, undici의 lookup 훅은 호스트가 IP 리터럴이면 아예 호출되지 않으며, URL.hostname은 IPv6 리터럴의 대괄호를 남긴다. OG 스크래핑 서버 설계 노트 2부작의 마지막 편이다.

    2026-08-22·39분
  • ◆ OG 스크래핑 서버 설계 노트
    #nodejs#web#scraping

    OG 스크래핑 서버를 Node.js로 짓는다면 (1): 런타임 선택부터 에러율과 지연까지

    링크 미리보기 서버의 "에러율 10%"는 성질이 다른 다섯 종류의 실패가 뭉친 숫자다. 이 워크로드가 왜 I/O 바운드에 저 TPS인지, 런타임 선택이 실제로 갈리는 네 지점은 어디인지 따져본 뒤, User-Agent와 인코딩으로 에러율을 낮추는 일로 넘어간다. Node 내장 TextDecoder는 CP949 확장 문자를 에러 없이 다른 글자로 바꾸고, 스크랩해 온 og:title은 API 응답이 아니라 사용자 입력이다. 캐시 스탬피드와 negative caching, 그리고 "P95 1초 미만"을 캐시 히트율에서 역산해 검증하는 200만 건 시뮬레이션까지 담았다. OG 스크래핑 서버 설계 노트 2부작의 첫 편이다.

    2026-08-22·53분
  • ◆ 프론트엔드 개발자가 알아야 할 쿠버네티스
    #kubernetes#autoscaling#nextjs

    오토스케일링은 자동이지만 즉시가 아니다: HPA의 시간을 구간별로 실측한 기록

    트래픽을 12배로 올리고 새 파드가 첫 요청을 받기까지 31.5초. 그 31.5초의 내역서를 스톱워치로 뽑았다. 감지 창이 지배하는 구조, 배포 직후 5분 창에서 오토스케일러가 눈을 잃는 조건, 안정화 창의 계단, 메모리 HPA가 Node에서 불발되는 이유, KEDA의 선제 확장까지. 프론트엔드 개발자를 위한 쿠버네티스 시리즈의 다섯 번째 편이다.

    2026-08-10·39분
  • ◆ 프론트엔드 개발자가 알아야 할 쿠버네티스
    #kubernetes#nextjs#nodejs

    파드는 어떻게 종료되는가: 배포 중 에러의 원인과 해결을 실측한 기록

    코드를 한 줄도 바꾸지 않은 배포에서도 에러는 샌다. 롤링 배포 중 새는 실패를 유형과 시각까지 태깅해 원인 네 가지를 부검하고, 처방을 한 층씩 얹어 0으로 만들기까지의 실측 기록이다. Next.js의 종료 코드 원문과 인질 드레인, CrashLoopBackOff의 실제 시간표까지. 프론트엔드 개발자를 위한 쿠버네티스 시리즈의 네 번째 편이다.

    2026-08-08·36분

새 글을 놓치고 싶지 않으시다면 RSS로 구독해 주세요.

RSS 구독 →

yceffort — 프론트엔드 엔지니어입니다. 발표·기술 자문·기고 문의는 이곳에서 받고 있습니다.

← Back to the blogIssue on GitHub →