darellchua2

design-patterns-skill

Apply GoF design patterns (Creational, Structural, Behavioral) appropriately without over-engineering - language-agnostic with practical examples

darellchua2 7 5 Updated 1mo ago
GitHub

Install

npx skillscat add darellchua2/civiltekk-skills/design-patterns-skill

Install via the SkillsCat registry.

SKILL.md

What I do

Apply design patterns where they fit — and refuse to force them. Patterns solve problems you HAVE, not problems you MIGHT have; let them emerge from refactoring, not upfront design.

When to use me

  • A design problem you recognize (repeated type-switching, behavior addable without modification, complex object construction)
  • You're tempted to add a pattern and want a second opinion on whether it's warranted

House Learnings

Learning: zai-client-class

Instead of per-endpoint adapters, wrap all API endpoints in a single client class handling key resolution, base URL config, and error mapping centrally (combined Adapter + Facade): one ZaiClient with _headers()/_request() internals and typed endpoint methods (search, summarize, analyze); missing ZAI_API_KEY raises at construction.

Learning: enum-strategy-resolution

Dispatch via str + Enum with a default member: one dispatch point, Open/Closed-compliant (new strategies need no dispatcher edit), callers pass raw strings or enum members interchangeably. Unknown values fall through to the UNKNOWN member's handler instead of raising.

Learning: atomic-sql-update-race-free-transition

Use a single UPDATE ... WHERE expected_state RETURNING cols as an optimistic lock — the WHERE guards the transition, RETURNING fetches columns in one round-trip, losers re-read and reconcile idempotently. Never read-then-write state transitions (two workers both commit, duplicate side effects).
Detection: rg 'get_.*\(|fetch_.*\(' --type py -A 10 | rg 'status|state' | rg 'commit|save|update'

Learning: double-checked-locking-async-refresh

Async token/cache refresh must use double-checked locking (unlocked check → acquire lock → RE-CHECK → refresh only if still invalid) so exactly ONE caller hits the upstream provider per expiry window; hot path stays lock-free. Pair with time.monotonic() (NTP-immune) and proactive refresh at 80% of TTL.
Detection: rg 'async with self\._lock|async with.*Lock' --type py -A 15 | rg 'await.*refresh|await.*fetch' | rg -v 'if.*stale|if.*expired'

Learning: zai-node-mixin

Prefer mixins over deep inheritance for selectively adopted behaviors: a CacheMixin/RetryMixin composing into DataPipeline respects __init_subclass__, avoids fragile-base-class coupling, and subclasses pick only what they need.

Removed 2026-09: GoF catalog with per-pattern code examples (Singleton/Factory/Builder/Adapter/Decorator/Proxy/Strategy/Observer/Template Method/Command), pattern-selection table, anti-pattern table, steps/best-practices/verification ceremony — textbook the model knows; the five codified learnings above are this config's real additions.