internal/website/docs/architecture/adr-009-progressive-configuration.md
Accepted
Microservices frameworks face a paradox:
Too simple: Framework is toy, not production-ready Too complex: High barrier to entry, discourages adoption
Implement progressive configuration where:
svc := micro.NewService(micro.Name("hello"))
svc.Run()
Uses defaults:
MICRO_REGISTRY=consul \
MICRO_REGISTRY_ADDRESS=consul:8500 \
MICRO_BROKER=nats \
MICRO_BROKER_ADDRESS=nats://nats:4222 \
./service
No code changes, works with CLI flags.
reg := consul.NewConsulRegistry(
registry.Addrs("consul1:8500", "consul2:8500"),
registry.TLSConfig(tlsConf),
)
b := nats.NewNatsBroker(
broker.Addrs("nats://nats1:4222", "nats://nats2:4222"),
nats.DrainConnection(),
)
svc := micro.NewService(
micro.Name("myservice"),
micro.Version("1.2.3"),
micro.Registry(reg),
micro.Broker(b),
micro.Address(":8080"),
)
Full control over initialization and configuration.
cfg := config.NewConfig(
config.Source(file.NewSource("config.yaml")),
config.Source(env.NewSource()),
config.Source(vault.NewSource()),
)
// Use cfg to initialize plugins with complex configs
Standard vars for all plugins:
MICRO_REGISTRY=<type> # consul, etcd, nats, mdns
MICRO_REGISTRY_ADDRESS=<addrs> # Comma-separated
MICRO_BROKER=<type>
MICRO_BROKER_ADDRESS=<addrs>
MICRO_TRANSPORT=<type>
MICRO_TRANSPORT_ADDRESS=<addrs>
MICRO_STORE=<type>
MICRO_STORE_ADDRESS=<addrs>
MICRO_STORE_DATABASE=<name>
MICRO_STORE_TABLE=<name>
Plugin-specific vars:
ETCD_USERNAME=user
ETCD_PASSWORD=pass
CONSUL_TOKEN=secret
func (s *service) Init() error {
if s.opts.Name == "" {
return errors.New("service name required")
}
// Warn about development defaults in production
if isProduction() && usingDefaults() {
log.Warn("Using development defaults in production")
}
return nil
}