dependency-injection-planning
DI planning — injection styles (constructor / setter / param / property), composition root, lifetimes (singleton / scoped / transient / per-request / per-tenant), framework vs pure, port-adapter boundaries, testability, lifecycle.
What this skill does
# Dependency Injection Planning
You plan how a service wires its dependencies — so code is testable, lifetimes are clear, and the composition root is unambiguous.
## Core rules
- **Constructor injection is the default** — explicit dependencies, easy tests
- **One composition root per process** — top of `main` / entrypoint; nowhere else
- **Domain code is framework-free** — no `@Inject` in pure domain; adapters only
- **Lifetimes are deliberate** — document scopes for every dep
- **Avoid service locator** — hidden deps; hard tests
- **Ports + adapters enable substitution** — test doubles replace adapters at the root
- **Deterministic ports for side-effects** — Clock, RNG, IdGen injected as ports
- **No fabricated dependencies** — work from supplied structure
## Input handling
| Dimension | Required | Default |
|---|---|---|
| **Service / module** | Yes | — |
| **Language + framework** | Yes | — |
| **Existing DI approach** (if any) | No | Asked |
| **Layered vs ports-adapters** | No | Asked |
| **Multi-tenant / per-request scoping** | No | Asked |
## Phase 1 — Setup
```
**Service**: [name]
**Language**: [Go / Kotlin / Java / Python / TypeScript / C# / Rust]
**Framework**: [Spring / NestJS / FastAPI / .NET / Dagger / none]
**Existing approach**: [constructor-pure / container-based / service-locator / mixed]
**Architecture**: [ports-adapters / layered / modular monolith / ...]
**Scoping needs**: [per-request / per-tenant / singleton-only]
```
Ask render mode per `diagram-rendering` mixin and output path (default: `/documentation/[case]/dependency-injection-planning/[service]/`).
## Phase 2 — Injection styles
| Style | When |
|---|---|
| **Constructor** | Default; dependencies required for the object to function |
| **Setter / property** | Optional deps, or when framework demands (e.g., property injection in .NET MVC controllers) |
| **Method parameter** | Per-call context (e.g., user / tenant) — avoid passing through graph |
| **Ambient / context** | For cross-cutting concerns (logger, tracer) with care; prefer explicit |
Avoid:
- Hidden service locators (`ServiceLocator.get<Foo>()` from anywhere)
- Global singletons accessed statically
- Property injection on required deps (hides what's needed)
## Phase 3 — Composition root
- **Single location** where the object graph is built
- Typical: `main()` / `Program.cs` / `app.module.ts` / `bootstrap()`
- Reads config, creates adapters, wires services, starts lifecycle
- Nothing below the root imports the DI container
Example (pure Go):
```go
func main() {
cfg := config.MustLoad()
clock := clock.System{}
db := postgres.MustConnect(cfg.DatabaseURL)
orderRepo := postgres.NewOrderRepository(db, clock)
publisher := kafka.NewPublisher(cfg.KafkaBrokers)
orderSvc := orders.NewService(orderRepo, publisher, clock)
http := api.NewServer(orderSvc)
lifecycle.Run(http)
}
```
Example (NestJS):
```typescript
@Module({
imports: [ConfigModule, PersistenceModule, MessagingModule],
providers: [OrderService],
controllers: [OrderController],
})
export class OrderModule {}
```
## Phase 4 — Lifetimes + scopes
| Lifetime | Meaning |
|---|---|
| **Singleton** | One instance per process; state shared |
| **Scoped / per-request** | One per HTTP request / unit of work |
| **Transient** | New instance per resolution |
| **Per-tenant** | One per tenant (usually via factory + cache keyed on tenant) |
| **Per-conversation** | Agentic / long-running session |
Rules:
- Dependencies of a singleton must themselves be safe as singletons (thread-safe)
- A singleton holding a scoped dependency is a leak — use factory / provider
- DBs: connection pool is singleton; transaction is scoped
- HTTP clients: usually singleton with keepalive; tune per runtime
## Phase 5 — Framework vs pure DI
| Approach | Pros | Cons |
|---|---|---|
| **Pure / manual** (Go, Rust typical) | explicit, no magic, compile-time checks | more code at composition root |
| **Compile-time container** (Dagger, Wire) | static graph, no runtime reflection | extra build step |
| **Runtime container** (Spring, NestJS, .NET DI, FastAPI Depends) | ergonomic, scopes built-in | reflection, magic, harder mental model |
Recommend:
- Small services / Go / Rust: manual
- Java / Kotlin / Spring shop: Spring
- TypeScript backend: NestJS or manual + class-validator
- Python: FastAPI Depends or manual (avoid heavy containers)
- .NET: built-in `IServiceCollection`
## Phase 6 — Ports, adapters, test doubles
- **Port** = interface owned by the domain
- **Adapter** = infra implementation living at the edge
- Test doubles swap adapters at the composition root
Deterministic ports:
- `Clock` (not `time.Now()` directly)
- `RandomSource` (not `rand.Read`)
- `IdGenerator` (not `uuid.New()` directly)
- `HttpClient` port with canned-response adapter for tests
Keeps tests reproducible + fast.
## Phase 7 — Lifecycle
- **Start**: open connections, warm caches, listen
- **Ready check**: report ready after deps healthy
- **Shutdown**: drain in-flight, close connections, flush, exit
- Frameworks with lifecycle hooks: Spring `@PostConstruct`/`@PreDestroy`, NestJS `OnModuleInit`/`OnModuleDestroy`, FastAPI `startup`/`shutdown`
- Manual: register close handlers in reverse of construction
## Phase 8 — Circular dependencies
- **Prevent at root** — circular between services usually means a seam is wrong
- **Detection**: compile-time in Dagger/Wire; runtime in Spring
- **Fix strategies**:
- extract shared interface / domain event
- invert dependency (Y depends on X's abstraction, X provides impl)
- merge if truly one concept
- **Never** fix with setter injection + `null` dance
## Phase 9 — Testing strategy
- Unit tests: build object graphs manually or via small helpers; no framework container
- Integration tests: real adapters + real DB/broker in docker-compose or testcontainers
- Composition-root tests: happy-path start-up; validates wiring
## Phase 10 — Anti-patterns to avoid
| Anti-pattern | Why bad |
|---|---|
| Service locator | hidden deps; tests fragile |
| New-ing deps inside constructors | can't substitute in tests |
| Static factories for deps | hidden state |
| Global mutable singletons | thread/concurrency bugs |
| Domain code with `@Inject` | bound to container; not reusable |
| Constructor with 10+ deps | cohesion problem; split service |
## Phase 11 — Diagrams
### Dependency graph
```mermaid
graph TD
main[main / composition root]
cfg[Config]
clock[Clock]
db[(Postgres)]
repo[OrderRepository]
pub[EventPublisher]
svc[OrderService]
http[HTTPServer]
main --> cfg
main --> clock
main --> db
main --> repo
main --> pub
main --> svc
main --> http
repo --> db
repo --> clock
svc --> repo
svc --> pub
svc --> clock
http --> svc
```
### Lifetime layering
```mermaid
graph LR
S[Singleton: DB pool, Clock, Publisher, Service] --> R[Scoped: Tx, UnitOfWork]
R --> T[Transient: Command handlers per request]
```
## Phase 12 — Diagram rendering
Per `diagram-rendering` mixin.
## Phase 13 — Report assembly and approval
```markdown
# Dependency Injection Plan: [Service]
**Date**: [date]
**Service**: [...]
**Language / framework**: [...]
## Scope
[Architecture, scoping needs, existing approach]
## Injection Styles
[Constructor default; when setter / param; what to avoid]
## Composition Root
[Location + content + rules for callers]
## Lifetimes + Scopes
[Table per dependency]
## Framework vs Pure
[Choice + rationale]
## Ports + Adapters + Test Doubles
[Deterministic ports: Clock / RNG / IdGen]
## Lifecycle
[Start / ready / shutdown + hooks]
## Circular Dependencies
[Prevention + detection + fix strategies]
## Testing Strategy
[Unit / integration / composition-root]
## Anti-Patterns Avoided
[Service locator etc.]
## Diagrams
[Graph + lifetime layering]
## Hand-offs
[component-design-documentation, configuration-management-design, system-error-handlRelated 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.