Skip to content
Back to skills

Functional Capturing The Domain

ASecurity

Use when starting a feature or system, when code and the business use different words for the same thing, or when drawing boundaries between subsystems.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 21, 2026
ai-agentsgoexpressapidatabasedocumentation

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned October 21, 2026

npx -y skills add yutna/functional-design-skills --skill functional-capturing-the-domain --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Functional Capturing The Domain?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Functional Capturing The Domain
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/yutna-functional-capturing-the-domain/badge)](https://www.skillsdirectory.com/skills/yutna-functional-capturing-the-domain)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: functional-capturing-the-domain
description: Use when starting a feature or system, when code and the business use different words for the same thing, or when drawing boundaries between subsystems.
license: MIT
metadata:
  pack: functional-design-skills
  version: 3.3.0
---

# Capturing the Domain

**In this pack:** [how much design a task warrants](../functional-design/references/calibration.md),
[the notation](../functional-design/references/notation.md), and
[syntax per language](../functional-design/SKILL.md#language-packs).

## Overview

Software fails most often because the model in the code does not match
the model in the experts' heads. The cure is not more documentation; it
is a shared mental model, expressed in the same words in conversation, in
the types, and in the function names, with no translation step anywhere.

Discover the domain through what happens, not through what things are. A
list of nouns produces a database schema; a list of events and the
commands that cause them produces a design.

## When to use

- Starting a new feature, service, or bounded context
- Code says `UserRecord` while the business says "applicant"
- A term means two different things in two parts of the system
- Deciding where one subsystem ends and the next begins
- Before any schema, API, or type is written down

Not for: choosing the representation of a type once the concept is clear,
which is
[functional-modeling-with-algebraic-types](../functional-modeling-with-algebraic-types/SKILL.md).

## Core rules

1. Rule. **Use the domain's words, unchanged.** If experts say "quote", the type
   is `Quote`, not `PricingRequestDto`. Words invented by developers are the
   beginning of two models.
2. Default. **Discover through events.** Ask what happens, in the past tense:
   "booking confirmed", "payment declined". Events reveal boundaries that nouns
   hide.
3. Rule. **Every workflow starts from one command or one event, and returns
   events.** Name the trigger, the work, and what the rest of the world learns.
   That triple is the unit of design. A read that changes nothing is a query and
   not a workflow: it returns a view and no events. See
   [functional-designing-workflow-pipelines](../functional-designing-workflow-pipelines/SKILL.md).
4. Rule. **Draw a context boundary wherever a word changes meaning.** If
   "patient" means a billing account here and a person there, those are two
   contexts, and the two `Patient` types must be different types.
5. Rule. **Never share a model by accident.** Every pair of contexts has
   a relationship that was chosen and is written down. Usually it is a
   translation at the border, in one place; a small kernel owned by both
   is the other choice, made on purpose. See
   [bounded-contexts.md](references/bounded-contexts.md).
6. Default. **Persist nothing until the model holds.** Deriving the model from a
   schema imports the storage's compromises into the domain forever. The model
   holds once the read-back that rule 7 asks for brings no further change. A
   schema that is already there, or that belongs to someone else, changes
   nothing: the model is still written from the domain, and a mapping at the
   boundary carries the difference.
7. Default. **Write the model down as types, and read them back to the
   experts.** Types are the cheapest reviewable artefact, and non-programmers
   can follow a well-named choice type. Where there is no expert, the read-back
   goes to the user with the list of assumptions made, and
   [working-alone.md](../functional-design/references/working-alone.md) gives
   the order of the substitutes.

## Pattern

The developer-invented model, taken from the database:

```text
type BookingRecord = {
  id: Int,
  customerId: Int,
  statusCode: String,
  total: Float,
  flag1: Boolean,
  processedAt: DateTime?,
}
```

Little here is a business word. `flag1` will be explained in a wiki page
that goes stale. `statusCode` will be compared against string literals in
four modules.

The domain's model, taken from a conversation:

```text
-- "A quote becomes a booking when the patient accepts it. We can only
--  accept a quote that hasn't expired."
type Quote = { id: QuoteId, lines: NonEmptyList<QuoteLine>,
               expires: Instant }

type AcceptQuote = { quote: QuoteId, acceptedBy: PatientId }
type QuoteAccepted = { booking: BookingId, acceptedAt: Instant }
type AcceptQuoteError = QuoteExpired of Instant

acceptQuote :
  Instant -> BookingId -> Quote -> AcceptQuote
    -> Result<QuoteAccepted, AcceptQuoteError>
```

Every name came from the business. The rule about expiry is visible in
the error type. An expert can read this and say whether it is right.

The handler loads the quote named in the command and supplies the
instant and the new identifier. When it finds no quote it has nothing to
pass, so a missing quote is not a case of `AcceptQuoteError`. This
`Quote` is the discovery sketch: a record with an expiry. It is refined
into one case for each state in
[functional-modeling-state-machines](../functional-modeling-state-machines/SKILL.md).

## Discovery procedure

1. **Collect events.** With the experts, or from evidence where there
   are none (see below), list everything that happens, in
   the past tense, on one surface. Do not organise yet.
2. **Find the triggers.** For each event, ask what caused it: a command
   from a person, another event, or the passage of time.
3. **Group into workflows.** A command or an event, the work it starts,
   the events it produces. Name each workflow in the domain's words.
4. **Mark the pain points.** Where experts disagree, hesitate, or say "it
   depends", that is where the real complexity is.
5. **Listen for changed meanings.** The same word used differently by two
   people is a context boundary, not a naming argument to settle.
6. **Draw the contexts and the flows between them**, then decide the
   relationship of each pair. See
   [bounded-contexts.md](references/bounded-contexts.md).
7. **Write the types**, and read them back. Iterate on the types, not on
   prose.

With no experts to ask, run the steps against the evidence in the
repository (tests, documentation, issues, type names) and list every
assumption for the user to confirm. The read-back in step 7 then goes
to the user, with that list. See
[Running it alone](references/event-storming.md#running-it-alone) and
[working-alone.md](../functional-design/references/working-alone.md).

## Quick reference

| Domain concept   | Appears in code as                          |
| ---------------- | ------------------------------------------- |
| Event            | A record named in the past tense            |
| Command          | A record named as an imperative             |
| Workflow         | One function: a trigger in, events out      |
| Business rule    | A type that makes the violation unbuildable |
| Constraint       | A constructor that can fail                 |
| Bounded context  | A module or service with its own types      |
| Context boundary | An explicit translation function            |

## Red flags

- A type name that no business person would recognise
- The same word meaning two things in one codebase
- The model was derived from tables, or from an existing API
- A workflow with no named trigger and no named outcome
- "We'll clarify that with the business later" in a design document
- One shared `Patient` type used by scheduling, billing and clinical
  records

## Common mistakes

- **Modelling nouns first.** Entity lists produce schemas. Events produce
  designs.
- **Settling a vocabulary dispute by vote.** Two meanings mean two
  contexts. Keep both words, in different places.
- **Treating the ubiquitous language as global.** It is ubiquitous within
  one context, not across the company.
- **Building a canonical shared model.** A model that serves every
  context serves none, and every change to it touches everything.
- **Skipping the read-back.** Types nobody outside the team has reviewed
  are guesses written confidently.

## Related skills

- [functional-modeling-with-algebraic-types](../functional-modeling-with-algebraic-types/SKILL.md)
- [functional-designing-workflow-pipelines](../functional-designing-workflow-pipelines/SKILL.md)
- [functional-enforcing-consistency-boundaries](../functional-enforcing-consistency-boundaries/SKILL.md)
- [functional-choosing-precise-names](../functional-choosing-precise-names/SKILL.md)

## Further reading

- [event-storming.md](references/event-storming.md) is the discovery
  session, step by step, with the questions that produce a model.
- [bounded-contexts.md](references/bounded-contexts.md) covers finding
  boundaries, context maps, and translating at the border.

Files in this skill

  • SKILL.md8.5 KB
  • references/bounded-contexts.md4.8 KB
  • references/event-storming.md5.2 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.