software-specification
This skill should be used when the user asks to "write specifications", "specify an abstraction", "create contract tests", "property-based testing", "design by contract", "specification tests", or discusses how to formally specify interfaces before implementation. Provides methodology for writing executable specifications using the Basic/Advanced/Edge cases structure.
SKILL.md
| Name | software-specification |
| Description | This skill should be used when the user asks to "write specifications", "specify an abstraction", "create contract tests", "property-based testing", "design by contract", "specification tests", or discusses how to formally specify interfaces before implementation. Provides methodology for writing executable specifications using the Basic/Advanced/Edge cases structure. |
name: software-specification description: This skill should be used when the user asks to "write specifications", "specify an abstraction", "create contract tests", "property-based testing", "design by contract", "specification tests", or discusses how to formally specify interfaces before implementation. Provides methodology for writing executable specifications using the Basic/Advanced/Edge cases structure.
Specification Methodology
Overview
Specification-driven development formalizes abstraction contracts through executable tests before implementation. Specifications define what an abstraction does, not how it does it, enabling multiple implementations to be validated against the same contract.
When to Use Specifications
Apply specification-driven development when:
- Designing new abstractions (interfaces, protocols, contracts)
- Creating components with multiple potential implementations
- Establishing clear behavioral contracts for APIs
- Working with abstractions identified through decomposition
- Ensuring implementations satisfy defined invariants
Specification Structure
Organize specifications into three categories, in order of complexity:
Basic Cases
Cover the fundamental expected behaviors - the "happy path":
- Normal inputs produce expected outputs
- Core functionality works as documented
- Standard use cases succeed
Advanced Cases
Address more complex scenarios:
- Multiple valid inputs and their interactions
- State transitions and sequences
- Boundary conditions within valid ranges
- Performance characteristics (if contractual)
Edge Cases
Handle exceptional and corner situations:
- Invalid inputs and error conditions
- Empty, null, or missing values
- Extreme values (max/min bounds)
- Concurrent access (if applicable)
- Resource exhaustion scenarios
Arrange/Act/Assert Pattern
Structure each specification test using AAA:
Arrange: Set up preconditions and inputs
Act: Execute the behavior under test
Assert: Verify postconditions and outputs
Principles:
- Keep each section clearly separated
- One logical assertion per test (multiple physical asserts allowed if testing one concept)
- Arrange section should be minimal - complex setup suggests design issues
- Act section should be a single operation
- Assert section verifies the contract, not implementation details
Contract Tests vs Implementation Tests
Contract tests (specifications):
- Test against the abstraction/interface
- Verify behavioral contracts
- Run against any conforming implementation
- Focus on what, not how
Implementation tests:
- Test specific implementation details
- Verify internal behavior
- Tied to one implementation
- Focus on how
Specifications are contract tests. Keep implementation details out of specifications.
Property-Based Testing
Beyond example-based tests, consider properties that must always hold:
Common Properties
- Identity:
f(identity) = identity(e.g., adding zero, multiplying by one) - Idempotence:
f(f(x)) = f(x)(e.g., absolute value, normalization) - Commutativity:
f(a, b) = f(b, a)(e.g., addition, set union) - Associativity:
f(f(a, b), c) = f(a, f(b, c)) - Inverse:
f(g(x)) = x(e.g., encode/decode, serialize/deserialize) - Invariants: Conditions that must hold before and after operations
When to Use Properties
- Mathematical operations
- Serialization/deserialization pairs
- Collection operations
- State machine transitions
- Any operation with algebraic laws
Writing Effective Specifications
Detect Project Context
Before writing specifications:
- Identify the project's language and testing framework
- Follow existing test conventions and patterns
- Place specification files alongside or mirroring source structure
- Use the project's assertion style and utilities
Specification File Organization
tests/
├── specifications/ # or specs/, contracts/
│ ├── repository_spec.* # Repository abstraction specs
│ ├── cache_spec.* # Cache abstraction specs
│ └── parser_spec.* # Parser abstraction specs
└── implementations/ # Implementation-specific tests
Naming Conventions
Name specifications to describe the contract:
should_return_empty_when_not_foundshould_throw_on_invalid_inputshould_maintain_invariant_after_mutation
Dependencies
Specifications depend on the abstraction (interface/type), not any implementation:
Specification → Abstraction (interface)
↑
Implementation
This allows running the same specifications against different implementations.
Integration with Decomposition
When working with abstractions from software decomposition:
- Receive abstraction definition: Interface, responsibilities, collaborators
- Identify key behaviors: What must this abstraction do?
- Structure specifications: Basic → Advanced → Edge cases
- Define properties: What invariants must hold?
- Write executable specs: Test files depending only on the abstraction
Workflow
To specify an abstraction:
- Understand the abstraction: Read interface/type definition or description
- List behaviors: Enumerate what the abstraction must do
- Categorize: Assign each behavior to Basic/Advanced/Edge
- Identify properties: Find invariants and algebraic laws
- Write specifications: Create test file with AAA structure
- Verify dependencies: Ensure specs depend on abstraction, not implementation
Additional Resources
Reference Files
For detailed patterns and language-specific examples:
references/patterns.md- Common specification patterns by categoryreferences/properties.md- Property-based testing patterns and laws
Example File
examples/cache-spec.ts- TypeScript example showing the complete pattern (Basic/Advanced/Edge/Properties with AAA)