Closed eminetto closed 4 years ago
@cjslep @aschrijver @hurrycaner can you take a look in this new structure?
Again with the same (un)healthy dose :wink: of lacking Go knowledge as before I have the following observations:
Some of the same considerations I mentioned in #3 still apply:
book
, user
, loan
are part of it. If they are separate contexts they should not be interspersed throughout the project structure like this, imho.repository_mysql.go
- the choice for MySQL - is a techstack decision that has nothing to do with your domain. It should not exist in the domain
folder. A layered / hexagonal architecture places this in the Infrastructur layer. The repository interface could be part of the domain, though. These kinds of folder structures we are talking about are most appropriate for large-scale projects (as @cjslep also mentioned in #3) . Imagine what could happen when the project grows:
repository_mysql.go
but has a sprawl of related files, that are further polluting the domain
folder. It becomes harder to maintain "inversion of control" (i.e. your domain has zero dependencies to application
and infrastructure
layers).usecase
folder structure is undescriptive. The current design would only work for CRUD of the entity. With a more full-blown DDD - where CRUD can be an anti-pattern that leads to an anemic domain model - I'd have to open each service.go
file to find what use cases are actually in there.I'll add more observations to #3 as well. Despite what @cjslep mentioned my proposed folder structure still looks the cleanest, and - although it may require a bit more discipline - looks still do-able in Go.
Again with the same (un)healthy dose 😉 of lacking Go knowledge as before I have the following observations:
Some of the same considerations I mentioned in #3 still apply:
- To me the clean architecture structure here implies there's one bounded context where
book
,user
,loan
are part of it. If they are separate contexts they should not be interspersed throughout the project structure like this, imho.
I agree with that. What i'm trying to do is make this example as simple as possible. So, i'm assuming that this is a single domain.
- Your
repository_mysql.go
- the choice for MySQL - is a techstack decision that has nothing to do with your domain. It should not exist in thedomain
folder. A layered / hexagonal architecture places this in the Infrastructur layer. The repository interface could be part of the domain, though.
Thanks! I made a new commit to change this. Can you review again?
These kinds of folder structures we are talking about are most appropriate for large-scale projects (as @cjslep also mentioned in #3) . Imagine what could happen when the project grows:
- The MySQL code may no longer fit
repository_mysql.go
but has a sprawl of related files, that are further polluting thedomain
folder. It becomes harder to maintain "inversion of control" (i.e. your domain has zero dependencies toapplication
andinfrastructure
layers).- Your
usecase
folder structure is undescriptive. The current design would only work for CRUD of the entity. With a more full-blown DDD - where CRUD can be an anti-pattern that leads to an anemic domain model - I'd have to open eachservice.go
file to find what use cases are actually in there.I will try to make my domain to not be anemic. Let me think in an improvement to this example... Thanks for pointing that.
I'll add more observations to #3 as well. Despite what @cjslep mentioned my proposed folder structure still looks the cleanest, and - although it may require a bit more discipline - looks still do-able in Go.
I think having the fixtures in the same location as the domain entities makes sense. If there are a lot of them they could be in a subdir.
Note that in a non-anemic domain model the entity definitions (e.g. book
aggregate root) would contain domain-specific business logic. There's many ways to slice this, but this could be related to business rules, validation (e.g. determining the strength of a password
value object), or applying / triggering domain events + errors. This means that in the domain
folder you would also find tests.
In the infrastructure ➜ application ➜ domain
layered design, the usecase
folder is typically in Application layer and not under domain
. The use cases retrieve domain entities (via the repositories) and invoke domain logic on them. They contain the glue code that puts stuff together. There may be many use cases that are not directly domain-related (not part of the ubiquitous language). Just a consideration.. you may have a different preference.
The api
would be in infra/api
. In the hexagonal architecture it is one of the endpoints to the outside world, just as the db interface.
My biggest issue with the current setup is that usecase
folder is not showing me use cases. It is not self-describing to that extent. It has subfolders that contain a service that seems to be 1-to-1 connected to a domain entity. But it is not.
//Service loan usecase
type Service struct {
userService user.UseCase
bookService book.UseCase
}
If a use case has a 1-to-1 match to a feature that was agreed upon with the customer, and hence - based on domain design - is described in a snippet of text formulated in the ubiquitous language (and note that a use case is not necessarily part of the domain itself. It uses the domain), then having a separate folder that clearly shows me its about that feature, and where I also find the BDD tests that are pre-loaded with the plaintext use case description, would be much cleaner architecture imho.
In your design I would move domain/usecase
to application
i.e. this is the application layer.
Plus a Service != a Use Case. A service is the entry point to multiple use cases. And that is also how it is implemented here.
With this - even though I don't know how my OOP concepts translate exactly to Go - I am still very much in favor of a folder structure that looks like my other proposal: https://github.com/eminetto/clean-architecture-go-v2/issues/3#issue-680180916
New structure