Naming Conventions
Unified naming and structure
The naming convention should make each child package understandable at a glance: what its core object is, how to use it standalone, how to connect it through Provider, and how to register drivers and instances.
Driver naming
Use the bare interface name:
type Driver interface { ... }
Driver factories are called Driver(...):
redis.Driver(client)
s3.Driver(options...)
The option used to select a driver is called Use(name) to avoid colliding with the Driver interface:
cache.RegisterPool("default", cache.Use("redis"))
storage.RegisterDisk("cloud", storage.Use("s3"))
Package file organization
Recommended structure:
cache/
registry.go # Registry + New
provider.go # Provider + ProviderOption
options.go # Option / DriverOption
types.go # Driver / Info / constants
default.go # Default()
memory.go # default driver
redis/ # external dependency driver, independent go.mod
Keep Provider shape consistent
Provider should return the provider.Provider interface and usually embed provider.Base:
func Provider(options ...ProviderOption) provider.Provider {
item := &providerImpl{}
return item
}
Lifecycle convention:
Initregisters DI default objects.Registerapplies config, registers commands, registers instances, and registers route services.Resolvehandles delayed mounts.Bootstarts logic that needs the full application registration to be complete.Shutdownreleases resources.
Default only reads the default instance from DI
func Default() *Registry {
return provider.MustInvokeDefault[*Registry]()
}
Default() can only be used after the application completes Freeze or Run. Use Provider options for startup-time configuration.
Avoid command name collisions
Commands use pkg:verb:
route:list
queue:work
database:ping
devtools:embed
Do not add new bare command names, otherwise packages may collide.