본문 바로가기
Development

[21.01.13] YDKJSY - The Module Pattern

by igy95 2024. 1. 7.

Encapsulation and Least Exposure

캡슐화는 종종 OOP의 원리로 인용된다. 하지만 이 개념은 더 포괄적인 영역을 맡고 있고, 최근 컴포넌트 기반 아키텍처의 어플리케이션을 설계하는 프론트 엔드 개발 영역에 이끄는 트렌드로 작용하고 있다. 캡슐화를 이용하는 가장 큰 목적은 데이터와 기능의 가시성을 통제하는 데에 있다. 이는 이전 챕터에서 다루었던 '노출의 최소화'의 관점과 같은 맥락을 유지하고 있고 JS에서는 렉시컬 스코프의 기술을 통해 이 관점을 지키고 있다.

 

이러한 노력의 자연스러운 결과는 결국 더 나은 코드의 체계화를 지향한다는 것이다. 어떤 경계를 기준으로 무엇이 어디 있는지 쉽게 알 수 있다는 것은 소프트웨어의 유지보수를 더 용이하게 하고 데이터와 기능의 외부 스코프로 무방비한 노출을 예방함으로 안정성을 높일 수 있다.

What Is a Module?

모듈은 관련된 데이터와 기능(메소드)들의 집합이다. 이러한 정보들은 또 private 과 public 의 성격을 띄며 나누어질 수 있다. 모듈이 어떤 것인지 좀 더 자세히 알기 위해, '모듈은 아니지만' 그러한 특성을 띄고 있는 몇몇 코드 패턴을 비교해보자.

Namespaces (Stateless Grouping)

// namespace, not module
var Utils = {
    cancelEvt(evt) {
        evt.preventDefault();
        evt.stopPropagation();
        evt.stopImmediatePropagation();
    },
    wait(ms) {
        return new Promise(function c(res){
            setTimeout(res,ms);
        });
    },
    isValidEmail(email) {
        return /[^@]+@[^@.]+\.[^@.]+/.test(email);
    }
};

데이터가 없이 무상태의 함수만을 그룹화 해놓은 이러한 코드 패턴은 'namespace'라고 부르는 게 더 정확하다.

Data Structures (Stateful Grouping)

// data structure, not module
var Student = {
    records: [
        { id: 14, name: "Kyle", grade: 86 },
        { id: 73, name: "Suzy", grade: 87 },
        { id: 112, name: "Frank", grade: 75 },
        { id: 6, name: "Sarah", grade: 91 }
    ],
    getName(studentID) {
        var student = this.records.find(
            student => student.id == studentID
        );
        return student.name;
    }
};

Student.getName(73);
// Suzy

이 구조는 데이터와 기능을 모두 하나의 스코프로 번들링하고는 있지만, 데이터의 가시성을 통제하지는 못하고 있다. records 가 어디서든 접근 가능하다는 점에서 이 구조는 모듈이라기보다는 하나의 자료 구조에 가까운 형태를 띄고 있다.

Modules (Stateful Access Control)

모듈을 구현하기 위한 조건은 '데이터의 그룹화'와 '가시성의 통제', 총 두가지로 볼 수 있다. 또 모듈을 통해 인스턴스를 하나만 얻을 것인지, 혹은 다수의 인스턴스를 만들어줄 것인지 그 용도에 따라 분류가 가능하다. 한 개의 인스턴스만을 필요로 하는 모듈은 보통 IIFE 를 통해 만들어주게 되는데 이를 'singleton'이라고 한다. 반대로 여러 개의 인스턴스가 필요하다면 그냥 모듈을 함수 형태로 만들고 필요할 때마다 호출 할당을 해주면 된다. 이것은 'module factory'라고도 한다.

 

classic module로 분류할 수 있는 조건은 다음과 같다.

 

  • 최소 하번은 실행되는 모듈 팩토리 함수로부터, 외부 스코프일 것.
  • 모듈의 내부 스코프는 모듈에 대한 상태를 나타내는 숨겨진 정보를 하나라도 갖고 있을 것.
  • 모듈은 public API 로 숨겨진 모듈 상태에 대한 함수 참조를 하나라도 반환할 것(클로저 이용).

Exit Scope

모듈의 대해 어떤 포맷을 사용하든 간에, 모듈은 프로그램의 데이터와 기능들을 구조화하고 체계화하는데 가장 효율적인 방법이다. 또한 모듈은 Scope & Closure 파트에서 변수와 함수를 적절한 곳에 위치시키기 위해 렉시컬 스코프를 어떻게 사용해야하는지에 대한 최종 종착지라고 할 수 있다. 왜냐하면 모듈의 방식에서, 우리가 모듈의 state를 유지할 수 있는 이유는 렉시컬 스코프 시스템의 영향을 받은 클로저가 존재하기 때문이다.