Building software has come a long way over the past few years, but at the same time, it has become increasingly complex. With new technologies, databases, frameworks, and deployment methods emerging all the time, it's hard to keep up.
As developers, we understand the importance of building software that not only functions correctly, but also adds real value to the end-users. This is why we strive to focus on the core business logic and the features that directly contribute to the user experience, rather than spending countless hours on the mundane tasks that often come with software development.
We of course streamline the development process and try to minimize the amount of time spent on non-essential tasks, but it's still overwhelming. Requirements change, deadlines always seem impossible, the world of software continues to evolve at an ever-increasing pace, it seems that the challenge of keeping up is here to stay.
Ultimately, we want to create software that has a greater impact on the world, while also making our jobs as developers more fulfilling and enjoyable.
That's why we decided to take a step back and really focus on software architecture. We dug deep into Hexagonal Architecture, Event Driven Architecture, and other patterns like CQRS and Event Sourcing. We also dove into Domain Driven Design and Behaviour Driven Development.
Well, after months of learning and working on the Bitloops Platform (join waiting list - release in a few months), we created the Ultimate ToDo app that follows all of these great design patterns and principles.
Now, we know what you're thinking, a ToDo app might not need to be this over-engineered. But trust us, this app is a great example for building awesome software that's easy to understand and easy to change.
You can find the entire codebase in our GitHub Repo: ddd-hexagonal-cqrs-es-eda. We've used TypeScript / NodeJS and built it with Nest.JS.
The repo and codebase has been designed to help you learn, leverage and copy to build software that's organized, easy to understand, and easy to change.
And the best part, it uses available open-source technologies and has integrations setup for MongoDB, PostgreSQL, NATS, JWT (for authentication), Jaeger and Prometheus, but of course, all of these can be changed or adapted if you wish.
Let me break down the example for you!
Hexagonal Architecture, which is a great approach for building modern software applications, is a core inspiration, as well as domain-driven design (DDD) for the design of the domain logic.
The combination of these two software patterns / principles makes it really easy to build tests, create new features, and change stuff, without having to worry about unintended consequences.
At their core, both hexagonal architecture and DDD preach the separation of business logic code from infrastructure code. This ensures your code is organized, easy to understand, and easy to change.
Therefore, in the example provided, we clearly separated the domain and application code from all the other code, including the website, authentication, database, and tracing and observability tools we use.
Now, when it comes to understanding the domain, we use Event Storming to help us out. It helps us get all of our domain experts, product managers, and developers on the same page, speaking the same language, and aligning on what's required.
In this particular example, we created three bounded contexts and different number of processes within each:
- User Login process
- User Registration process
- Todo Process
- Onboarding Process
Clarification: the event storming yielded many interesting and valid ideas for the ToDo app - the options are almost limitless. However, the purpose of this example was to demonstrate the software design and architecture, not ToDo App features!
Focusing on the Todo process as it is the core domain, we've identified five commands that are separate use cases:
- Add Todo
- Complete Todo
- Uncomplete Todo
- Modify Todo Title
- Delete Todo
Each of these use cases should be separate from the other, and that's why this step is so important. If you do this well, you'll find that the actual coding is quite simple.
For more details do checkout the Github repo.
We have a clear project folder structure that follows the output of the event storming. The business/domain logic code is where the high-value code lies.
This is what differentiates your application from others, so it's important to keep it well organized and easily changeable.
For the Todo process, we've set up the application to coordinate the activities and hold the use cases.
Why do we need all this?
- The commands trigger the command handlers
- Contracts specify how the todo module communicates with other modules
- The domain contains all the elements using DDD
- Ports represent the interface between the application and infrastructure
- Queries trigger the query handlers
- Tests include all the behavior driven tests that were identified
The code is all there in the repo, but its actually not the most interesting part. Setting it up and designing the application correctly is what makes the code so simple and practical.
Well, we believe that it can help developers of all levels as one of the main benefits is that the overheads and complications of using these design patterns and principles have been taken care of for you.
More experienced developers can use it as a template to more quickly and efficiently build projects that follow these design patterns and best practices. It serves as a quick reference guide or a cheat sheet on the side - a cheat sheet that you can easily tailor to your liking or contribute back if you have other things to add. The structure of the codebase alone will make your life easier when it comes to coding.
If you're a developer with intermediate experience, this implementation reference is gonna be your sidekick in helping you implement best practices. It'll make your software more organized and easier to understand, so you can save time and focus on things that are way more important.
And if you're new to this whole development game, this is your chance to get **exposure to a modern tech stack **that's gonna make you feel like you're in the big leagues. So don't be afraid to jump in and give it a shot, you might just surprise yourself.
If you found any of this interesting, I recommend taking a look at the project itself - we have all the code there.
Our ultimate goal is to build a platform that will help developers design and build scalable, resilient and easy to maintain applications like this example, but in an easier and even faster way.
This implementation reference is a sneak preview of what our platform will offer: empowering developers to focus on what really matters, the features that add value to your users.