UML Tests Code

In software, the real work is design.
Code is the consequence.

Deterministic AI code generation.

Where it broke

AI: zero cost to generate / zero cost to be wrong
You: high cost to review / high cost if you miss an error
"Build a greeting service"
Run 1 → GreetingService.greet(String name)
Run 2 → GreetingHandler.handle(GreetRequest req)
Run 3 → Greeter.sayHello(User user)
Same prompt. Three different architectures.

Every step had a contract. Natural language broke it. DisC restores it with tests.

Assembly Assembler
C Compiler
OOP Compiler
Natural Language None
DisC Tests

Design is Code restores the contract.

How it works

Three steps. Each one narrows what the AI can do, until the only code it can write is the code you designed.

1

Draw the interaction

Each arrow is a decision you’re making about how components talk to each other.

design/greeting.puml
@startuml
GreetingService -> GreetingFactory: create(userName)
GreetingService <-- GreetingFactory: greeting: Greeting
@enduml
generates
2

Each arrow becomes a verify()

The solid arrow became a verify(greetingFactory).create(userName) assertion. Deterministic.

DefaultGreetingServiceTest.java
@Test
void shouldCreateGreetingWithUserName() {
    // Given
    String userName = "World";
    Greeting expectedGreeting = new Greeting("Hello, World!");
    when(greetingFactory.create(userName)).thenReturn(expectedGreeting);
    // When
    Greeting result = greetingService.greet(userName);
    // Then
    verify(greetingFactory).create(userName);
    assertThat(result).isEqualTo(expectedGreeting);
}
constrains
3

AI writes code to pass the tests

No interpretation, no creative freedom. The test suite is the contract.

DefaultGreetingService.java
public class DefaultGreetingService implements GreetingService {
    private final GreetingFactory greetingFactory;

    public DefaultGreetingService(GreetingFactory greetingFactory) {
        this.greetingFactory = greetingFactory;
    }

    @Override
    public Greeting greet(String userName) {
        return greetingFactory.create(userName);
    }
}

1 solid arrow = 1 verify() test = 1 method call

What’s at stake

AI coding tools promise speed. They deliver three new problems.

Your skills disappear

When AI writes the code, you get the output without the journey. You can’t defend the architecture. You can’t adapt when requirements change. You can’t spot when the reasoning was wrong.

You become the quality filter

AI generates at zero cost. You review at high cost. Miss one error and it ships. This isn’t collaboration — it’s exploitation.

Your codebase becomes fragile

If AI goes offline tomorrow, can your team maintain what it wrote? If no one designed the architecture, no one understands it.

Get started

DisC ships as a Claude Code skill. Install it in seconds and start generating tests from your UML diagrams.

Requires Claude Code and a Java 17+ project (JUnit + Mockito). Additional language support coming soon.

Claude Code Skill

terminal
# Add the skill from the marketplace
/skill add --name "design-is-code" mossgreen/design-is-code-plugin

# Put UML files in your project's design/ folder, then run:
/design-is-code:disc <filename>

Frequently asked questions

Why UML? Isn't that outdated? +

UML sequence diagrams aren't about ceremony — they're the most compact formal notation for expressing object interactions. Unlike class diagrams or activity diagrams, sequence diagrams map 1:1 to method calls and test assertions. We're not using UML for documentation; we're using it as a specification language that both humans and AI can execute deterministically.

Does this scale beyond simple CRUD? +

DisC is designed for interaction-heavy code: services calling other services, orchestration logic, workflows with branching and loops. The more complex the interaction structure, the more value you get from formal specification. Pure algorithmic code (sorting, math, parsing) is explicitly out of scope — use traditional TDD for that.

What about existing code? +

You can adopt DisC incrementally. Start with new features: draw the sequence diagram, generate tests, then implementation. Existing code doesn't need to be rewritten. As you add new interactions, the formally specified portion grows naturally.

Is this suitable for regulated environments? +

Yes. Every method call traces back to an arrow in the sequence diagram, and every arrow generates a test. The formal specification serves as living documentation — design decisions are captured in a reviewable artifact before any code is written. For teams in banking, insurance, healthcare, or any domain where traceability and auditability matter, this is design you can point to.

What about languages other than Java? +

The DisC methodology is language-agnostic, but the current Claude Code skill generates Java (JUnit + Mockito). Support for additional languages and test frameworks is on the roadmap. The UML diagrams themselves don't change — only the code generation templates.

How is this different from normal TDD? +

TDD has you write tests first, but the tests are still code — you're making implementation decisions while writing them. DisC separates design (UML) from implementation entirely. The tests are generated mechanically from the diagram, ensuring they test the specified interactions and nothing more. There's no temptation to test implementation details.