bxcodec / go-clean-arch

Go (Golang) Clean Architecture based on Reading Uncle Bob's Clean Architecture
MIT License
9.04k stars 1.19k forks source link

How to manage dependency will be more elegant? #35

Open bluntdel opened 4 years ago

bluntdel commented 4 years ago

I see these codes in the main.go.

authorRepo := _authorRepo.NewMysqlAuthorRepository(dbConn) ar := _articleRepo.NewMysqlArticleRepository(dbConn) timeoutContext := time.Duration(viper.GetInt("context.timeout")) * time.Second au := _articleUcase.NewArticleUsecase(ar, authorRepo, timeoutContext) _articleHttpDeliver.NewArticleHttpHandler(e, au)

I think if articleUcase need articleRepo,articleAuthorRepo and more other repository... Dependency management will be terrible, it will produce many codes like "newAriticleUseaCase(ARepo,BRepo,CRepo...)".So if it can be more elegant? I don't think write in the main.go is a good idea.

frederikhors commented 4 years ago

@bluntdel and @bxcodec what do you think about https://github.com/google/wire guys?

bxcodec commented 4 years ago

Wow, good question, personally I haven't do any elegant way.

Because for me personally, I'd rather see an explicit one rather than implicit, like in Java world with a lot of decorator things, that really consumes a lot of my mind budget to understand how is it worked.

Also in this explicit way, I can do knowledge transfer to junior engineers easily without the need to know how dependency injection tools work.

@frederikhors , I'll look into it, and try to understand it. If it's not making things more complicated, then it's a good to try.

PhantomX7 commented 4 years ago

@bluntdel surely it is a problem if we create a monolith using this this design pattern. It will create a long dependency injection call func New(aRepo a.repository, bRepo b.repository ...) AUsecase { ... } i have found a great library called fx to reduce the code boilerplate of the dependency injection. @frederikhors the difference between wire and fx is that wire is a code generator and fx is runtime auto inject dependency.

myugen commented 3 years ago

Maybe, it could be possible manage those dependencies through a context, for example, creating an ArticleContext interface such that

type ArticleContext interface {
    GetARepo() ARepo
    GetBRepo() BRepo
    GetCRepo() CRepo
    ....
    GetZRepo() ZRepo
}

Then, you just need to call inside usecase the respective repository:

func (a *articleUsecase) Fetch(c MyArticleContext, cursor string, num int64) (res []domain.Article, nextCursor string, err error) {
    ....
    aRepo := c.GetARepo()
    ....
}
mcauto commented 2 years ago

@bxcodec I made a sample project with dependency injection framework uber-go/fx. Could you feedback to me?

https://github.com/mcauto/todolist-api

HubQin commented 1 year ago

I wonder that is this way testable? and where to place ArticleContext.

mcauto commented 1 year ago

이런 식으로 테스트 가능한지 궁금합니다. 그리고 ArticleContext를 배치할 위치.

How about this?

https://github.com/mcauto/todolist-api/blob/main/modules/domains/todo/service_test.go#L38