Files
freemo d9e5668cec fix(skills): comprehensive final audit pass for programming-patterns skill
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
2026-04-15 13:22:13 -04:00

12 KiB

Proxy Pattern

Provide a surrogate or placeholder for another object to control access to it.

Problem

You need to control how an object is accessed. Common scenarios:

  1. Virtual proxy — Delay expensive object creation until actually needed (lazy loading).
  2. Protection proxy — Restrict access based on permissions.
  3. Logging proxy — Log all interactions transparently.

Solution

Create a proxy class with the same interface as the real object. The proxy holds a reference to the real object and adds control logic (lazy init, access checks, logging) before/after delegating calls.

┌────────┐      ┌──────────────────┐
│ Client  │─────▶│ Service (intf)   │
└────────┘      │ + request()      │
                └──────┬───────────┘
                       │
               ┌───────┴───────┐
               │               │
          ┌────┴────┐    ┌─────┴─────┐
          │RealServ │    │   Proxy   │
          │         │    │ + real    │
          └─────────┘    │ + request│
                         └──────────┘

When to Use

  • Virtual proxy: The real object is expensive to create and may not always be needed.
  • Protection proxy: You need to check permissions before granting access.
  • Logging proxy: You want to record interactions without modifying the real object.
  • Caching proxy: You want to cache results of expensive operations.

When to Avoid

  • The added indirection is unnecessary for simple, inexpensive objects.
  • The proxy would duplicate logic that belongs in the real object.
  • You need to proxy many methods and a language-level mechanism (e.g., Python __getattr__, JS Proxy) would be cleaner.

Pseudocode

interface Database:
    method query(sql): string

class RealDatabase implements Database:
    constructor():
        output "Connecting to database... (expensive)"
    method query(sql):
        return "Result of: " + sql

// Virtual proxy — lazy init
class LazyDatabaseProxy implements Database:
    field real: Database = null
    method query(sql):
        if real is null:
            real = new RealDatabase()
        return real.query(sql)

// Protection proxy
class ProtectedDatabaseProxy implements Database:
    field real: Database
    field user_role: string
    constructor(real, role):
        this.real = real; this.user_role = role
    method query(sql):
        if user_role != "admin":
            output "ACCESS DENIED for role: " + user_role
            return null
        return real.query(sql)

// Logging proxy
class LoggingDatabaseProxy implements Database:
    field real: Database
    constructor(real): this.real = real
    method query(sql):
        output "[LOG] query: " + sql
        result = real.query(sql)
        output "[LOG] result: " + result
        return result

Python

from abc import ABC, abstractmethod


class Database(ABC):
    """Service interface."""

    @abstractmethod
    def query(self, sql: str) -> str: ...


class RealDatabase(Database):
    """Expensive real service."""

    def __init__(self) -> None:
        print("  [RealDB] Connecting to database... (expensive)")

    def query(self, sql: str) -> str:
        return f"Result of: {sql}"


# --- Virtual Proxy (lazy loading) ---

class LazyDatabaseProxy(Database):
    """Delays creation of RealDatabase until first use."""

    def __init__(self) -> None:
        self._real: RealDatabase | None = None

    def query(self, sql: str) -> str:
        if self._real is None:
            print("  [LazyProxy] First access — initializing real database")
            self._real = RealDatabase()
        return self._real.query(sql)


# --- Protection Proxy ---

class ProtectedDatabaseProxy(Database):
    """Checks user role before allowing queries."""

    def __init__(self, real: Database, user_role: str) -> None:
        self._real = real
        self._role = user_role

    def query(self, sql: str) -> str:
        if self._role != "admin":
            print(f"  [ProtectionProxy] ACCESS DENIED for role '{self._role}'")
            return "ACCESS DENIED"
        return self._real.query(sql)


# --- Logging Proxy ---

class LoggingDatabaseProxy(Database):
    """Logs every query transparently."""

    def __init__(self, real: Database) -> None:
        self._real = real

    def query(self, sql: str) -> str:
        print(f"  [LogProxy] Executing: {sql}")
        result = self._real.query(sql)
        print(f"  [LogProxy] Got: {result}")
        return result


