Site icon JVM Advent

Spec-Driven Development in Practice: How AI Simplify Full-Stack Java

AI is changing how we build software, but many teams still work as if nothing has changed. They treat code as the only reliable artifact. Everything else slowly gets outdated:

AI code generation tools can make this even worse if used without structure. They produce code fast, but the process behind the code remains the same.

Spec-Driven Development (SDD) solves this by starting from clear specifications instead of starting from code. AI then uses these specifications to generate consistent code, tests, and documentation.

The AI Unified Process (AIUP) is a practical way to apply SDD in real projects. It keeps requirements, code, and documentation in sync. In this article, we look at AIUP in the context of a full-stack Java application built with Spring Boot, jOOQ, and Vaadin.

From Code-Centered To Spec-Driven

In most teams, development is code-centered:

This leads to long-term problems:

Spec-Driven Development flips this:

  1. You start with a clear specification.
  2. This specification becomes the single source of truth.
  3. AI generates code, tests, and diagrams from it.
  4. Developers review and adjust the generated results.

When requirements change, you update the specification first, then regenerate.

The AI Unified Process (AIUP)

AIUP is an iterative process with a simple but powerful structure.
It is built on three core specification artifacts:

  1. Requirements Catalog
  2. Entity Model
  3. System Use Cases

These artifacts are always updated in this order. Everything else flows from them.

1. Requirements Catalog

The Requirements Catalog is the foundation of AIUP.
It defines what the system must do and under which conditions.

It contains three types of requirements:

Functional Requirements

These describe what the system should do. In AIUP, they are usually written as user stories.

Examples:

Functional requirements describe user goals and expected behavior, not code.

Non-Functional Requirements

These describe qualities of the system, like:

Example:

Constraints

These describe rules that must always be enforced.

Examples:

The Requirements Catalog is written in simple, precise language. It is reviewed frequently and kept under version control. Everything in AIUP starts with this catalog.

2. Entity Model

The Entity Model describes the domain data structure.
It answers:

Which concepts exist, and how do they relate?

The Entity Model is based on the Requirements Catalog. Functional requirements describe what users want to do. Constraints often describe the domain rules. From both, you extract stable domain objects.

For example, from the requirements above, you define:

Entities:

Attributes:

Relationships:

The Entity Model lets AI generate:

It ensures that back end, database, and UI use the same domain structure.

3. System Use Cases

AIUP uses only System Use Cases. There is no separation between business and system use cases.

A System Use Case describes how the system behaves when triggered by a user or external system. It defines:

System Use Cases transform requirements into explicit logic.

Example System Use Case: Deactivate Customer

Name: Deactivate Customer
Actor: Administrator
Preconditions:

Main Flow:

  1. Load customer
  2. Load related orders
  3. Check for open orders
  4. If open orders exist, return error
  5. Set customer.active = false
  6. Write audit entry

Postconditions:

How AIUP Runs In Iterations

AIUP uses short iterations. Each cycle follows this sequence:

  1. Update Requirements Catalog
  2. Update Entity Model
  3. Update System Use Cases
  4. Generate code, diagrams, and tests with AI
  5. Review and improve the generated output
  6. Run tests
  7. Refine the specifications

This creates a stable, controlled development loop.

Example: A Java Feature With AIUP

Imagine you add a “Deactivate Customer” feature. All documentation is code and under version control.
The example uses Markdown, but you could also use AsciiDoc to get a richer Markdown syntax.

Step 1: Requirements Catalog

| Category                  | Description                                                |
|---------------------------|------------------------------------------------------------|
| Functional requirement    | As an admin, I want to deactivate a customer who has no open orders. |
| Non-functional requirement| All write operations must be audited.                      |
| Constraint                | Customer email must be unique.    

Step 2: Entity Model

Entity: Customer with id, name, email, active  
Entity: Order with id, status, customerId  
Relation: Customer 1..* Order  
Rule: Status can be OPEN, COMPLETED, or CANCELLED

AI generates:

Step 3: Use Cases

## UC-001: Deactivate Customer

**Name**  
Deactivate Customer

**Actor**  
Administrator

**Preconditions**  
- User is authenticated  
- User has role ADMIN

**Main Flow**  
1. Load customer  
2. Load related orders  
3. Check for open orders  
4. If open orders exist, return error  
5. Set customer.active = false  
6. Write audit entry

**Postconditions**  
- Customer is inactive  
- Operation is logged

AI generates:

You review, adjust, and commit.

Why This Fits Full-Stack Java So Well

AIUP fits the Java ecosystem because:

AIUP connects these elements with a straightforward process.

Benefits For Teams

AI Is A Partner, Not A Replacement

AIUP assumes a skilled development team. Developers still:

AI accelerates work. Developers ensure correctness.

Conclusion

Spec-Driven Development with AIUP provides teams with a structured approach to using AI. AI can generate code, tests, and diagrams that stay consistent with the specification.

In a Java stack using Spring Boot, jOOQ, and Vaadin, this approach is a natural fit. It increases speed, improves quality, and keeps the system aligned with business needs.

To get started:

This is how AIUP makes full-stack Java development faster, safer, and more consistent.

See it in Action

Two webinar recordings show how to work with the AIUP: Spec-driven Development and Spec-driven Testing

Author: Simon Martinelli

Simon Martinelli is a Java Champion, Vaadin Champion, and Oracle ACE Pro, with over three decades of experience as a software architect, developer, consultant, and trainer. As the owner of Martinelli LLC, he specializes in optimizing full-stack development with Java and has a deep focus on modern architectures and distributed systems. He frequently shares his expertise by speaking at international conferences, writing articles, and maintaining his blog: https://martinelli.ch. His passion for teaching is reflected in his work as a lecturer at the Bern University of Applied Sciences BFH and the University of Applied Sciences Northwestern Switzerland FHNW, where he teaches courses on modern architecture, distributed systems, persistence technologies, and DevOps.
Exit mobile version