
🚢 DeepStrike – Applying DDD, Clean Architecture, Event Sourcing, and CQRS in a Battleship Game
As software engineers, we constantly hear about concepts like Domain-Driven Design (DDD), Clean Architecture, Event Sourcing, and CQRS. They appear in conference talks, blog posts, and technical debates.
But what really caught my attention was Event Sourcing. I wanted to understand how to structure aggregates in a way that works naturally with Event Sourcing and CQRS.
That’s how DeepStrike was born — a proof of concept where I used these architectural techniques to implement something both fun and complex enough: a digital version of the classic Battleship game.
The Book That Sparked the Idea
One of the main inspirations for this PoC was the book: 📖 Learning Domain-Driven Design: Aligning Software Architecture and Business Strategy by Vlad Khononov.
It’s an incredible resource that helped me connect business strategy with technical architecture. What I really loved about the book is how it demystifies DDD: it’s not about heavy frameworks or obscure patterns, it’s about language, collaboration, and boundaries.
This book gave me the confidence to take the next step: building something myself.
Why Battleship? 🎯
When choosing a domain for the PoC, I wanted something that:
- Had a clear ubiquitous language (ships, shots, boards, hits, sinks…).
- Allowed for state changes to be expressed as events.
- Was simple enough to implement, but rich enough to explore concepts like aggregates, projections, and history navigation.
The classic Battleship game was a perfect match. Every action — placing a ship, firing a shot, marking a hit — naturally translates into an event. And that made it a great playground for Event Sourcing and CQRS.
How I Built It ⚙️
I decided to split the project into two modules, each with its own architectural approach:
API (Domain Core)
- Built with DDD, Event Sourcing, CQRS, and Clean Architecture.
- Domain logic is expressed through aggregates and value objects.
- Game state is reconstructed by replaying events.
- Projections (like Game Summary) use CQRS to provide fast reads.
- PostgreSQL + Liquibase → Events and read models persisted in a structured way.
- OpenAPI → Contract-first approach with code generation for API stubs.
CTL (Supporting Domain)
- A lightweight Spring Shell CLI client.
- Implements commands such as create, fire, join, ready.
- Orchestrates requests to the API, handles errors, and provides user feedback.
- No heavy domain logic — just a transaction script pattern.
Other Tech Choices
- Java 21 + Spring Boot as the foundation.
- Docker to run Postgres and the system easily.
What I Learned 💡
Building this PoC was full of “aha!” moments. Some of my main takeaways:
- DDD is about shared understanding. Modeling the game using its own language (ships, shots, hits) made the code more expressive and aligned with the domain.
- Event Sourcing gives superpowers. Instead of just storing the current state, I can replay the entire game, debug past moves, or even reconstruct “what the board looked like at turn 5.”
- CQRS reduces complexity. By separating reads and writes, I could design projections like Game Summary without polluting the main aggregate logic.
- Clean Architecture enforces discipline. It kept my domain pure and isolated from infrastructure details.
- Learning accelerates with practice. Reading concepts was useful, but building something concrete made everything “stick” in my mind.
Challenges Along the Way ⚔️
Of course, it wasn’t all smooth sailing:
- I ran into ship overlapping issues when generating random fleets.
- Handling coordinates (A–J, 0–9) was trickier than expected, since humans think in grid letters while the system thinks in integers.
- Designing events to be both expressive and minimal took several iterations.
- But each challenge was exactly what I wanted: a chance to think like a domain modeler, not just a coder.
Repository 📂
For anyone curious to dive deeper, the full source code is available here: 👉 GitHub Repository – DeepStrike
Final Thoughts 🌟
This project wasn’t about building the “perfect” Battleship game. It was about using a playful domain to explore serious architectural principles.
If you’re learning DDD, Event Sourcing, or CQRS, my advice is: ⚡ Don’t stop at theory. Pick a domain (even a game!) and try to model it. You’ll be amazed at how much the concepts come alive when applied.
And if you’re looking for guidance, Vlad Khononov’s Learning Domain-Driven Design is a fantastic starting point. It truly changed how I approach software design.