Systems Don't Exist But Definitions Do
Table of Contents
1. Fish Don't Exist (And Neither Does Your Code)
You've probably heard it: "Fish don't exist."
Not in the sense that there are no aquatic creatures. But in the sense that "fish" is a fuzzy, human-invented category with no clean boundaries. Lungfish are fish? Are whales fish?
The answer: Fish exist because we decided they do. We drew a line around a collection of creatures and said "that's a fish." The category is useful, but it's not discovered in nature—it's constructed by us.
2. Files Don't Exist Either
Your computer feels real. Files, folders, applications—you can see them on your desktop.
But they don't actually exist.
What actually exists: magnetic patterns on disk, electricity flowing through circuits.
What doesn't exist: the "file" abstraction.
When you double-click "myproject.txt", the OS executes complex instructions to read bytes and present them as a "file." The "file" is a definition. A useful fiction. If the OS changed its definition, the whole concept changes.
3. Your System Doesn't Exist Either
Now extend this to your software.
You believe your system has an OrderService, an order_created event, a payment-timeout error. But these don't actually exist.
What actually exists: functions executing, data transforming, bytes transmitting.
What doesn't exist: the categories you've imposed.
When you say "OrderService," you're drawing a circle around clustered functions. That's a definition, not a discovery. Tomorrow you could reorganize it completely.
If nothing fundamentally exists except the definitions we create, then the definitions themselves become the most important part of the system.
4. The Usual Mess
Most teams scatter definitions everywhere:
- Component: class in code, deployment in K8s, box in diagram, paragraph in wiki
- Error: exception in code, ticket in Jira, Slack thread, tribal knowledge
- Event: Kafka schema, consumer code, API docs, that one email
Four definitions of the same thing. All drifting. All inconsistent.
5. Make Definitions Explicit
Stop pretending definitions are just "documentation." They're not describing the system—they are the system.
;; First, define what errors need (s/def :error/code string?) (s/def :error/severity #{:low :medium :high :critical}) (s/def :error/retry? boolean?) ;; Define the error TYPE and the required props (contract.type/def #{:semantic-namespace/error} [:error/code :error/severity :error/retry?]) ;; Now define a specific error with expected props-types/values (contract/def #{:semantic-namespace/error :domain.payment/timeout} {:error/code "PAY_TIMEOUT" :error/severity :high :error/retry? true})
Notice what just happened: The identity #{:semantic-namespace/error :domain.payment/timeout} reads like English:
"An error, in the payment domain, specifically a timeout"
The compound identity is the description. You don't need separate documentation—you can read it.
6. Why Compound Identities Matter
Traditional identities are flat strings. No semantics. No relationships.
:payment-timeout-error ;; What domain? What type? What properties?
Compound identities are sets of semantic aspects. Readable as plain English.
#{:semantic-namespace/error ;; "an error"
:domain.payment/timeout ;; "payment domain, timeout type"
:severity/high} ;; "high severity"
;; Reads: "A high-severity error in the payment domain, specifically a timeout"
Now the system can answer questions:
;; "What can go wrong with payments?" (find-docs #{:domain.payment}) ;; "What are all high-severity issues?" (find-docs #{:severity/high}) ;; "Show me all errors" (contract.type/instances #{:semantic-namespace/error})
The definitions are queryable. The identities are readable. The system is self-describing.
7. The Scale: What Gets Defined?
You might think: "Okay, but how many contract types do I really need?"
More than you think. And that's the point.
7.1. Short Term (First Sprint)
;; Core types - 5-8 contract types (contract.type/def #{:semantic-namespace/error} [...]) (contract.type/def #{:semantic-namespace/event} [...]) (contract.type/def #{:semantic-namespace/endpoint} [...]) (contract.type/def #{:semantic-namespace/component} [...]) (contract.type/def #{:semantic-namespace/permission} [...])
7.2. Mid Term (Growing System)
;; The system reveals itself - 20-40 contract types (contract.type/def #{:semantic-namespace/metric} [...]) (contract.type/def #{:semantic-namespace/command} [...]) (contract.type/def #{:semantic-namespace/query} [...]) (contract.type/def #{:semantic-namespace/job} [...]) (contract.type/def #{:semantic-namespace/validation} [...]) (contract.type/def #{:semantic-namespace/transformation} [...]) (contract.type/def #{:semantic-namespace/webhook} [...]) (contract.type/def #{:semantic-namespace/cache-strategy} [...]) (contract.type/def #{:semantic-namespace/rate-limit} [...]) (contract.type/def #{:semantic-namespace/circuit-breaker} [...]) (contract.type/def #{:semantic-namespace/retry-policy} [...]) (contract.type/def #{:semantic-namespace/saga} [...]) (contract.type/def #{:semantic-namespace/feature-flag} [...]) (contract.type/def #{:semantic-namespace/configuration} [...]) (contract.type/def #{:semantic-namespace/migration} [...]) (contract.type/def #{:semantic-namespace/integration} [...]) (contract.type/def #{:semantic-namespace/alert} [...]) (contract.type/def #{:semantic-namespace/dashboard} [...]) (contract.type/def #{:semantic-namespace/report} [...]) (contract.type/def #{:semantic-namespace/audit-log} [...])
7.3. The Realization
Each type might have 5-50 instances:
;; 15 errors across 4 domains = 15 definitions #{:semantic-namespace/error :domain.payment/timeout} #{:semantic-namespace/error :domain.payment/declined} #{:semantic-namespace/error :domain.order/not-found} #{:semantic-namespace/error :domain.order/invalid-state} #{:semantic-namespace/error :domain.shipping/address-invalid} ;; ... etc ;; 25 events across your system = 25 definitions #{:semantic-namespace/event :domain.order/created} #{:semantic-namespace/event :domain.order/cancelled} #{:semantic-namespace/event :domain.payment/succeeded} ;; ... etc ;; 40 endpoints = 40 definitions #{:semantic-namespace/endpoint :api.order/create} #{:semantic-namespace/endpoint :api.order/get} #{:semantic-namespace/endpoint :api.payment/charge} ;; ... etc
A mid-sized project easily has 500-1000 definitions across 30-40 contract types.
Right now, these definitions are scattered. In your head. In code. In tickets. In Slack.
What if they were all in one place? Typed. Queryable. Readable.
;; "Show me the entire system" (count @registry) ;; => 847 definitions ;; "What domains do we have?" (keys (clusters)) ;; => (:domain.payment :domain.order :domain.shipping :domain.user) ;; "What can fail in production?" (->> (contract.type/instances #{:semantic-namespace/error}) (map contract/fetch) (filter #(= :critical (:error/severity %)))) ;; => All critical errors, across all domains ;; "What needs monitoring?" (contract.type/instances #{:semantic-namespace/metric}) ;; => Every metric defined in the system
The scale isn't a burden. It's clarity.
Every one of those 847 things already exists in your system—you just haven't named them explicitly yet.
8. The Leap
Most teams think: System exists → document it → hope docs stay current
The truth: Define everything explicitly → system implements the definitions → query the definitions to understand the system
The definitions come first. Everything else flows from them.
9. What You Get
;; Single source of truth @registry ;; Every metric, error, event, permission, component ;; Fully queryable (contract.type/instances #{:semantic-namespace/error}) ;; All errors, across all domains ;; Human readable #{:semantic-namespace/metric :domain.order/latency} ;; "A metric for order domain latency" - reads like English ;; Generative (generate-api-from-definitions) (generate-docs-from-definitions) (generate-tests-from-definitions)
Your system isn't mysterious anymore. It's not hidden in code, configs, or people's heads.
It's explicit. It's unified. It's readable. It's just definitions.
All the way down.
10. resources
- https://github.com/semantic-namespace/contract.example a mock medium project definitions to query about
- https://github.com/semantic-namespace/compound-identity the compound-identity registry and utilities to navigate/query that registry
- https://github.com/semantic-namespace/contract the semantic contract and type design and utils
- https://github.com/semantic-namespace/contract.di a PoC about defining dependency injection on systems via component contract definitions. Include utils to plan, query and start the system