Date: 2025-02-25
Status
Accepted
Context
Our ebook conversion system needs to operate in different environments (development, test, production) with environment-specific settings. Currently, our configuration system uses a single configuration file, which leads to several issues:
- Development vs. Production Settings: Different environments require different settings (e.g., paths, timeouts, log levels)
- Testing Challenges: Tests need isolated configuration to avoid affecting development settings
- Deployment Complexity: Deployment requires manual configuration changes
- Security Concerns: Sensitive production settings shouldn't be in development configuration
- Hardcoded Values: Many environment-specific values are hardcoded rather than configured
Our existing configuration system loads from a single YAML file and performs basic validation, but doesn't account for different environments.
Decision
We will implement an environment-specific configuration system with the following components:
-
Environment Detection:
- Create a
BookProcessing::Environmentclass to detect and manage the current environment - Support explicit environment setting via the
BOOK_ENVenvironment variable - Define standard environments: development, test, and production
- Provide environment checking methods (
development?,test?,production?)
- Create a
-
Layered Configuration:
- Base configuration file (
config/base.yml) for shared settings - Environment-specific configuration files (
config/{environment}.yml) - Environment variable overrides for runtime configuration
- Base configuration file (
-
Configuration Loading Strategy:
- Load base configuration first
- Overlay environment-specific configuration
- Apply environment variable overrides
- Use deep merging for nested configuration
-
Environment-Specific Validation:
- Apply different validation rules based on the environment
- Stricter validation for production
- More permissive validation for development
- Special handling for test environment
-
Default Values:
- Provide sensible defaults for each environment
- Document required vs. optional configuration
Implementation
The implementation includes:
- A new
BookProcessing::Environmentclass for environment detection and management - Enhanced
BookProcessing::Configurationclass with environment-specific loading - Environment-specific configuration files for development, test, and production
- Environment variable override support for runtime configuration
- Environment-specific validation rules
Consequences
Positive
- Environment Isolation: Each environment has its own configuration
- Simplified Deployment: No need to manually change configuration during deployment
- Enhanced Testing: Tests can run with isolated configuration
- Improved Security: Sensitive settings can be kept separate
- Runtime Flexibility: Environment variables allow runtime configuration
- Reduced Hardcoding: More values can be moved to configuration
- Clearer Defaults: Each environment has appropriate defaults
Negative
- Increased Complexity: Multiple configuration files to maintain
- Potential Duplication: Some settings may be duplicated across environments
- Configuration Drift: Environments may become inconsistent over time
- Learning Curve: Developers need to understand the layered configuration system
Mitigation Strategies
- Documentation: Clear documentation of the configuration system
- Configuration Templates: Provide templates for each environment
- Validation Tools: Create tools to validate configuration across environments
- Configuration Review: Regular review of configuration files for consistency
- Default Fallbacks: Ensure sensible defaults when configuration is missing
References
- The Twelve-Factor App: III. Config
- Ruby on Rails environment configuration approach
- Elixir's configuration system (for future migration reference)