solid-ddd
Language-agnostic SOLID principles and DDD tactical patterns. Trigger: Always loaded for non-documentation code changes via sdd-apply.
What this skill does
# solid-ddd
> Language-agnostic catalog of SOLID design principles and Domain-Driven Design tactical patterns with concrete do/don't examples.
**Triggers**: Always loaded for non-documentation code changes. Load when writing or reviewing any class, module, domain object, service, or repository. Applicable across all languages and frameworks.
---
## Patterns
### SOLID Principles
---
#### SRP — Single Responsibility Principle
A class, module, or function has exactly one reason to change. One unit = one concern.
**DON'T** — one class handles both order persistence and email notification:
```typescript
// [Illustrative — TypeScript]
class OrderService {
save(order: Order): void { /* writes to DB */ }
sendConfirmationEmail(order: Order): void { /* sends email */ }
calculateDiscount(order: Order): number { /* discount logic */ }
}
```
**DO** — each class owns one responsibility:
```typescript
// [Illustrative — TypeScript]
class OrderRepository { save(order: Order): void { /* DB only */ } }
class OrderNotifier { sendConfirmation(order: Order): void { /* email only */ } }
class DiscountCalculator { calculate(order: Order): number { /* pricing only */ } }
```
**Signal — SRP violated**: the class has multiple unrelated reasons to change (schema change AND email template change affect the same file).
---
#### OCP — Open/Closed Principle
A unit is open for extension, closed for modification. Add behavior by adding code, not by editing existing code.
**DON'T** — every new payment method requires editing the same function:
```typescript
// [Illustrative — TypeScript]
function processPayment(type: string, amount: number) {
if (type === 'credit') { /* ... */ }
else if (type === 'paypal') { /* ... */ }
// Adding 'crypto' forces editing this function
}
```
**DO** — new behavior is added by adding a new implementation:
```typescript
// [Illustrative — TypeScript]
interface PaymentProcessor { process(amount: number): void; }
class CreditProcessor implements PaymentProcessor { process(amount) { /* ... */ } }
class PaypalProcessor implements PaymentProcessor { process(amount) { /* ... */ } }
// Adding crypto: create CryptoProcessor — no existing code touched
```
**Signal — OCP violated**: adding a new variant requires touching a central switch/if chain that already exists.
---
#### LSP — Liskov Substitution Principle
Subtypes must be substitutable for their base types without altering correctness. A subclass must honor the contract of its parent.
**DON'T** — subclass breaks the parent contract by throwing where parent succeeds:
```typescript
// [Illustrative — TypeScript]
class Rectangle { setWidth(w: number) { this.width = w; } }
class Square extends Rectangle {
setWidth(w: number) { this.width = w; this.height = w; } // Breaks area contract
}
```
**DO** — prefer composition or a shared interface with separate implementations:
```typescript
// [Illustrative — TypeScript]
interface Shape { area(): number; }
class Rectangle implements Shape { area() { return this.width * this.height; } }
class Square implements Shape { area() { return this.side * this.side; } }
```
**Signal — LSP violated**: calling code needs to check the concrete type before using the abstraction (`if (shape instanceof Square)`).
---
#### ISP — Interface Segregation Principle
Clients must not be forced to depend on methods they do not use. Prefer narrow, focused interfaces over fat ones.
**DON'T** — one fat interface forces every implementor to stub unused methods:
```typescript
// [Illustrative — TypeScript]
interface Worker {
work(): void;
eat(): void; // Robots don't eat
sleep(): void; // Robots don't sleep
}
class RobotWorker implements Worker {
work() { /* real logic */ }
eat() { throw new Error('Not supported'); } // forced no-op
sleep() { throw new Error('Not supported'); } // forced no-op
}
```
**DO** — split into narrow interfaces; each class implements only what it needs:
```typescript
// [Illustrative — TypeScript]
interface Workable { work(): void; }
interface Feedable { eat(): void; sleep(): void; }
class HumanWorker implements Workable, Feedable { /* all methods real */ }
class RobotWorker implements Workable { work() { /* only real method */ } }
```
**Signal — ISP violated**: an implementor has one or more methods that throw `NotImplementedException`, return empty, or are no-ops.
---
#### DIP — Dependency Inversion Principle
High-level modules must not depend on low-level modules. Both depend on abstractions. Abstractions must not depend on details.
**DON'T** — high-level service directly instantiates a concrete repository:
```typescript
// [Illustrative — TypeScript]
class OrderService {
private repo = new PostgresOrderRepository(); // concrete dependency
placeOrder(order: Order) { this.repo.save(order); }
}
```
**DO** — high-level service depends on an abstraction; the concrete class is injected:
```typescript
// [Illustrative — TypeScript]
interface OrderRepository { save(order: Order): void; }
class OrderService {
constructor(private repo: OrderRepository) {} // depends on abstraction
placeOrder(order: Order) { this.repo.save(order); }
}
// Caller injects: new OrderService(new PostgresOrderRepository())
```
**Signal — DIP violated**: `new ConcreteClass()` inside a service constructor or method body with no injection seam.
---
### DDD Tactical Patterns
---
#### Entity
An object defined by its identity, not its attributes. Two entities with the same ID are the same entity even if their data differs.
- **Has**: a stable, unique identifier (ID) that persists across state changes.
- **Behavior**: encapsulates domain logic relevant to its lifecycle.
- **Distinguishing signal vs. Value Object**: ask "does it matter which one it is?" — if yes, it is an Entity.
```
// [Pseudocode]
Entity Order { id: OrderId; status: OrderStatus; items: Item[] }
// Two Orders with id=42 are the same order even if status changed
```
---
#### Value Object
An object defined entirely by its attributes. No identity. Immutable. Equality is structural.
- **Has**: no ID field. Equality is based on all attribute values.
- **Immutable**: replace, never mutate. Operations return new instances.
- **Distinguishing signal vs. Entity**: ask "does it matter which one it is?" — if no, it is a Value Object.
```
// [Pseudocode]
ValueObject Money { amount: Decimal; currency: Currency }
// Money(10, USD) == Money(10, USD) — two instances are equal by value
```
---
#### Aggregate
A cluster of domain objects (one Entity as root + optional child objects) treated as a single unit for data changes. All access to internal objects goes through the Aggregate Root.
- **Aggregate Root** is the only public entry point. External code holds a reference only to the root.
- **Invariants** that span multiple child objects are enforced by the root.
- **Transactions** should not span multiple Aggregates — each Aggregate is a consistency boundary.
```
// [Pseudocode]
Aggregate Order (root) {
addItem(product, qty) // enforces max-items invariant
removeItem(itemId)
confirm() // guards: status must be DRAFT
}
// External code: order.addItem(…) — never order.items.push(…) directly
```
---
#### Repository
An abstraction that provides collection-like access to Aggregates. Hides the persistence mechanism from the domain layer.
- **Interface** lives in the domain layer. **Implementation** lives in the infrastructure layer (DIP applied).
- Methods are domain-language methods (`findById`, `findByCustomer`, `save`) — not SQL or ORM calls.
- One Repository per Aggregate Root — not per entity or table.
```
// [Pseudocode]
interface OrderRepository {
findById(id: OrderId): Order | null
findByCustomer(customerId: CustomerId): Order[]
save(order: Order): void
}
```
---
#### Domain Service
A stateless operation that belongs to the domain but does not naturally fit inside a single Entity or Value Object.
- **Stateless**: no mutable fiRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.