loading...

Using Domain-Driven Design(DDD)in Golang

Steven Victor on February 22, 2020

Domain-Driven Design pattern is the talk of the town today. Domain-Driven Design(DDD) is an approach to software development that simplifies the c... [Read Full]
markdown guide
 

Hi Steven, thank you for the article, there is not much DDD articles so this is good thing.

However, I have some observations regarding implementation details.

1) You start by "DDD comprises of 4 Layers" Domain, Infrastructure, Application, Interfaces then ... You put Infrastructure inside Domain ! Infrastructure package should be on the same level as Domain, Application and Interfaces. That is because Infrastructure layer brings support to all 3 others layers, not only domain. You can define go service interface inside your application package then have its implementation inside infrastructure because the implementation brings some weird dependencies.

2) packages "utils" :S in DDD you should not have an "utils" package. Everything have a place.
Auth and Security are infrastructure stuff

Middleware and FileUpload are Interfaces stuff

3) You talk about Entities but not about Agregates, you separate Repositories from Entities, their should be colocated in the same package , the "agregate" which name should be the aggregate name. Modularity is a big principle of DDD. Interchangeable component losely coupled with big cohesion.

4) In food_app.go in the application layer, there is a Service Interface , good. But there is no Factory for it, the struct implementation is just public to everyone "type FoodApp struct{...}" , it should be private and be called something like "type foodService struct {}" Factories are important because they help construct the object (inject services if needed, instrument it, etc )

5) The factory of your repository should
a) be inside the infrastructure package
func NewUserRepository(db *gorm.DB) repository.UserRepository
b) it takes an infrastructure object gorm.DB that the caller should not handle

6) You could use the DomainRegistry pattern to handle the restitution of the different factories (service, repo, aggregates). DomainRegistry interface in domain root then the DomainRegistry implementation in the infrastructure

In fact, there are other concerns but I think you get the point. Tactical patterns of DDD are direction to follow this is not strict if we respect certain rules.

Don't get me wrong this is just a fair critics. Because every one is learning, me the first. But from what I see the article can confuse first time DDD players because you break some principles.

If you want I can fork you repository and propose something we can discuss on.

 

Great. Thanks, a lot Epo for the feedback.

For the first point, The Infrastructure Layer is actually on the same level as the Domain. This was not the case in the first push. It had long been corrected. Please check.

For the second point, I'm currently refactoring to have the Auth in the infrastructure(have been a bit busy at work), I will probably update before the week runs out.

For the third point, I will refactor to that. Thanks.

For the fourth point, that was an oversight. The change has been effected now.

For the fifth point, I didn't quite get you. But this no longer applies in the implementation above.
func NewUserRepository(db *gorm.DB) repository.UserRepository
The article is currently in a constant state of editing as constructive feedback such as yours are given. If you don't mind, can you elaborate on your fifth point?

Please go ahead and fork the repository, your changes are welcome.

Thanks again for the feedback.

 

Hi Steven, thank you for the article, I have a question!

Why do you pass a repository as param when init interface?
Such as services.Food is passed as params of interfaces.NewFood initialization.
foods := interfaces.NewFood(services.Food, services.User, fd, redisService.Auth, tk)

I think that pass a application is better choice! How do you think about it?

 

Hello Victor. First of all I wanted to thank you because your project have been very helpful as an example for implementing a project of my own. I have a question for you about the code tho. Why in the api in the refresh token method you just erase the refresh token and not the previous generated access token in the redis db. It seems like it will always remain an orphan access token in the redis database if you do this I think. Is there any reason for you to do that?. Thanks again.

 

Hi Jose,

For we to ever use the Refresh Token, it means the Access Token must have expired(and Redis deletes it automatically).

 

Hi Steven. Thanks for the answer. That makes sense. I will check it out it might be something on my implementation. The other thing is I don't see in the code in the frontend where you are encripting the password with the Bcrypt. Is that missing? or am I just don't seeing it?.

Thank you.

Hi,
The password is encrypted on the backend.
Go to this path: infrastructure/security/password.go
The function that hashes the password is defined there.

 

Why did you choose to return interfaces e.g. in your repository creation functions? Isn't that against recommended Go best practices?

 

Hi Martin. Thanks for the feedback.
In order to answer your question properly, can you include a code snippet to a comment where you observed this?

Thanks.

 
Sloan, the sloth mascot Comment marked as low quality/non-constructive by the community View code of conduct

Bad guide, I'm not sure author understands DDD

 

Hi Dennis, thanks for the feedback. Please can you point areas you were not okay with(the bad stuff), as regards this implementation? Supporting links will also be helpful.

Though the author is not yet a DDD expert, he did some research before writing this.

These are some of the author's references:

engineering.grab.com/domain-driven...

newtonmeters.com/blog/domain-drive...

github.com/marcusolsson/goddd

github.com/takashabe/go-ddd-sample

If these references are also a bad guide, the author will appreciate it if he is pointed to a good guide, how DDD is implemented.

Thanks as I anticipate your response.

 

This article makes a huge disservice to DDD.

The article focuses on project structure and layers like it is some stiff guideline for DDD whereas it is not.

DDD is about describing the domain in the code. Then building upon this domain code to create some useful use cases (also dropping in some infrastructural code for persistence, messaging and stuff like that). DDD is about direction of dependencies and direction of control in those mentioned "layers". About loosely coupled layers. It is about how your application can grow around the domain.
In application that follows DDD principles, I should be able to tell what is the application about just looking at the packages.. In application from the article I just know that this is another weekend application.

Great! Thanks Kskitek for the feedback. I'm no way close to perfection. I wrote about this based on how I implemented DDD for a small application I built(which the link is shared in the article).

To help me better understand, do you have any material, link, video, article, github repo, anything at all, that explained how DDD is implemented the "ideal" way in Golang? I and the rest of the people reading this article will greatly benefit.

Thanks as I anticipate your response.

Hey Steven,

I have to agree ksiktek here. I have a feeling you were a bit too quick with diving into the implementation. Although in the end the implementation is what it all comes down to, that is not the essence of DDD. Instead DDD is - as you mentioned, but not deepened further - about creating a design in such a way that it is

  • understandable for you as a software engineer (and your collegues)
  • understandable for your customers (that's something most other approaches don't)
  • brings the problem domain (your customer's world) and the solution domain (your world of code) together in one solution

In doing so, it removes some of the steps that 'traditional' software development took: first create a functional or conceptual design, then translate that into technical design and finally translate that into code. In each translation, information got filtered or lost, resulting in all the bugs and mismatches that we see nowadays between software as it was built and software as it was intended.

I've been teaching DDD courses for over 7 years now, and I will be posting short digestable articles about it over the coming months (transferring my training material to either Medium or Dev.to for those who can't attend - or want to revisit the material after the training). Feel free to dive in. If you drop me a message here or on twitter (@delphinocons ) I'll send you an invite for the newsletter that I'm launching related to these same articles. And of course, feel free to ask if you have specific questions. :-)

Hi Angelo,

Thanks for your comment. I will really be looking forward to your posts as it will help me better understand DDD better.

I kindly request that you also share the link here when it is ready.

Thanks.

Hello Steven, you're welcome. The articles will be posted on Medium and here on Dev.to, so I'm sure you'll catch them. I also have a newsletter, which is released in lock step with the articles. If you subscribe to that you will get automatic notifications of new articles: eepurl.com/g1oOaD

code of conduct - report abuse