DEV Community

Cover image for The Module Pattern — Encapsulate, Organize, Reuse
Md Enayetur Rahman
Md Enayetur Rahman

Posted on

The Module Pattern — Encapsulate, Organize, Reuse

A practical digest of “Learning Patterns” by Lydia Hallie & Addy Osmani

“A module keeps related code together and unrelated code out.” — Learning Patterns

Modern JavaScript gives us many ways to group behaviour, but the Module Pattern remains timeless: bundle variables and functions behind a clear public API while hiding implementation details.


1  Why Modules?

Hallie & Osmani frame modules as the answer to two perennial problems:

  1. Global‑scope pollution – scripts that stomp on each other’s variables.
  2. Mental overload – codebases with no obvious boundary lines.

Encapsulation tackles both: each module owns its name‑space and reveals only what consumers need.


2  Two Faces of the Module Pattern

2.1 Classic IIFE / Revealing Module

const Counter = (function () {
  // Private state
  let count = 0;

  // Private helper
  function log() {
    console.log(`Current count 👉 ${count}`);
  }

  // Public API
  return {
    increment() {
      count++;
      log();
    },
    reset() {
      count = 0;
      log();
    },
    value() {
      return count;
    },
  };
})();

Counter.increment(); // 1
Counter.value();     // 1
Counter.count;       // undefined (private!)
Enter fullscreen mode Exit fullscreen mode

How it works: an immediately‑invoked function expression creates a new scope; the returned object reveals only selected members.

2.2 ES Modules (ESM)

Since ES2015, the language itself provides first‑class modules:

//📄 math.js
let _cache = {};

export function square(n) {
  if (_cache[n]) return _cache[n];
  return (_cache[n] = n * n);
}

export const PI = 3.14159;

//📄 usage.js
import { square, PI } from "./math.js";
Enter fullscreen mode Exit fullscreen mode

export and import give the same encapsulation benefits with better tooling (tree‑shaking, static analysis).

Hallie & Osmani treat ESM as the modern evolution of the classic pattern—same goals, nicer syntax.


3  Real‑World Use Cases (5 examples)

# Scenario Why Modules Shine
1 Analytics SDK wrappers (e.g., Google Analytics, Mixpanel) Expose trackEvent() while hiding vendor‑specific setup & keys.
2 Feature‑flag / Config managers Keep environment secrets private; export a clean getFlag() API.
3 UI component libraries (Modal, Toast, Tooltip) Bundle markup, styling helpers, and state logic into one importable unit.
4 Service layer in Node micro‑services Each service (userService, emailService) exports operations; internal DB queries stay private.
5 Redux/Vuex slices & Zustand stores Encapsulate state + actions; consumers import hooks/selectors only.

These examples all echo the book’s advice: “When behaviour and data belong together, package them as a module.”


4  Pros & Cons

👍 Pros

  • Prevents accidental name collisions.
  • Clarifies boundaries for easier testing and refactoring.
  • Enables lazy‑loading and code‑splitting (ESM + dynamic import()).

⚠️ Cons

  • Over‑fragmentation can lead to “too many files” syndrome.
  • Misusing singletons (stateful modules) may complicate server‑side rendering.

Hallie & Osmani recommend treating modules as “cohesive homes for related code, not catch‑alls.”


5  Best Practices Checklist

  • Single Responsibility: one idea per module.
  • Explicit Exports: export only what callers need; keep the rest private.
  • Immutable Interfaces: changing a module’s API should be deliberate & versioned.
  • Documentation at Source: README or JSDoc next to the code.

6  Wrap‑up

The Module Pattern is older than modern JavaScript—but still essential. By packaging logic behind clear interfaces, you shrink mental overhead and grow reusability. Next time you catch your code leaking globals or mixing concerns, reach for this pattern.

Coming soon in #LearningPatterns24: the Observer Pattern!


This summary is based on concepts outlined in *“Learning Patterns” (Patterns.dev)** by Lydia Hallie & Addy Osmani. The original content is licensed CC BY‑NC 4.0.*

Top comments (0)