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

7.2 KiB

Identity Map Pattern

Problem

When multiple parts of an application load the same database record, they may create separate object instances for the same entity. This leads to inconsistencies: updating one instance doesn't update the other. It also wastes memory and database round-trips — the same row is fetched repeatedly.

Solution

Maintain an in-memory map keyed by entity identity (typically the primary key). Before loading from the database, check the map. If the entity is already loaded, return the existing instance. On save, update the map. This ensures each entity exists at most once in memory per session.

When to Use

  • ORM or Unit of Work implementations
  • When the same entity is accessed from multiple code paths in a single request
  • To prevent duplicate database queries for the same record
  • When object identity matters (same DB row = same object reference)

When to Avoid

  • Stateless APIs where each request starts fresh
  • Read-only queries where duplicates don't matter
  • Very large datasets where caching everything in memory is impractical
  • Simple scripts with sequential, non-overlapping access patterns

Pseudocode

class IdentityMap:
    cache = {}    # key: (type, id) → value: entity

    function get(type, id):
        return cache.get((type, id))

    function put(type, id, entity):
        cache[(type, id)] = entity

    function has(type, id):
        return (type, id) in cache

Python Implementation

from dataclasses import dataclass, field
from typing import Optional, Any


@dataclass
class User:
    id: int
    name: str
    email: str


class IdentityMap:
    def __init__(self):
        self._cache: dict[tuple[type, Any], Any] = {}
        self._hit_count = 0
        self._miss_count = 0

    def get(self, entity_type: type, entity_id: Any) -> Optional[Any]:
        key = (entity_type, entity_id)
        if key in self._cache:
            self._hit_count += 1
            return self._cache[key]
        self._miss_count += 1
        return None

    def put(self, entity_type: type, entity_id: Any, entity: Any) -> None:
        self._cache[(entity_type, entity_id)] = entity

    def remove(self, entity_type: type, entity_id: Any) -> None:
        self._cache.pop((entity_type, entity_id), None)

    def clear(self):
        self._cache.clear()
        self._hit_count = 0
        self._miss_count = 0

    @property
    def stats(self):
        return {"hits": self._hit_count, "misses": self._miss_count, "size": len(self._cache)}


class UserRepository:
    """Repository with identity map — simulates DB with a dict."""

    def __init__(self, identity_map: IdentityMap):
        self.identity_map = identity_map
        self.db_queries = 0
        # Simulated database
        self._db = {
            1: {"id": 1, "name": "Alice", "email": "alice@example.com"},
            2: {"id": 2, "name": "Bob", "email": "bob@example.com"},
            3: {"id": 3, "name": "Charlie", "email": "charlie@example.com"},
        }

    def find_by_id(self, user_id: int) -> Optional[User]:
        # Check identity map first
        cached = self.identity_map.get(User, user_id)
        if cached is not None:
            print(f"  [IdentityMap] HIT for User#{user_id}")
            return cached

        # Simulate DB query
        print(f"  [DB] SELECT * FROM users WHERE id = {user_id}")
        self.db_queries += 1
        row = self._db.get(user_id)
        if row is None:
            return None

        user = User(**row)
        self.identity_map.put(User, user_id, user)
        return user


# --- Demo ---
identity_map = IdentityMap()
repo = UserRepository(identity_map)

print("=== First load (cache miss, hits DB) ===")
user1 = repo.find_by_id(1)
print(f"  Got: {user1}")

print()
print("=== Second load same ID (cache hit, no DB) ===")
user1_again = repo.find_by_id(1)
print(f"  Got: {user1_again}")
print(f"  Same object? {user1 is user1_again}")

print()
print("=== Load different user (cache miss) ===")
user2 = repo.find_by_id(2)
print(f"  Got: {user2}")

print()
print("=== Mutate user1 — reflected everywhere ===")
user1.email = "alice@newdomain.com"
user1_check = repo.find_by_id(1)
print(f"  user1.email = {user1_check.email}")

print()
print(f"=== Stats ===")
print(f"  DB queries: {repo.db_queries}")
print(f"  Identity map: {identity_map.stats}")

Output:

=== First load (cache miss, hits DB) ===
  [DB] SELECT * FROM users WHERE id = 1
  Got: User(id=1, name='Alice', email='alice@example.com')

=== Second load same ID (cache hit, no DB) ===
  [IdentityMap] HIT for User#1
  Got: User(id=1, name='Alice', email='alice@example.com')
  Same object? True

=== Load different user (cache miss) ===
  [DB] SELECT * FROM users WHERE id = 2
  Got: User(id=2, name='Bob', email='bob@example.com')

=== Mutate user1 — reflected everywhere ===
  [IdentityMap] HIT for User#1
  user1.email = alice@newdomain.com

=== Stats ===
  DB queries: 2
  Identity map: {'hits': 2, 'misses': 2, 'size': 2}

JavaScript Implementation

class IdentityMap {
  constructor() {
    this._cache = new Map();
    this.hits = 0;
    this.misses = 0;
  }

  _key(type, id) {
    return `${type}:${id}`;
  }

  get(type, id) {
    const key = this._key(type, id);
    if (this._cache.has(key)) {
      this.hits++;
      return this._cache.get(key);
    }
    this.misses++;
    return null;
  }

  put(type, id, entity) {
    this._cache.set(this._key(type, id), entity);
  }

  get stats() {
    return { hits: this.hits, misses: this.misses, size: this._cache.size };
  }
}

class UserRepository {
  constructor(identityMap) {
    this.identityMap = identityMap;
    this.dbQueries = 0;
    this._db = new Map([
      [1, { id: 1, name: "Alice", email: "alice@example.com" }],
      [2, { id: 2, name: "Bob", email: "bob@example.com" }],
    ]);
  }

  findById(id) {
    const cached = this.identityMap.get("User", id);
    if (cached) {
      console.log(`  [IdentityMap] HIT for User#${id}`);
      return cached;
    }
    console.log(`  [DB] SELECT * FROM users WHERE id = ${id}`);
    this.dbQueries++;
    const row = this._db.get(id);
    if (!row) return null;

    const user = { ...row }; // Shallow copy from "DB"
    this.identityMap.put("User", id, user);
    return user;
  }
}

// --- Demo ---
const im = new IdentityMap();
const repo = new UserRepository(im);

console.log("=== First load (cache miss) ===");
const user1 = repo.findById(1);
console.log(`  Got: User(id=${user1.id}, name=${user1.name}, email=${user1.email})`);

console.log("\n=== Second load same ID (cache hit) ===");
const user1Again = repo.findById(1);
console.log(`  Same reference? ${user1 === user1Again}`);

console.log("\n=== Mutate — reflected everywhere ===");
user1.email = "alice@newdomain.com";
const check = repo.findById(1);
console.log(`  email after mutation: ${check.email}`);

console.log(`\nDB queries: ${repo.dbQueries}`);
console.log("Identity map stats:", im.stats);
  • Repository — the identity map lives inside the repository, ensuring that find(id) always returns the same object instance.
  • Unit of Work — the unit of work uses the identity map to track which objects have been modified during a transaction.
  • Flyweight — flyweight shares immutable intrinsic state; identity map shares mutable entity instances by identity.