chapter four
4 The honest hexagon: Use cases, commands, and the case against exceptions
This chapter covers
- Defining use cases as typed input port contracts using domain language
- Why exceptions as the sole error channel leave your use case contracts incomplete
- Replacing exception-based error handling with Either<Error, R> for compiler-enforced, explicit failure paths
- Structuring input as self-validating commands and queries
- Routing use cases through a command and query bus
- A first look at domain events as a mechanism for decoupled side effects
We built the core of WriteFlow's domain: entities that guard their own invariants, value objects that make illegal states unrepresentable, and factories that ensure objects enter the world valid. The domain is honest—it cannot be constructed into an invalid state, it says what it means, and it hides what it does not want touched. Now we wire that domain to the outside world.
This chapter is about the application layer—the thin ring that sits between external actors and your domain, orchestrating use cases without owning business logic. It is thinner than most developers expect; more powerful than most codebases reveal, though.