Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feedbacks #1

Closed
resotto opened this issue Sep 21, 2020 · 21 comments
Closed

Feedbacks #1

resotto opened this issue Sep 21, 2020 · 21 comments
Labels
good first issue Good for newcomers

Comments

@resotto
Copy link
Owner

resotto commented Sep 21, 2020

Feel free to write your thoughts.

@jzvelc
Copy link

jzvelc commented Sep 24, 2020

I think the main problem of implementing DDD in Go is the lack of data mapper ORM which provides entity change tracking. If you manage to provide guidance on how to implement repository save method and how to update aggregate child entities this could become big.

@resotto
Copy link
Owner Author

resotto commented Sep 24, 2020

@jzvelc Thank you for your comment! I'll try it!

@ferdypruis
Copy link

Before looking into ORM's, please read this blog by "Uncle Bob"; https://blog.cleancoder.com/uncle-bob/2013/10/01/Dance-You-Imps.html

@resotto
Copy link
Owner Author

resotto commented Sep 24, 2020

@ferdypruis Thank you! I'll read it first.

@resotto
Copy link
Owner Author

resotto commented Sep 25, 2020

OK, I read it. I perfectly agree with:

But please don’t think of those data structures as your business objects. What’s more, please design your business objects without consideration for the relational schema. Design your applications to behave first. Then figure out a way to bind those behaviors to the data brought into memory by your ORM.

This is also the same as the Domain-Driven Design way, so I'm completely convinced.

And then, I'm thinking about the solution of

the lack of data mapper ORM which provides entity change tracking. If you manage to provide guidance on how to implement repository save method and how to update aggregate child entities

@resotto
Copy link
Owner Author

resotto commented Sep 26, 2020

@jzvelc I investigated GORM doc, and found this:
https://gorm.io/docs/update.html#Check-Field-has-changed

Could you solve the problem with this?

@resotto
Copy link
Owner Author

resotto commented Sep 26, 2020

Ah, You mean I should include this gorm function sample into goilerplate??

@jzvelc
Copy link

jzvelc commented Sep 26, 2020

Provide an aggregate which holds a collection of children entities and show how to update child entity. There are two types of repositories. Collection based and persistance based. With data mapper orm where you have auto change tracking you normally use collection based repository. Any changes made to child entity are automatically peristed when unit of work is comitted and no persistance logic leaks in application/domain layer. With active record persistance based repository is more suitable. However I didn't find any examples how to properly work with child entities. You only have a repository per aggregate and changes to child entities are made through the aggregate root. One possible solution I thought about would be to raise domain event for every state change and repository could react on that.

@resotto
Copy link
Owner Author

resotto commented Sep 26, 2020

The way to have a repository per aggregate where changes to child entities are made through the aggregate root is the Domain-Driven Design one.

So, I'll implement it via this way.

Thank you for your detailed explanation.

@akoufa
Copy link

akoufa commented Sep 27, 2020

Hello. Did you consider using any Dependency Injection (DI) tool instead of doing manual DI ?

@resotto
Copy link
Owner Author

resotto commented Sep 28, 2020

@akoufa Thank you for your comment.
Yes, I thought about the DI tool Wire.
But I thought the costs of introducing it might be eventually equal to those of manual DI so I chose manual DI.

@akoufa
Copy link

akoufa commented Sep 30, 2020

@resotto For this sample project yes but if the project grows bigger the cost of introducing it is constant and the manual DI cost will grow and supersede the initial cost of Wire

@resotto
Copy link
Owner Author

resotto commented Sep 30, 2020

@akoufa I think it is trading off in the end.

When injecting dependency manually,

  • initialize implementation(struct)
  • give it to usecase as arguments in order

When injecting dependency with tool,

  • write settings for it (constant)
  • write something like anotation to the side that does and the other side that is injected (not constant)

However, it depends on which one you find easier.
So I'll implement example with wire. Thank you.

@resotto
Copy link
Owner Author

resotto commented Sep 30, 2020

Now, I'm working on implementing get/save of a little bit complicated entity's repository.

@resotto
Copy link
Owner Author

resotto commented Oct 2, 2020

@jzvelc I implemented child entity update:
https://github.com/resotto/goilerplate/blob/master/cmd/app/adapter/repository/order.go

I think we can know in advance which properties of child entity will change, so we don't have to do everything in one save/update method.

@resotto
Copy link
Owner Author

resotto commented Oct 3, 2020

@akoufa I considered Wire but I felt its cost is not low.

Moreover, Goilerplate might depend on it since DI tool such as Wire is some kinds of Application Framework, I think.

So I tried to reduce the cons side of Manual DI and this is the result of it:

https://github.com/resotto/goilerplate#dependency-injection

@akoufa
Copy link

akoufa commented Oct 3, 2020

@resotto I think I have an improvement suggestion regarding the manual DI example of yours. For example instead of creating the dependency graph every time a new request is being handled you could extract the DI code to the startup of the Service. You could find a good example of how this is done https://github.com/eldimious/golang-api-showcase/blob/master/server.go . Here the Dependency Graph is build up in the server.go file which acts as an entry file which coordinates the setup of the service. Maybe something similar would work for Goilerplate ?

@resotto
Copy link
Owner Author

resotto commented Oct 3, 2020

@akoufa Thank you! I'll check it!

@resotto
Copy link
Owner Author

resotto commented Oct 4, 2020

Aha, in manual DI, the number of implementation initialization will be expensive.

So, I'll try to reduce it by using global variable.

@akoufa This codes you gave me was helpful. Thank you.
This is the result of improvement: https://github.com/resotto/goilerplate#global-injecter-variable

@resotto
Copy link
Owner Author

resotto commented Oct 4, 2020

Now, we might fail pulling goilerplate-pg:latest image from GitHub Container Registry.

I'm investigating.

Workaround

Let's build docker image from Dockerfile and run it.

docker build -t goilerplate-pg:latest .
docker run -d -it --name pg -p 5432:5432 -e POSTGRES_PASSWORD=postgres goilerplate-pg:latest

@resotto resotto added the good first issue Good for newcomers label Oct 4, 2020
@resotto
Copy link
Owner Author

resotto commented Dec 8, 2020

please go to discussion

@resotto resotto closed this as completed Dec 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

4 participants