domain-modeling-made-functional

Encodes domain invariants in static type systems using algebraic data types and functional workflows.

1|Updated May 21, 2026
One-click install
npx skills add https://github.com/vnovakovits/claude-skills --skill domain-modeling-made-functional-vnovakovits
Or copy as Structured Prompt for Agent▼
Please help me install this Agent Skill.
Skill: domain-modeling-made-functional
Source: https://github.com/vnovakovits/claude-skills/tree/main/plugins/engineering-practices/skills/domain-modeling-made-functional
Command: npx skills add https://github.com/vnovakovits/claude-skills --skill domain-modeling-made-functional-vnovakovits

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve? Domain bugs often come from illegal states that the type system was never told to forbid, leaving rules enforced only by runtime checks and tests. This Skill applies Scott Wlaschin's functional DDD approach to push domain constraints into types so the compiler rejects invalid states, exception-based failures, and impure domain logic. ## Core Features & Use Cases - Type-driven domain modeling: Wrap primitives in single-case types, model aggregates as sum types (choice-of-states), and make illegal states unrepresentable in F#, C#, Scala, Kotlin, or TypeScript. - Workflows as type signatures: Design workflows as Command → AsyncResult<Events, DomainError>, with errors-as-values on a three-track railroad (domain errors, infrastructure errors, panics) and total functions throughout. - Functional core, imperative shell: Structure application services as impureim/Recawr sandwiches using dependency rejection, parameterization, and DTO-to-domain translation at bounded-context edges. - Use Case: When reviewing an Order record with eight optional fields and sibling-exclusive bools, use this Skill to remodel it as a discriminated union of states (Unvalidated, Validated, Priced, Paid) so invalid combinations cannot compile. ## Quick Start Ask Claude to review your domain model or aggregate against the Domain Modeling Made Functional checklist and refactor exception-based code to errors-as-values.

Frequently Asked Questions about domain-modeling-made-functional

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I make illegal states unrepresentable in C#?▼

Model each state as its own sealed record in a discriminated union hierarchy, carrying only fields valid in that state. Wrap primitives like Guid and string in single-case record types with validated factory methods so invalid values cannot be constructed.

Should I throw exceptions or return Result types for domain errors?▼

Return domain errors as values in an Either or Result type with a sum type of named failure cases, since expected rejections are part of the contract. Reserve exceptions for infrastructure failures propagated as effects and true panics from programmer bugs.

What is the impureim sandwich in functional architecture?▼

The impureim sandwich structures an application service as impure read, pure decision, impure write. The shell gathers all inputs, calls one pure domain function that returns decisions or events, then persists and publishes the results.

Does functional domain modeling work in dynamically typed languages?▼

These techniques rely on a compiler to enforce type-encoded invariants, so they do not apply to Python, Ruby, or vanilla JavaScript. Use this approach in F#, Scala, Kotlin, TypeScript, or C# with records and LanguageExt.

How do I handle a domain decision that needs an external call partway through?▼

First try hoisting the read to the front of the workflow. If that is impossible, split into two shell-orchestrated sandwiches where the pure core returns a value like NeedsReprice and the shell performs the fetch, reserving free monads for genuine multi-round interleaving.

When should I use a sum type instead of optional fields?▼

Use a sum type when a record has multiple Option fields or sibling-exclusive booleans where only some combinations are legal. Each legal combination becomes its own case, so the compiler forces callers to handle every state and forbids invalid ones.