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)