-
Couldn't load subscription status.
- Fork 22
Open
Labels
ConfigsRelated to overall configuration of zainoRelated to overall configuration of zainoarchitectureArchitectural improvementsArchitectural improvementstech-debtTechnical debt that needs to be addressedTechnical debt that needs to be addressed
Description
God Object - IndexerConfig mixes concerns across multiple domains
Labels: configs, tech-debt, architecture
Problem
IndexerConfig is a God Object that violates the Single Responsibility Principle by mixing configuration for entirely different subsystems in a single struct.
Current Problematic Code
pub struct IndexerConfig {
// Backend selection
pub backend: zaino_state::BackendType,
// JSON-RPC server settings
pub enable_json_server: bool,
pub json_rpc_listen_address: SocketAddr,
pub enable_cookie_auth: bool,
pub cookie_dir: Option<PathBuf>,
// gRPC server settings
pub grpc_listen_address: SocketAddr,
pub grpc_tls: bool,
pub tls_cert_path: Option<String>,
pub tls_key_path: Option<String>,
// Validator connection settings
pub validator_listen_address: SocketAddr,
pub validator_grpc_listen_address: SocketAddr,
pub validator_cookie_auth: bool,
pub validator_cookie_path: Option<String>,
pub validator_user: Option<String>,
pub validator_password: Option<String>,
// Cache settings
pub map_capacity: Option<usize>,
pub map_shard_amount: Option<usize>,
// Database settings
pub zaino_db_path: PathBuf,
pub zebra_db_path: PathBuf,
pub db_size: Option<usize>,
// Network and debug
pub network: String,
pub no_sync: bool,
pub no_db: bool,
pub slow_sync: bool,
}Impact
- Unclear Responsibilities: What is IndexerConfig actually responsible for?
- Change Amplification: Adding a new server option affects the "main" config
- Documentation Overload: Single struct needs to document 6+ different concepts
- Testing Complexity: Can't test server config without creating entire IndexerConfig
- Poor Cohesion: Fields that change together are scattered
- Hidden Dependencies: Which fields are used together isn't clear
Solution
Split into focused, domain-specific configuration objects:
// Top-level config just orchestrates
pub struct IndexerConfig {
pub network: Network,
pub backend: BackendConfig,
pub server: ServerConfig,
pub storage: StorageConfig,
pub debug: DebugConfig,
}
// Server owns its configuration
pub struct ServerConfig {
pub grpc: GrpcConfig,
pub json_rpc: Option<JsonRpcConfig>, // Optional server
}
pub struct GrpcConfig {
pub listen_address: SocketAddr,
pub tls: TlsConfig,
}
pub struct JsonRpcConfig {
pub listen_address: SocketAddr,
pub auth: JsonRpcAuth,
}
// Backend config variants encode valid combinations
pub enum BackendConfig {
LocalZebra {
rpc_address: SocketAddr,
grpc_address: SocketAddr,
auth: ZebradAuth,
state_config: ZebraStateConfig,
},
RemoteZcashd {
rpc_address: SocketAddr,
auth: ZcashdAuth,
},
// Each variant has exactly what it needs
}
// Storage is its own concern
pub struct StorageConfig {
pub cache: Option<CacheConfig>,
pub database: DatabaseConfig,
}Usage becomes clearer:
# TOML structure mirrors the code structure
network = "mainnet"
[backend]
type = "local_zebra"
rpc_address = "127.0.0.1:8232"
grpc_address = "127.0.0.1:9000"
auth = { cookie = { path = ".cookie" }}
[server.grpc]
listen_address = "0.0.0.0:8080"
tls = { enabled = { cert = "cert.pem", key = "key.pem" }}
[server.json_rpc]
listen_address = "0.0.0.0:8545"
auth = "disabled"
[storage.database]
path = "./zaino_db"
size = { gb = 10 }Benefits:
- Each struct has a single, clear responsibility
- Related fields are grouped together
- Can test/modify subsystems independently
- Documentation is focused and relevant
- Changes are localized to affected subsystem
- Configuration structure mirrors system architecture
Metadata
Metadata
Labels
ConfigsRelated to overall configuration of zainoRelated to overall configuration of zainoarchitectureArchitectural improvementsArchitectural improvementstech-debtTechnical debt that needs to be addressedTechnical debt that needs to be addressed
Type
Projects
Status
In progress