Hi you guys !
I had the pleasure to be involved in a project in where I've learned a lot about DDD and through this article I want to explain the knowledge that I got.
During this article we're going to see a complete example and it's important that you have at least a basic knowledge about DDD, AWS and Nodejs.
A brief introduction to DDD
First of all we need to understand what's DDD (Domain-Driven Design), and it's a hard question being honest but I'd like to put a sentence that maybe can help you for acknowledging the journey that we're going to do.
Using DDD is incredibly useful when designing services because it helps you rationalise the granularity of your software, the ownership boundaries and model interactions need to build de-coupled and reactive distributed systems
Reference from: Domain Driven Design (DDD): Core concepts and Enterprise Architecture
I think the keyword that I'd put focus would be granularity and it's completely true, imagine that you have a big solution such as: ERM, Social Network, etc. You can write your solution with a big diagram design where you've put your entities and N attributes + N relationships and it's fine but do you think would be the best solution ? You could answer with a 'depends' and you're right, it exists big solutions and small solutions but I always thought that this methodology will work for any size.
If you're interested more about this topic I'll let you a few articles that you could check out before to analyze our solution.
The Value at the Intersection of TDD, DDD, and BDD
Domain-Driven Design Starter Modelling Process
Domains, Sub-Domains and Bounded Contexts: Explained with example from industry
DDD Bounded Contexts and Java Modules
DDD Part 1: Strategic Domain-Driven Design
My Hide-URL Project
DDD Solution
Yes ! For this example we're going to create a hide-URL project. I've chosen this solution because I think it's easy to implement it.
It's important to clarify that this example is just for a example and when I say this's because for creating a real DDD solution we need to have several meetings, involve stakeholders, apply event storming, know about the business, etc.
Inside our domain that I called Custom Hide-URL Domain I'll have two subdomain:
1) Hide-URL Subdomain
Type: Core
1.1) Hide Bounded Context
1.1.1) Ubiquitous Language
URL: The way that the user can enter to a website
Hide-URL: Hide a big URL to a small id
1.1.2) Input Communication
Front-end (User): Create hide url, Get hide url
2) Identity Management Subdomain:
Type: Generic
2.1) Identity Management Bounded Context
2.1.1) Ubiquitous Language
Email: The email that a user has for accessing.
Password: The password that a user has for accessing.
2.1.2) Input Communication
Front-end (User): Generate token
Hide Bounded Context: Validate token
Now we can define our Context Mapping:
Hide Bounded Context (Downstream) <-> (Upstream) (OHS) Identity Management Bounded Context
If you want to design your Bounded Contexts with more details check out Bounded Context Canvas.
Code Solution
The code solution you can find it here: https://github.com/eduluc12/ddd-example
I'd rather to use pnpm instead of npm/yarn but this's not obligatory for continuing with our solution.
pnpm install
The structure of our project will be:
StructureI'd like to start first with the configuration files, for this solution we're going to use swc as a compiler (ts -> js), webpack as a module bundler and serverless framework for our deployment (yes, with this we're going to upload our IaC).
Why did I use CQRS ?
CQRS (Command Query Responsibility Segregation) is a pattern that give us the chance to split our responsibilities in two ways:
Write side: Where the system will change a state, the write side is a mutable side.
Read side: Where the system will read several states but without modify it, the read side is a immutable side.
So I though that this mini-project can use it as a example, if you want to use this pattern you need to understand the benefits that could give you, I've found a couple of them:
Granularity about the infrastructure
We can manage different databases for each side
Good coupling if you're using Event Sourcing, such as: In our read side we can handle a projection and in our write side we can save events.
and in our project we've defined those sides:
Don't you know nothing about Clean Architecture ? I invite you to visit this post.
Have you noticed about the domain layer ? Inside of this folder we're going to have our aggregates, events, entities, services defined by our DDD analysis and where we must put the business logic.
In the application folder we can see: use-cases, handlers, commands, queries, ports.
The utility about Nestjs and why I'd like to use it in my projects are that give us the chance to segregate our solution through modules and inject dependencies easily and also it has a CQRS module for helping us throughout the solution.
Acknowledging Identity Management Subdomain
For the creation of our generic subdomain we're going to use Cognito User Pool a service of AWS that has a free tier and it's going to act as our generic subdomain (we're using a service that was created for an external provider).
Deploying
First of all, you need to have your AWS' tokens, you can get it in two ways:
Creating a user
Creating a role and assume that role
After got it, we can run the next command:
npm run deploy
Testing our solution
After we've deployed our solution, we're going to register an user and get its token.
aws cognito-idp admin-create-user \
--user-pool-id <userpool_id> \
--username <email>
aws cognito-idp admin-set-user-password \
--user-pool-id '<userpool_id>' \
--username <email> \
--password '<password>' \
--permanent
aws cognito-idp initiate-auth \
--auth-flow USER_PASSWORD_AUTH \
--client-id <client_id> \
--auth-parameters USERNAME=<email>,PASSWORD='<password>'
After you've gotten its token we can send it to our API through the Authorization header.
Creating a new hide URL
curl --location --request POST 'https://<base>/dev/hideurl/urls' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <access token>' \
--data-raw '{
"url": "http://example.com"
}'
Redirect to a hide URL
In your browser you can enter to this URL and you'll redirect to the original website:
https://<base>/dev/hideurl/urls/<id>
I hope this post was interesting for you and if you have a suggestion I'll be glad to read it, see you the next time !
Top comments (0)