d9e5668cec
Fixes and improvements from exhaustive audit: Consistency fixes in SKILL.md: - 'Pipe & Filter' → 'Pipe and Filter' (one stray '&' found and corrected) - 'Singleton for factory instance' → clarified to 'register factory as singleton-scoped via DI container' (less misleading wording) - Documentation Format section updated with note that SKILL.md itself is the authoritative source for related-pattern combinations Coverage fix — Related Patterns sections: - Added '## Related Patterns' to ALL 94 pattern files (was 0/94) - Each section lists 3–6 related patterns with relationship descriptions - Covers: why they're related, when to prefer one vs the other, and which are often confused SOLID principles → Creational → Structural → Behavioral → Architectural → Concurrency → Functional → Resilience → Data Access → Messaging → Testing → Error Handling → Microservice — all 13 categories covered Code verification: - Python: 0 failures (all 85 testable blocks pass) - Go: 0 failures (all 76 testable blocks pass) - JavaScript: 0 failures (all 78 testable blocks pass) - All 239 code blocks verified correct after edits Final skill state: - 108 files, 36,524 lines across 13 reference categories - 94/94 pattern files have Related Patterns sections - 2,815-line SKILL.md with 67 decision trees, 23 scenarios, 0 broken references, 0 naming inconsistencies
9.3 KiB
9.3 KiB
Module Pattern
Encapsulate related functionality, data, and behavior into a single unit with a well-defined public API, hiding internal implementation details.
Problem
You have a set of related utility functions and state (e.g., a string utility library with internal helpers). Without encapsulation, all functions and variables pollute the global namespace, internal helpers are exposed, and there is no clear boundary between public and private.
Solution
Group related functionality into a module that exposes only a public API. Internal state and helper functions are hidden. In Python this is a module with __all__; in Go it's a package with unexported identifiers; in JavaScript it's a closure/IIFE or ES module with selective exports.
┌──────────────────────────────┐
│ StringUtils Module │
│ │
│ Public API: │
│ + capitalize(s) │
│ + slug(s) │
│ + word_count(s) │
│ + stats() │
│ │
│ Internal (hidden): │
│ - _call_count │
│ - _track_call() │
│ - _normalize_whitespace() │
└──────────────────────────────┘
When to Use
- You want to group related functions and state with a clear public/private boundary.
- You need to avoid polluting the global namespace.
- You want to enforce encapsulation without full OOP class hierarchies.
- You are building a utility library or service layer.
When to Avoid
- The functionality is a single function — just export the function directly.
- You need multiple instances with separate state — use a class or factory instead.
- The language has first-class module support and you'd just be wrapping it redundantly.
Pseudocode
module StringUtils:
// Private state
_call_count = 0
// Private helper
function _track_call():
_call_count += 1
function _normalize_whitespace(s):
return collapse multiple spaces in s to single spaces, trimmed
// Public API
function capitalize(s):
_track_call()
return first letter uppercase + rest of s
function slug(s):
_track_call()
return _normalize_whitespace(s).lower().replace(" ", "-")
function word_count(s):
_track_call()
return number of words in _normalize_whitespace(s)
function stats():
return { calls: _call_count }
// Usage
print StringUtils.capitalize("hello world")
print StringUtils.slug("Hello Big World")
print StringUtils.word_count("one two three")
print StringUtils.stats()
Python
"""
string_utils module — demonstrates the Module pattern.
Only symbols listed in __all__ are part of the public API.
"""
# --- Private state ---
_call_count = 0
# --- Private helpers ---
def _track_call() -> None:
global _call_count
_call_count += 1
def _normalize_whitespace(s: str) -> str:
"""Collapse multiple spaces and strip."""
return " ".join(s.split())
# --- Public API ---
def capitalize(s: str) -> str:
"""Capitalize the first letter of the string."""
_track_call()
if not s:
return s
return s[0].upper() + s[1:]
def slug(s: str) -> str:
"""Convert to a URL-friendly slug."""
_track_call()
return _normalize_whitespace(s).lower().replace(" ", "-")
def word_count(s: str) -> int:
"""Count words in a string."""
_track_call()
normalized = _normalize_whitespace(s)
return len(normalized.split()) if normalized else 0
def stats() -> dict:
"""Return usage statistics."""
return {"total_calls": _call_count}
__all__ = ["capitalize", "slug", "word_count", "stats"]
if __name__ == "__main__":
print("=== Module Pattern: StringUtils ===")
print()
result1 = capitalize("hello world")
print(f"capitalize('hello world') => '{result1}'")
result2 = slug("Hello Big World")
print(f"slug('Hello Big World') => '{result2}'")
result3 = word_count(" one two three ")
print(f"word_count(' one two three ') => {result3}")
result4 = slug("Another Test String")
print(f"slug('Another Test String') => '{result4}'")
print(f"\nstats() => {stats()}")
# Show that private members exist but are conventionally hidden
print(f"\n--- Internal state (not part of public API) ---")
print(f"_call_count = {_call_count}")
print(f"_normalize_whitespace(' a b ') = '{_normalize_whitespace(' a b ')}'")
Output:
=== Module Pattern: StringUtils ===
capitalize('hello world') => 'Hello world'
slug('Hello Big World') => 'hello-big-world'
word_count(' one two three ') => 3
slug('Another Test String') => 'another-test-string'
stats() => {'total_calls': 4}
--- Internal state (not part of public API) ---
_call_count = 4
_normalize_whitespace(' a b ') = 'a b'
Go
package main
import (
"fmt"
"strings"
"unicode"
)
// ============================================================
// stringutils "module" — unexported identifiers are private.
// In a real project this would be its own package.
// ============================================================
// private state
var callCount int
// private helper
func trackCall() {
callCount++
}
func normalizeWhitespace(s string) string {
return strings.Join(strings.Fields(s), " ")
}
// --- Public API (exported) ---
func Capitalize(s string) string {
trackCall()
if len(s) == 0 {
return s
}
runes := []rune(s)
runes[0] = unicode.ToUpper(runes[0])
return string(runes)
}
func Slug(s string) string {
trackCall()
return strings.ReplaceAll(strings.ToLower(normalizeWhitespace(s)), " ", "-")
}
func WordCount(s string) int {
trackCall()
normalized := normalizeWhitespace(s)
if normalized == "" {
return 0
}
return len(strings.Fields(normalized))
}
type Stats struct {
TotalCalls int
}
func GetStats() Stats {
return Stats{TotalCalls: callCount}
}
// ============================================================
func main() {
fmt.Println("=== Module Pattern: StringUtils ===")
fmt.Println()
r1 := Capitalize("hello world")
fmt.Printf("Capitalize(\"hello world\") => '%s'\n", r1)
r2 := Slug("Hello Big World")
fmt.Printf("Slug(\"Hello Big World\") => '%s'\n", r2)
r3 := WordCount(" one two three ")
fmt.Printf("WordCount(\" one two three \") => %d\n", r3)
r4 := Slug("Another Test String")
fmt.Printf("Slug(\"Another Test String\") => '%s'\n", r4)
fmt.Printf("\nGetStats() => %+v\n", GetStats())
}
Output:
=== Module Pattern: StringUtils ===
Capitalize("hello world") => 'Hello world'
Slug("Hello Big World") => 'hello-big-world'
WordCount(" one two three ") => 3
Slug("Another Test String") => 'another-test-string'
GetStats() => {TotalCalls:4}
JavaScript
// Module pattern using an IIFE to create a closure with private scope.
const StringUtils = (() => {
// --- Private state ---
let callCount = 0;
// --- Private helpers ---
function trackCall() {
callCount++;
}
function normalizeWhitespace(s) {
return s.trim().replace(/\s+/g, " ");
}
// --- Public API ---
return {
capitalize(s) {
trackCall();
if (!s) return s;
return s.charAt(0).toUpperCase() + s.slice(1);
},
slug(s) {
trackCall();
return normalizeWhitespace(s).toLowerCase().replace(/ /g, "-");
},
wordCount(s) {
trackCall();
const normalized = normalizeWhitespace(s);
return normalized === "" ? 0 : normalized.split(" ").length;
},
stats() {
return { totalCalls: callCount };
},
};
})();
// --- Main ---
console.log("=== Module Pattern: StringUtils ===\n");
const r1 = StringUtils.capitalize("hello world");
console.log(`capitalize('hello world') => '${r1}'`);
const r2 = StringUtils.slug("Hello Big World");
console.log(`slug('Hello Big World') => '${r2}'`);
const r3 = StringUtils.wordCount(" one two three ");
console.log(`wordCount(' one two three ') => ${r3}`);
const r4 = StringUtils.slug("Another Test String");
console.log(`slug('Another Test String') => '${r4}'`);
console.log(`\nstats() => ${JSON.stringify(StringUtils.stats())}`);
// Demonstrate that internals are truly hidden
console.log(`\n--- Attempting to access private state ---`);
console.log(`StringUtils.callCount => ${StringUtils.callCount}`); // undefined
console.log(`StringUtils.trackCall => ${StringUtils.trackCall}`); // undefined
Output:
=== Module Pattern: StringUtils ===
capitalize('hello world') => 'Hello world'
slug('Hello Big World') => 'hello-big-world'
wordCount(' one two three ') => 3
slug('Another Test String') => 'another-test-string'
stats() => {"totalCalls":4}
--- Attempting to access private state ---
StringUtils.callCount => undefined
StringUtils.trackCall => undefined
Related Patterns
- Facade — a facade provides a simplified interface over a subsystem; a module encapsulates a subsystem with explicit public/private boundaries.
- Singleton — a module is effectively a singleton in most module systems (loaded and cached once).
- Namespace — modules provide namespacing as a side effect, preventing name collisions in the global scope.