Design Tests Code

Deterministic AI code generation.

Human review architecture design. AI does the typing. DisC turns UML sequence diagrams into mockist tests that leave AI zero room to interpret.

See it in action

Watch how DisC turns a UML sequence diagram into tests and working code.

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
~
Spec-Driven Partial (still natural language)
DisC Tests (mechanically generated from formal spec)

Design is Code restores the contract.

How it works

Four steps. From verified truth to guaranteed implementation.

0

Establish truth

Before you design, verify your assumptions. If you don’t know how an API behaves — spike it. If you’re guessing about data formats — test them. Design based on facts, not assumptions.

Output: verified facts that justify the diagram you’re about to draw.

informs
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

preview

GreetingServiceGreetingFactoryGreetingServiceGreetingServiceGreetingFactoryGreetingFactorycreate(userName)greeting: Greeting
generates
2

Each arrow becomes a verify()

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

DefaultGreetingServiceTest.java

 public interface Greeting {}
 public interface GreetingService { Greeting greet(String userName); }
 public interface GreetingFactory { Greeting create(String userName); }


 @MockitoSettings(strictness = Strictness.LENIENT)
 class DefaultGreetingServiceTest {

     @Mock private GreetingFactory greetingFactory;
     @Mock private String userName;
     @Mock private Greeting greeting;

     private Greeting result;
     DefaultGreetingService defaultGreetingService;

     @BeforeEach
     void setUp() {
         defaultGreetingService = new DefaultGreetingService(greetingFactory);
     }

     @Nested
     class WhenGreet {
         @BeforeEach
         void setUp() {
             when(greetingFactory.create(any())).thenReturn(greeting);
             result = defaultGreetingService.greet(userName);
         }

         @Test
         void shouldCreateGreeting() {
             verify(greetingFactory).create(userName);
         }

         @Test
         void shouldReturnGreeting() {
             assertThat(result).isEqualTo(greeting);
         }
     }
 }
constrains
3

AI writes code to pass the tests

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

DefaultGreetingService.java
 @Component
 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

Why Design is Code

AI coding tools promise speed. They create three structural problems that Design is Code solves.

No design, no ownership

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

DisC keeps the design artifact as the source of truth.

Prompt in, mystery out

Same prompt, different architecture every time. No guarantee of quality, no guarantee of consistency. If no one designed it, no one can maintain it.

One design, one possible implementation.

Cost asymmetry

AI generates at zero cost and pays nothing when it’s wrong. You review at high cost and pay for everything it missed. That’s not collaboration — that’s a broken feedback loop.

Tests generated from design — review is spot-checking, not archaeology.

Try it now — Claude Code + Java

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

Requires Claude Code and a Java 17+ project (JUnit 5 + Mockito).

Don’t use Java or Claude Code? The methodology works for any language and any AI coding tool. Draw the sequence diagram, generate mockist tests from it, then let AI implement against the tests. The plugin automates this for Java. The thinking applies everywhere.

Install Design-Is-Code plugin for Claude Code

  1. 1.

    Install the plugin for Claude Code (plugin docs):

    terminal
    claude plugin marketplace add mossgreen/design-is-code-plugin
    claude plugin install design-is-code@mossgreen-design-is-code --scope user
  2. 2.

    Put your UML sequence diagram in your project's design/ folder

  3. 3.

    Start a Claude Code session, then run /design-is-code:disc <sequence-diagram-filename>

DisC vs. alternatives

Criteria Vibe Coding Spec-Driven DisC
Input Prompt Natural language spec UML diagram
AI interprets? Yes Yes (less) No
Same output every time? No No Yes
Tests generated from design? No Sometimes (AI-written) Mechanically from diagram
Design artifact survives? None Markdown docs Formal spec + tests
Upstream verification? None None Human review architecture design

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.

How is this different from Kiro or Spec Kit? +

Kiro and Spec Kit use natural language specifications — structured requirements, acceptance criteria, technical plans. This is better than vibe coding, but the spec is still English, and English is ambiguous. The same spec can produce different architectures on different runs. DisC uses formal notation (UML sequence diagrams) that maps 1:1 to test assertions. Tests are generated mechanically from the diagram, not written by hand or by AI. The result: one diagram, one set of tests, one possible implementation. Deterministic, not interpreted. Spec-driven development organized the input. DisC made the output deterministic.

What is Step 0? Why do I need it? +

Step 0 is the discipline of verifying your assumptions before you design. If you don't know how an external API behaves, you spike it. If you're guessing about data formats, you test them. You design based on verified facts, not guesses. DisC guarantees your code matches your design. Step 0 ensures your design matches reality. Without it, you can have a perfectly implemented wrong design. No other spec-driven tool addresses this. They all assume you already know what you want. DisC assumes you should prove it first.