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

Service register best practices #78

Closed
iyaozhen opened this issue May 13, 2024 · 5 comments
Closed

Service register best practices #78

iyaozhen opened this issue May 13, 2024 · 5 comments
Labels
question Further information is requested

Comments

@iyaozhen
Copy link

I have been using do for a while. But I have a confused about service register

a typical service:

type Service struct {
	meegoMaterial *material.MeegoMaterial[material.MeegoMeta] `do:""`
	docMaterial   *material.DocMaterial[material.DocMeta]     `do:""`
	anyMaterial   *material.AnyMaterial[any]                  `do:""`
}

func NewService() (*Service, error) {
	return di.InvokeStruct[Service]()
}

And I add service.Register() function in main.go.

func Register() {
	di.Provide(material.NewMeegoMaterial)
	di.Provide(material.NewAnyMaterial)
	di.Provide(material.NewDocMaterial)

        di.Provide(report.NewService)
}

It works, But when I testing report:

func init() {
	service.Register()
}

func TestService_Report(t *testing.T) {

}

Circular dependencies error:

# ***/biz/service/report
package ***/biz/service/report
	imports ***/biz/service
	imports ***/biz/service/report: import cycle not allowed in test

I register service in test init func without report now.

func init() {
	di.Provide(material.NewMeegoMaterial)
	di.Provide(material.NewDocMaterial)
	di.Provide(objectstorage.NewService)
	di.Provide(material.NewAnyMaterial)
}

But I think it is ugly, Is there a better way? all in one service.Register() maybe no need to exist?

Of course, this is not do is problem, It should be my problem with using and understanding.

@samber
Copy link
Owner

samber commented May 13, 2024

Yes, declaring services globally might create import cycles sometimes.

In v2-beta6, we added support for "do.Package" -> https://do.samber.dev/docs/getting-started#register-services-using-package-declaration

You can create a do.Package in ***/biz/service/ for a subset of your app.

go get -u github.com/samber/do/v2@v2.0.0-beta.7

If you currently use v1, check the migration guide: https://do.samber.dev/docs/upgrading/from-v1-x-to-v2

I currently use v2 in my own project. You can consider it almost production-ready. Some APIs might change before release.

@iyaozhen
Copy link
Author

iyaozhen commented May 13, 2024

Thx, I try to do.Package.
I used v2 in production for some time, it is very good.

@iyaozhen
Copy link
Author

Hello samber, do.Package doesn't seem to solve my problem.

Maybe I didn't describe it in detail enough. I create a demo: https://github.com/iyaozhen/samber-do-learn/blob/main/service/car/car_test.go

image

import cycle:

package github.com/iyaozhen/samber-do-learn/service/car
	imports github.com/iyaozhen/samber-do-learn/service
	imports github.com/iyaozhen/samber-do-learn/service/car: import cycle not allowed in test

TestCar_Start_V2 It is work, but I will add lots of do.Provide.

service/register.go, Should it not exist?

I should use do.Package in car? But engine used in a other car2 service, car and car2 Lazy/Provide Duplicate?

@samber
Copy link
Owner

samber commented May 16, 2024

Ok, i see your issue.

Maybe you could move your tests to a dedicated package? 🤔

I don't know the complexity of your app, but you can also have a do.Package in 2 sub-packages (here: service/engine/ and service/car/) and import them in tests: do.New(engine.Pkg, car.Pkg).

I don't know if this issue is related to DI, since you would have the same problem in traditional programming.

Did you try with interfaces? Using do.InvokeAs might prevent some troubles.

@samber samber added the question Further information is requested label May 16, 2024
@iyaozhen
Copy link
Author

Thank you for your patient answer. There's no particular solution for me.

move your tests to a dedicated package

not golang customary norm

2 sub-packages

car.Package

do.Package(
	do.Lazy(engine.NewEngine),
	do.Lazy(NewCar),
)

airplane.Package

do.Package(
	do.Lazy(engine.NewEngine),
	do.Lazy(NewAirplane),
)

https://github.com/iyaozhen/samber-do-learn/blob/main/service/car/car_test.go

panic: DI: service `*/service/engine.Engine` has already been declared

interface

interface is a good way. But it will make the project more complex. In general, there is only one implementation of an interface.

This is not do is problem, the same problem in traditional programming.

I'll close this issue first, If there is a good solution, I will come back to update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants