When I started building RouteBastion, a Broker to unify APIs for solving the Vehicle Routing Problem (VRP), I was determined to design it the "right way". Clean code, separation of concerns, rich domain models... Everything! Naturally, I turned to Domain-Driven Design (DDD).
I went deep into DDD: Bounded Contexts, Aggregates, Entities, Value Objects, Ubiquitous language... One can say I was cooking by the (blue) book.
I modeled customers, API keys, vehicles, and even constraints as domain objects. It was elegant, well, at least on paper.
The Real Complexity Wasn’t in the Domain
As the days passed by and I refactored parts of the code, I realized something important: my real complexity wasn’t in the domain, but it was in way I interacted with Cloud Providers.
Being a Broker of APIs means:
- Massive requests can eventually come through;
- Dealing with quotas and rate limits;
- Caching strategies, concurrency, and task queues;
- Periodically checking statuses on the external APIs.
The domain part (the "business logic" of who a customer is, or what a vehicle does) is stable, simple, and predictable. What isn’t simple is the Cloud selection algorithm, tuning performance of my database, and designing scalable queue-based execution for solving hundreds of routes in parallel.
What I Learned
DDD shines when business rules are complex and volatile. That’s not the case with RouteBastion. My complexity was mostly technical, not business-oriented. That doesn’t mean DDD was useless, quite the opposite. Here’s how I’ve reframed things:
- I still use DDD principles to structure my codebase and isolate concerns;
- My core domain is now focused on orchestration of routing solutions (namely external APIs);
- Performance, and concurrency are now treated as first-class citizens in my architecture.
That realization led me to offload anything that wasn’t core to my problem space. For example, I used Kong Gateway for the first time to handle things like:
- Rate limiting;
- Authentication;
- Routing.
These were concerns that didn’t belong in my domain layer, they were infrastructure responsibilities. Kong helped me focus on the actual routing orchestration and performance tuning, while still ensuring production-grade API exposure.
Advice for Devs Exploring DDD
If you're on a DDD journey and your domain feels "too simple", ask yourself:
- Where does your system’s complexity really come from?
- Are you solving a business problem, a technical challenge, or both?
- Could your “domain layer” be more about orchestrating processes than modeling behavior?
DDD is a great tool, but like any tool, its value depends on when and how you use it.
Closing Thoughts
Building RouteBastion has taught me to appreciate the separation of domain and infrastructure, but also to recognize when the “domain” isn’t the main actor. Sometimes, you're not building a business system, you're building a high-performance system that serves a business system.
And that’s perfectly fine. Now, I'm slowly refactoring parts of my system to gain more traction for future development.
If you’ve ever wrestled with something related, I’d love to hear your story too.
🤘 Thanks for reading, follow me if you're into DDD, architecture, and solving hard problems with clean code.
We’re thrilled to announce free tokens now live for Dev.to contributors to reward our amazing writing community! Connect your wallet here (no gas fees). – Admin