핵심 인사이트 (3줄 요약)
- 본질: 모듈 패턴 (Module Pattern)은 클로저 (Closure)로 private 상태를 감춘 뒤, 공개할 메서드만 반환해 정보 은닉 (Information Hiding)과 응집된 API (Application Programming Interface)를 만드는 구조다.
- 가치: 전역 네임스페이스 오염과 내부 구현 노출을 줄여, 초기 JavaScript 같은 환경에서도 클래스 없이 캡슐화와 책임 경계를 만들 수 있다.
- 판단 포인트: 현대 프로젝트에서는 ECMAScript Module을 우선 쓰되, 런타임 private 상태를 강하게 숨기거나 레거시 브라우저·플러그인 구조를 유지해야 할 때 모듈 패턴이 여전히 유효하다.
Ⅰ. 개요 및 필요성
모듈 패턴은 관련된 데이터와 함수를 하나의 폐쇄된 스코프에 묶고, 외부에는 제한된 인터페이스만 노출하는 설계 방식이다. 초기 JavaScript 환경에서는 파일을 로드하는 순간 전역 객체 window에 값이 흩어지기 쉬웠고, 라이브러리끼리 같은 변수명이나 함수명을 사용하면 충돌이 자주 발생했다. 또한 내부 헬퍼 함수와 임시 상태까지 전부 외부에서 접근 가능하면, 구현 교체가 곧 외부 호환성 문제로 번졌다.
이 문제를 줄이기 위해 즉시 실행 함수 표현식 (IIFE, Immediately Invoked Function Expression)과 클로저를 이용한 모듈 패턴이 널리 쓰였다. 핵심은 단순하다. 함수 하나를 경계로 private 영역을 만든 뒤, 필요한 메서드만 객체 형태로 반환한다. 그러면 외부는 "무엇을 할 수 있는가"만 알고, "안에서 어떻게 처리하는가"는 몰라도 된다.
┌──────────────────────────────────────────────────────────────────────┐
│ Global namespace vs module boundary │
├────────────────────────────┬─────────────────────────────────────────┤
│ window.user │ AppModule │
│ window.config │ ├─ private state │
│ window.cache │ ├─ private helpers │
│ name collision risk │ └─ public API only │
│ implementation exposed │ implementation hidden │
└────────────────────────────┴─────────────────────────────────────────┘
즉 모듈 패턴은 "코드를 예쁘게 묶는 취향"이 아니라, 전역 노출 비용을 줄이고 변경 영향을 통제하기 위한 경계 설계에서 출발했다.
- 📢 섹션 요약 비유: 물건을 거실 바닥에 다 꺼내 놓으면 누구나 건드리고 섞이기 쉽다. 모듈 패턴은 서랍장을 만들어 필요한 손잡이만 밖으로 내놓는 방식이다.
Ⅱ. 아키텍처 및 핵심 원리
모듈 패턴의 런타임 동작은 세 단계로 볼 수 있다. 첫째, IIFE나 팩터리 함수가 실행되며 lexical scope가 만들어진다. 둘째, 그 내부에 private 변수와 helper 함수를 둔다. 셋째, 외부에 보여 줄 메서드만 담은 객체를 반환한다. 반환된 메서드들은 클로저를 통해 내부 스코프를 계속 참조하므로, 함수 실행이 끝난 뒤에도 private 상태가 살아남는다.
const cartModule = (() => {
let totalPrice = 0;
function validate(price) {
return Number.isFinite(price) && price >= 0;
}
return {
add(price) {
if (validate(price)) totalPrice += price;
},
total() {
return totalPrice;
}
};
})();
| 구성 요소 | 역할 | 설계 포인트 |
|---|---|---|
| private state | 외부에 숨길 데이터 저장 | 직접 참조를 노출하지 않아야 진짜 은닉이 됨 |
| private helper | 검증, 변환, 캐시 계산 | public 메서드보다 자유롭게 변경 가능 |
| public API | 외부가 사용하는 진입점 | 이름과 계약을 안정적으로 유지해야 함 |
| closure | private 상태 지속 | 함수가 끝난 뒤에도 상태가 유지되는 핵심 메커니즘 |
┌──────────────────────────────────────────────────────────────────────┐
│ Runtime structure of Module Pattern │
├──────────────────────────────────────────────────────────────────────┤
│ IIFE / factory execution │
│ ├─ private state : data, cache, counters │
│ ├─ private helpers : validate, normalise, format │
│ └─ return public API object │
│ │ │
│ Client call ----▼------------------------------------------------┐ │
│ api.method() -> closure -> private state read/write -> result │ │
└───────────────────────────────────────────────────────────────────┴───┘
여기서 자주 놓치는 사실이 하나 있다. IIFE 기반 모듈 패턴은 보통 한 번 생성된 싱글턴이다. 만약 사용자별 인스턴스를 여러 개 만들어야 한다면, 모듈 패턴보다 팩터리 함수나 클래스가 더 적합할 수 있다. 반대로 "애플리케이션 전체에서 하나만 있어야 하는 설정, 캐시, 로그 채널"처럼 공유 상태가 자연스러운 경우에는 장점이 된다.
- 📢 섹션 요약 비유: 모듈 패턴은 가게 주방을 벽으로 가리고 주문창만 내놓는 구조와 같다. 손님은 메뉴를 주문할 수 있지만, 주방 안 냉장고와 조리 순서를 직접 건드리지는 못한다.
Ⅲ. 비교 및 연결
모듈 패턴을 정확히 이해하려면 "단순 네임스페이스", "클래스", "언어 차원의 모듈"과 구분해야 한다. 이름이 비슷해도 은닉 수준과 생성 방식이 다르다.
| 비교 대상 | 은닉 방식 | 인스턴스 모델 | 장점 | 한계 |
|---|---|---|---|---|
| 네임스페이스 객체 | 관례상 구분 | 보통 싱글턴 | 단순함 | 실제 private 보장 없음 |
| 모듈 패턴 | 클로저 스코프 | 보통 싱글턴 | 강한 런타임 은닉 | 정적 분석, tree-shaking에 불리 |
| 클래스 + private 필드 | 언어 문법 | 다중 인스턴스 | 타입/상속과 궁합 좋음 | 초기 JS 환경에는 부적합 |
| ECMAScript Module | 파일 스코프 | 모듈 캐시 기반 | import/export, 정적 의존성 분석 | 파일 단위 이상 세밀한 런타임 은닉은 별도 설계 필요 |
또한 모듈 시스템의 역사 흐름에서도 의미가 있다. 전역 변수 시대에는 이름 충돌이 가장 큰 문제였고, 이를 줄이기 위한 중간 해법이 모듈 패턴이었다. 이후 CommonJS, AMD (Asynchronous Module Definition), UMD (Universal Module Definition), ECMAScript Module이 등장하면서 의존성 관리와 번들링은 언어·도구 차원으로 올라갔다. 즉 모듈 패턴은 "현대 모듈 시스템 이전의 과도기적 해법"이면서도, 동시에 클로저 기반 캡슐화의 원형이다.
- 📢 섹션 요약 비유: 네임스페이스는 물건에 라벨만 붙이는 정도이고, 모듈 패턴은 자물쇠 달린 서랍장이다. ECMAScript Module은 건물 설계도 자체에 방과 문을 나눠 놓는 수준이다.
Ⅳ. 실무 적용 및 기술사 판단
실무에서 모듈 패턴은 레거시 브라우저 코드, jQuery 플러그인, 서드파티 위젯, 공용 설정 관리자 같은 영역에서 자주 만난다. 특히 외부에는 작은 API만 노출하고, 내부에서는 캐시·카운터·상태 전이를 숨기고 싶을 때 유용하다. 반대로 화면 컴포넌트처럼 동일 구조를 여러 개 만들어야 한다면, 클래스나 팩터리 함수가 더 자연스럽다.
적용 판단 체크리스트
- 애플리케이션 전체에서 공유할 단일 상태가 필요한가?
- 외부에 보여 줄 API는 작고 안정적이지만, 내부 구현은 자주 바뀔 가능성이 큰가?
import/export기반 정적 의존성 분석보다 런타임 은닉이 더 중요한가?- 테스트를 위해 외부 의존성을 주입할 수 있게 설계했는가?
- 여러 인스턴스가 필요한 문제를 억지로 싱글턴 모듈로 풀고 있지는 않은가?
자주 발생하는 안티패턴
- 하나의 모듈 안에 화면 제어, 네트워크 호출, 도메인 로직을 모두 넣어 거대한 God Module로 만드는 것
- private 배열이나 객체를 그대로 반환해 외부가 내부 상태를 우회 수정하게 만드는 것
- 숨겨진 싱글턴 상태 때문에 테스트 순서에 따라 결과가 달라지는 것
- 레거시 대응이 아닌데도 최신 도구 체인을 포기하고 모듈 패턴만 고집하는 것
다음과 같은 경우가 대표적인 선택 기준이다.
- 레거시 브라우저 위젯: IIFE 기반 모듈 패턴 적합
- 현대 프런트엔드 라이브러리: ECMAScript Module 우선
- 여러 독립 인스턴스가 필요한 객체: 클래스 또는 팩터리 함수 우선
- 민감한 내부 상태를 최소 API로 감출 서비스 래퍼: 모듈 패턴 또는 closure factory 검토
즉 기술사 관점에서는 "모듈 패턴이 낡았는가"보다 "이 문제가 싱글턴 은닉 문제인가, 다중 인스턴스 모듈화 문제인가"를 먼저 구분하는 판단이 중요하다.
- 📢 섹션 요약 비유: 하나의 금고가 필요한 일에 서랍 수백 개짜리 캐비닛을 들여놓을 필요는 없다. 반대로 여러 사람이 따로 써야 하는 물건을 금고 하나에 몰아넣으면 오히려 불편해진다.
Ⅴ. 기대효과 및 결론
모듈 패턴의 기대효과는 명확하다. 전역 노출을 줄여 충돌 위험을 낮추고, public API만 계약으로 유지해 내부 변경 자유도를 높이며, 관련 기능을 응집된 단위로 묶어 이해 비용을 줄인다. 특히 "작은 외부 인터페이스, 숨겨진 내부 상태"가 중요한 라이브러리나 소프트웨어 개발 키트 (SDK, Software Development Kit)에서는 여전히 설계적 의미가 있다.
하지만 한계도 분명하다. 파일 간 의존성 추적이 어렵고, 정적 최적화나 tree-shaking에 불리하며, 잘못 쓰면 숨겨진 싱글턴 상태가 테스트와 유지보수를 더 어렵게 만든다. 그래서 현대 코드베이스에서는 ECMAScript Module을 기본으로 두고, 그 위에 필요할 때만 클로저 기반 은닉을 덧씌우는 방식이 더 현실적이다.
결국 모듈 패턴은 "예전 자바스크립트 관용구"로만 외울 것이 아니라, 공개 계약과 내부 구현을 분리하는 클로저 기반 캡슐화 원리로 기억해야 한다. 이 원리를 이해하면 현대 훅, 커스텀 스토어, 서비스 래퍼가 왜 그런 형태를 취하는지도 더 잘 보인다.
- 📢 섹션 요약 비유: 모듈 패턴은 오래된 공구처럼 보여도, 나사를 감추고 손잡이만 밖으로 내놓는 설계 감각은 지금도 유효하다. 도구는 바뀌어도 "무엇을 숨기고 무엇을 보여 줄지"의 원리는 남는다.
📌 관련 개념 맵
| 개념 | 연결 포인트 |
|---|---|
| 정보 은닉 (Information Hiding) | 모듈 패턴이 구현하려는 핵심 설계 원칙 |
| 클로저 (Closure) | private 상태를 유지하게 만드는 런타임 메커니즘 |
| IIFE (Immediately Invoked Function Expression) | 전통적 모듈 패턴의 대표 구현 수단 |
| ECMAScript Module | 현대 표준 모듈 시스템으로, 파일 단위 캡슐화 제공 |
| Revealing Module Pattern | 반환 객체에 공개 멤버만 명시적으로 나열하는 변형 |
| CommonJS / AMD | 모듈 패턴 이후 등장한 파일 기반 모듈 시스템 |
📈 관련 키워드 및 발전 흐름도
Global variables
│
▼
Namespace object
│
▼
Module Pattern (IIFE + Closure)
│
├─ CommonJS / AMD / UMD
│
▼
ECMAScript Module
│
▼
Modern closure-based hooks and service wrappers
이 흐름은 전역 스크립트 시대의 충돌 문제를 줄이기 위해 모듈 패턴이 등장했고, 이후 언어 차원의 모듈 시스템으로 발전했음을 보여 준다.
👶 어린이를 위한 3줄 비유 설명
- 모듈 패턴은 장난감을 넣어 두는 상자를 만들고, 밖에는 손잡이만 남겨 두는 것과 같아요.
- 그래서 친구는 손잡이를 잡고 필요한 기능만 쓸 수 있고, 상자 안 물건을 함부로 뒤지지는 못해요.
- 이렇게 하면 안에 무엇을 바꿔도 밖에서 쓰는 방법은 크게 안 바뀌어요.