Build an application, one architectural decision at a time
Start with a passing domain test. Then follow a delivery operation through behavior, transactions, persistence, events and an external carrier. Each chapter answers a practical question; focused examples isolate details when the full system would distract.
These tutorials describe Vernac 0.5.0. Use JDK 25 for the documented builds;
generated application code targets Java 21. Released consumers use 0.5.0 artifacts
from Maven Central after publication. Repository examples use 0.5.0-SNAPSHOT by
default: install matching local artifacts first, or select the release with
-Dvernac.version=0.5.0 after publication.
Commands below include mvn; use the full command in the IntelliJ Maven run configuration used for these examples.
In PowerShell, quote a complete dotted -Dproperty=value argument when necessary.
Looking for one topic rather than a full learning path? Use the documentation map.
How to use the examples
The Task chapters are small, database-free exercises. The delivery chapters use
examples/persistence-demo; Dispatch adds a browser UI. Unless explicitly labelled
as an addition, a complete model is an alternative exercise: do not paste it into a
namespace that already defines the same types. Fragments belong inside the named
existing declaration. Revert intentional failures before moving to the next chapter.
Each chapter tells you where commands run and which extra dependencies it needs. For a source checkout, use the example build guide.
New to DDD? Start with the ideas
- What is DDD?: values, identities, aggregates and usecases explained with a task board.
- DDD for a small project: use the structure you need without inventing a large architecture.
- Choose your first success: a database-free domain test or a working web application.
Already know DDD? Start at the first domain model or use the documentation map to jump directly to your task.
1. Make the domain explicit
- Set up IntelliJ: create a project and navigate between Vernac and Java.
- Your first domain model: values, identity and a tested operation.
- From model to application: see how the architectural pieces connect.
- Default names and explicit roles: choose a clear generated API.
- Closed domain values: model states without transport codes.
- Lists, sets and repeated values: make multiplicity and identity intentional.
-
Domain behavior: inline Java, private helpers and external implementations.
-
Keep the meaning beside the model: a shared glossary, type hover and vocabulary for AI-assisted work.
- See the architecture: a namespace diagram, vocabulary and export for documentation.
Debug the business rule
Debug your business behavior where you wrote it walks through breakpoints, stepping, variables, Java expressions, conditions and logpoints in a small database-free application. Use matching 0.5.0 compiler and plugin artifacts, or the matching SNAPSHOT source build.
Start with a real web application
From New Project to a working application creates a small Thymeleaf/PostgreSQL task workspace from the 0.5.0 wizard. It demonstrates a complete browser-to-usecase-to-database path, local Compose, migrations and deployment configuration. The MVC adapter tutorial shows how to declare HTML pages, forms, redirects and safe error redisplay directly in Vernac.
2. Turn behavior into an application operation
- Usecases: one operation, declared results and one transaction boundary.
- Domain services: move a Stop between Tours using a shared domain rule.
3. Keep and evolve state
- Persist complete aggregates: shared entities, queries and concurrent changes.
- Repository queries: equality, absence, text patterns and boolean expressions. The pagination tutorial demonstrates generated queries, counts, independent usecase Result components and a paginated GET.
- Evolve with Flyway: review and apply a migration while retaining data.
- Schema tooling: snapshots, backfills and disposable-database verification.
4. React to facts and cross system boundaries
- Domain events: synchronous participation and durable deferred delivery.
- Run the ports and ACL walkthrough: inspect real HTTP calls against a local fixture.
- A Java-backed outbound port: the same architecture without HTTP.
- DTOs and PATCH: names, absence and explicit update intent.
- Mappings: translate transport records into validated domain values.
- Declarative REST: bind requests and responses.
- Declarative error translation: distinguish rejection from technical failure.
- HTTP runtime: use the lower-level Java API when needed.
- HTTP inbound adapters: expose a usecase with an explicit request/response contract.
FAQ · Language reference · Specification · Documentation home
Put the pieces together
Run Vernac Dispatch: an interactive application connecting the domain, transactions, PostgreSQL, durable events and a carrier ACL.
Reuse and evolve a type module: publish domain values, import them, create the initial application migration and upgrade a flattened external VO. The chapter explains explicit activation, provider selection, dependency navigation and independent migration histories. Run the persistent module lifecycle: call two persistent modules from an application, then upgrade their shared value with reviewed backfills while retaining existing data. Its separate API module and durable event receivers demonstrate the same activation graph.