We use cookies to ensure you get the best experience on our website.

6 min read
Executable Specs: Turning Plain English into Running Systems
Investigates the emerging practice of writing specs that double as documentation and runnable code. Demonstrates tooling patterns and pitfalls.

What are executable specifications?

Link to this section

Executable specifications are documents that describe the behavior of a system in a way that is both human-readable and machine-executable. They serve as a single source of truth for a feature, bridging the gap between the plain-English requirements defined by product managers and the functional code written by engineers. By writing specifications that can be run as automated tests, teams can ensure that the system behaves exactly as described, creating a living document that evolves with the software.

This approach often uses frameworks that follow Behavior-Driven Development (BDD) principles, where specifications are written in a structured natural language format, such as Gherkin. This allows stakeholders with varying technical expertise to understand and validate the system’s intended behavior.

How do they work?

Link to this section

Executable specifications connect plain-text feature descriptions to the application’s codebase through a series of structured steps. The process generally follows a consistent pattern that turns descriptive language into automated tests that verify the system’s functionality.

A typical workflow looks like this:

  1. Define the behavior: A feature’s behavior is described in a structured, natural-language format. A popular syntax for this is Gherkin, which uses Given, When, And, Then keywords to outline a specific scenario.
  2. Write step definitions: Each line in the specification is then mapped to a corresponding “step definition” in the codebase. This is a block of code that executes the action described in the step. For example, the line “Given a user is logged in as an administrator” would be linked to a function that creates an administrator session in a test environment.
  3. Implement the feature: With the tests in place, developers write the application code needed to make the tests pass. The specification acts as a clear set of requirements, guiding development and signaling when the feature is complete.
  4. Run the specification: The specification is executed as part of an automated test suite. If all the steps pass, the team can be confident that the feature has been implemented correctly. If a step fails, it immediately flags a discrepancy between the specification and the system’s actual behavior.

This cycle of defining, testing, and implementing ensures that documentation and code are never out of sync.

Why are they important?

Link to this section

Adopting executable specifications offers significant advantages for software teams by improving clarity, reducing ambiguity, and automating validation. This practice helps align product, engineering, and quality assurance, creating a more efficient and reliable development process.

Key benefits include:

  • A single source of truth: It eliminates discrepancies between documentation and actual system behavior. The specification is the test, so if it passes, it reflects the current state of the system.
  • Improved collaboration: Product managers, developers, and QA engineers can all contribute to and understand the specifications. This shared understanding reduces rework and ensures everyone is aligned on the desired outcome.
  • Living documentation: Unlike traditional documentation that quickly becomes outdated, executable specifications are constantly validated against the codebase. They evolve with the product, providing an accurate and reliable reference for how the system works.
  • Faster feedback loops: By automating the validation of requirements, teams can catch bugs and deviations from the specification earlier in the development cycle, reducing the cost and effort of fixing them.

These benefits lead to higher-quality software, faster delivery cycles, and better alignment between business goals and technical implementation.

Best practices for writing executable specs

Link to this section

To get the most out of executable specifications, it’s important to follow a few best practices. These guidelines help ensure that your specs are clear, maintainable, and effective at driving development and communication.

  • Focus on behavior, not implementation: Specs should describe what the system does from a user’s perspective, not how it does it. For example, instead of “When the user clicks the ‘Save’ button,” write “When the user saves their profile.” This makes the spec more resilient to UI changes.
  • Keep scenarios focused: Each scenario should test a single, specific rule or behavior. Avoid creating overly long or complex scenarios that try to cover multiple outcomes. A focused scenario is easier to understand, debug, and maintain.
  • Use declarative language: Use a clear and consistent vocabulary that is understood by everyone on the team. Avoid technical jargon and focus on the business domain. The language should be accessible to product managers and other non-technical stakeholders.
  • Regularly review and refactor: As your product evolves, so will your specifications. Regularly review them to ensure they are still relevant and accurately describe the system’s behavior. Refactor them as needed to improve clarity and remove duplication.

Following these practices helps create a suite of executable specifications that are not only effective as tests but also serve as a valuable and long-lasting form of documentation.

How Kinde helps

Link to this section

Implementing executable specifications requires a clear way to define and verify system behavior, especially for critical functions like authentication and authorization. Kinde provides a powerful and straightforward API that simplifies this process, allowing you to easily test complex user management scenarios.

For example, a specification might describe how a user with a specific role can access a protected feature.

Scenario: An editor can publish articles

  • Given a user is logged in with the “editor” role
  • When they attempt to access the article publishing page
  • Then they should be granted access

To implement the “Given” step, your test code would interact with Kinde to create a user and assign them the “editor” role. You can define roles and the permissions associated with them directly in the Kinde dashboard, making it simple to manage access control rules. The “Then” step would check if the application, using information from Kinde’s tokens, correctly identifies the user’s permissions and grants access.

By using Kinde to manage roles and permissions, you can easily write tests that verify your application’s authorization logic against clear, human-readable specifications. This ensures that your access control rules are not only correctly implemented but also perfectly documented.

Kinde doc references

Link to this section

Get started now

Boost security, drive conversion and save money — in just a few minutes.