go-micro.dev/v5@v5.12.0/internal/website/docs/architecture/adr-009-progressive-configuration.md (about) 1 --- 2 layout: default 3 --- 4 5 # ADR-009: Progressive Configuration 6 7 ## Status 8 **Accepted** 9 10 ## Context 11 12 Microservices frameworks face a paradox: 13 - Beginners want "Hello World" to work immediately 14 - Production needs sophisticated configuration 15 16 Too simple: Framework is toy, not production-ready 17 Too complex: High barrier to entry, discourages adoption 18 19 ## Decision 20 21 Implement **progressive configuration** where: 22 23 1. **Zero config** works for development 24 2. **Environment variables** provide simple overrides 25 3. **Code-based options** enable fine-grained control 26 4. **Defaults are production-aware** but not production-ready 27 28 ## Levels of Configuration 29 30 ### Level 1: Zero Config (Development) 31 ```go 32 svc := micro.NewService(micro.Name("hello")) 33 svc.Run() 34 ``` 35 36 Uses defaults: 37 - mDNS registry (local) 38 - HTTP transport 39 - Random available port 40 - Memory broker/store 41 42 ### Level 2: Environment Variables (Staging) 43 ```bash 44 MICRO_REGISTRY=consul \ 45 MICRO_REGISTRY_ADDRESS=consul:8500 \ 46 MICRO_BROKER=nats \ 47 MICRO_BROKER_ADDRESS=nats://nats:4222 \ 48 ./service 49 ``` 50 51 No code changes, works with CLI flags. 52 53 ### Level 3: Code Options (Production) 54 ```go 55 reg := consul.NewConsulRegistry( 56 registry.Addrs("consul1:8500", "consul2:8500"), 57 registry.TLSConfig(tlsConf), 58 ) 59 60 b := nats.NewNatsBroker( 61 broker.Addrs("nats://nats1:4222", "nats://nats2:4222"), 62 nats.DrainConnection(), 63 ) 64 65 svc := micro.NewService( 66 micro.Name("myservice"), 67 micro.Version("1.2.3"), 68 micro.Registry(reg), 69 micro.Broker(b), 70 micro.Address(":8080"), 71 ) 72 ``` 73 74 Full control over initialization and configuration. 75 76 ### Level 4: External Config (Enterprise) 77 ```go 78 cfg := config.NewConfig( 79 config.Source(file.NewSource("config.yaml")), 80 config.Source(env.NewSource()), 81 config.Source(vault.NewSource()), 82 ) 83 84 // Use cfg to initialize plugins with complex configs 85 ``` 86 87 ## Environment Variable Patterns 88 89 Standard vars for all plugins: 90 ```bash 91 MICRO_REGISTRY=<type> # consul, etcd, nats, mdns 92 MICRO_REGISTRY_ADDRESS=<addrs> # Comma-separated 93 MICRO_BROKER=<type> 94 MICRO_BROKER_ADDRESS=<addrs> 95 MICRO_TRANSPORT=<type> 96 MICRO_TRANSPORT_ADDRESS=<addrs> 97 MICRO_STORE=<type> 98 MICRO_STORE_ADDRESS=<addrs> 99 MICRO_STORE_DATABASE=<name> 100 MICRO_STORE_TABLE=<name> 101 ``` 102 103 Plugin-specific vars: 104 ```bash 105 ETCD_USERNAME=user 106 ETCD_PASSWORD=pass 107 CONSUL_TOKEN=secret 108 ``` 109 110 ## Consequences 111 112 ### Positive 113 114 - **Fast start**: Beginners productive immediately 115 - **Easy deployment**: Env vars for different environments 116 - **Power when needed**: Full programmatic control available 117 - **Learn incrementally**: Complexity introduced as required 118 119 ### Negative 120 121 - **Three config sources**: Environment, code, and CLI flags can conflict 122 - **Documentation**: Must explain all levels clearly 123 - **Testing**: Need to test all configuration methods 124 125 ### Mitigations 126 127 - Clear precedence: Code options > Environment > Defaults 128 - Comprehensive examples for each level 129 - Validation and helpful error messages 130 131 ## Validation Example 132 133 ```go 134 func (s *service) Init() error { 135 if s.opts.Name == "" { 136 return errors.New("service name required") 137 } 138 139 // Warn about development defaults in production 140 if isProduction() && usingDefaults() { 141 log.Warn("Using development defaults in production") 142 } 143 144 return nil 145 } 146 ``` 147 148 ## Related 149 150 - [ADR-004: mDNS as Default Registry](adr-004-mdns-default-registry.md) 151 - ADR-008: Environment Variable Support (planned) 152 - [Getting Started Guide](../getting-started.md) - Configuration examples 153 - [Configuration Guide](../config.md)