if __name__ == "__main__":
    print("=== Virtual Proxy (lazy loading) ===")
    lazy_db = LazyDatabaseProxy()
    print("Proxy created, no DB connection yet.")
    print(lazy_db.query("SELECT * FROM users"))
    print(lazy_db.query("SELECT * FROM orders"))

    print("\n=== Protection Proxy ===")
    real_db = RealDatabase()
    admin_db = ProtectedDatabaseProxy(real_db, "admin")
    guest_db = ProtectedDatabaseProxy(real_db, "guest")
    print(admin_db.query("SELECT * FROM secrets"))
    print(guest_db.query("SELECT * FROM secrets"))

    print("\n=== Logging Proxy ===")
    logged_db = LoggingDatabaseProxy(real_db)
    print(logged_db.query("SELECT count(*) FROM users"))

Output:

=== Virtual Proxy (lazy loading) ===
Proxy created, no DB connection yet.
  [LazyProxy] First access — initializing real database
  [RealDB] Connecting to database... (expensive)
Result of: SELECT * FROM users
Result of: SELECT * FROM orders

=== Protection Proxy ===
  [RealDB] Connecting to database... (expensive)
Result of: SELECT * FROM secrets
  [ProtectionProxy] ACCESS DENIED for role 'guest'
ACCESS DENIED

=== Logging Proxy ===
  [LogProxy] Executing: SELECT count(*) FROM users
  [LogProxy] Got: Result of: SELECT count(*) FROM users
Result of: SELECT count(*) FROM users

Go

package main

import "fmt"

// Database is the service interface.
type Database interface {
	Query(sql string) string
}

// RealDatabase is the expensive real service.
type RealDatabase struct{}

func NewRealDatabase() *RealDatabase {
	fmt.Println("  [RealDB] Connecting to database... (expensive)")
	return &RealDatabase{}
}

func (db *RealDatabase) Query(sql string) string {
	return "Result of: " + sql
}

// --- Virtual Proxy ---

type LazyDatabaseProxy struct {
	real *RealDatabase
}

func (p *LazyDatabaseProxy) Query(sql string) string {
	if p.real == nil {
		fmt.Println("  [LazyProxy] First access — initializing real database")
		p.real = NewRealDatabase()
	}
	return p.real.Query(sql)
}

// --- Protection Proxy ---

type ProtectedDatabaseProxy struct {
	real Database
	role string
}

func NewProtectedProxy(real Database, role string) *ProtectedDatabaseProxy {
	return &ProtectedDatabaseProxy{real: real, role: role}
}

func (p *ProtectedDatabaseProxy) Query(sql string) string {
	if p.role != "admin" {
		fmt.Printf("  [ProtectionProxy] ACCESS DENIED for role '%s'\n", p.role)
		return "ACCESS DENIED"
	}
	return p.real.Query(sql)
}

// --- Logging Proxy ---

type LoggingDatabaseProxy struct {
	real Database
}

func NewLoggingProxy(real Database) *LoggingDatabaseProxy {
	return &LoggingDatabaseProxy{real: real}
}

func (p *LoggingDatabaseProxy) Query(sql string) string {
	fmt.Printf("  [LogProxy] Executing: %s\n", sql)
	result := p.real.Query(sql)
	fmt.Printf("  [LogProxy] Got: %s\n", result)
	return result
}

func main() {
	fmt.Println("=== Virtual Proxy (lazy loading) ===")
	lazyDB := &LazyDatabaseProxy{}
	fmt.Println("Proxy created, no DB connection yet.")
	fmt.Println(lazyDB.Query("SELECT * FROM users"))
	fmt.Println(lazyDB.Query("SELECT * FROM orders"))

	fmt.Println("\n=== Protection Proxy ===")
	realDB := NewRealDatabase()
	adminDB := NewProtectedProxy(realDB, "admin")
	guestDB := NewProtectedProxy(realDB, "guest")
	fmt.Println(adminDB.Query("SELECT * FROM secrets"))
	fmt.Println(guestDB.Query("SELECT * FROM secrets"))

	fmt.Println("\n=== Logging Proxy ===")
	loggedDB := NewLoggingProxy(realDB)
	fmt.Println(loggedDB.Query("SELECT count(*) FROM users"))
}

