Skip to content

Conclusions

This project was undertaken as a practical exercise in applying Domain-Driven Design and DevOps practices to a non-trivial system. As such, we deliberately did not address concerns typical of production distributed systems, such as service availability, fault tolerance, or resilience patterns.

One of the most significant takeaways is that the hardest part of building a microservices system with DDD is not the implementation itself, but understanding the domain and designing the system correctly. The tactical design patterns offered by DDD provide a clear scaffolding that makes the implementation phase relatively straightforward once the design decisions are made. The real difficulty lies in the strategic design phase: identifying bounded contexts, defining their boundaries, and understanding how they relate to each other. On this front, Event Storming proved to be a valuable tool, helping surface domain concepts, clarify boundaries, and expose ambiguities early, before they could propagate into the implementation.

In hindsight, choosing the JVM as one of the backend runtimes introduced more accidental complexity than expected. The main source of friction was Gradle and the build-logic configuration: while the convention plugin approach is powerful, some aspects felt unnecessarily convoluted — for instance, using the version catalog inside build-logic requires a non-obvious workaround. The JVM choice also had downstream consequences on the development environment: we attempted to move the entire development environment to GitHub Codespaces using a devcontainer, but ultimately abandoned the effort. The official JetBrains plugin for Codespaces was removed from the IntelliJ marketplace, forcing us to fall back to other editors. In VSCode, there are no official JetBrains extensions for Kotlin development — only community-maintained ones that are poorly kept and largely unusable in practice. With a different language stack, Codespaces would likely have been a viable and productive option. A different language or build system might therefore have allowed us to spend that time more productively on all fronts.

Similarly, deploying the system on Kubernetes was an aspect we underestimated. Our goal was to experiment and learn the fundamentals, and we did gain a working understanding of the core concepts. However, the time invested in configuring and troubleshooting the cluster was substantial relative to the learning return, and a simpler deployment target would have been a more pragmatic choice.