Output:

=== Virtual Proxy (lazy loading) ===
Proxy created, no DB connection yet.
  [LazyProxy] First access — initializing real database
  [RealDB] Connecting to database... (expensive)
Result of: SELECT * FROM users
Result of: SELECT * FROM orders

=== Protection Proxy ===
  [RealDB] Connecting to database... (expensive)
Result of: SELECT * FROM secrets
  [ProtectionProxy] ACCESS DENIED for role 'guest'
ACCESS DENIED

=== Logging Proxy ===
  [LogProxy] Executing: SELECT count(*) FROM users
  [LogProxy] Got: Result of: SELECT count(*) FROM users
Result of: SELECT count(*) FROM users

JavaScript

class RealDatabase {
  constructor() {
    console.log("  [RealDB] Connecting to database... (expensive)");
  }

  query(sql) {
    return `Result of: ${sql}`;
  }
}

// --- Virtual Proxy (lazy loading) ---

class LazyDatabaseProxy {
  constructor() {
    this._real = null;
  }

  query(sql) {
    if (this._real === null) {
      console.log(
        "  [LazyProxy] First access — initializing real database"
      );
      this._real = new RealDatabase();
    }
    return this._real.query(sql);
  }
}

// --- Protection Proxy ---

class ProtectedDatabaseProxy {
  constructor(real, role) {
    this._real = real;
    this._role = role;
  }

  query(sql) {
    if (this._role !== "admin") {
      console.log(
        `  [ProtectionProxy] ACCESS DENIED for role '${this._role}'`
      );
      return "ACCESS DENIED";
    }
    return this._real.query(sql);
  }
}

// --- Logging Proxy ---

class LoggingDatabaseProxy {
  constructor(real) {
    this._real = real;
  }

  query(sql) {
    console.log(`  [LogProxy] Executing: ${sql}`);
    const result = this._real.query(sql);
    console.log(`  [LogProxy] Got: ${result}`);
    return result;
  }
}

// --- Main ---
console.log("=== Virtual Proxy (lazy loading) ===");
const lazyDB = new LazyDatabaseProxy();
console.log("Proxy created, no DB connection yet.");
console.log(lazyDB.query("SELECT * FROM users"));
console.log(lazyDB.query("SELECT * FROM orders"));

console.log("\n=== Protection Proxy ===");
const realDB = new RealDatabase();
const adminDB = new ProtectedDatabaseProxy(realDB, "admin");
const guestDB = new ProtectedDatabaseProxy(realDB, "guest");
console.log(adminDB.query("SELECT * FROM secrets"));
console.log(guestDB.query("SELECT * FROM secrets"));

console.log("\n=== Logging Proxy ===");
const loggedDB = new LoggingDatabaseProxy(realDB);
console.log(loggedDB.query("SELECT count(*) FROM users"));

Output:

=== Virtual Proxy (lazy loading) ===
Proxy created, no DB connection yet.
  [LazyProxy] First access — initializing real database
  [RealDB] Connecting to database... (expensive)
Result of: SELECT * FROM users
Result of: SELECT * FROM orders

=== Protection Proxy ===
  [RealDB] Connecting to database... (expensive)
Result of: SELECT * FROM secrets
  [ProtectionProxy] ACCESS DENIED for role 'guest'
ACCESS DENIED

=== Logging Proxy ===
  [LogProxy] Executing: SELECT count(*) FROM users
  [LogProxy] Got: Result of: SELECT count(*) FROM users
Result of: SELECT count(*) FROM users
  • Decorator — Both wrap objects with the same interface. Proxy controls access; Decorator adds behavior. Combined: Decorator wraps a Proxy to add both behavior and access control.
  • Adapter — Adapter wraps to change the interface; Proxy wraps to control access while keeping the same interface.
  • Facade — Facade simplifies a subsystem interface; Proxy keeps the same interface but adds control.
  • Memoization — Caching Proxy implements memoization transparently.
  • Guard Clause — Protection Proxy implements Guard Clause logic at the wrapper level.