autotoc_md325
doc_id: "LOG-ARCH-005" doc_title: "Conditional Compilation Refactoring Strategy" doc_version: "1.0.0" doc_date: "2026-04-04" doc_status: "Released" project: "logger_system"
category: "ARCH"
Conditional Compilation Refactoring Strategy
SSOT: This document is the single source of truth for Conditional Compilation Refactoring Strategy.
Version: 0.1.0.0 Last Updated: 2025-11-08 Status: Planning Document Priority: P1 (High)
Problem Statement
The logger_system currently uses extensive conditional compilation (#ifdef) to support multiple integration modes:
- Standalone Mode: Independent operation without ecosystem dependencies
- Thread System Integration: Implements
thread_system::logger_interface
- Common System Integration: Uses
common_system Result<T> and interfaces
Current State
Total conditional directives: 102
USE_THREAD_SYSTEM usage: 44 instances
BUILD_WITH_COMMON_SYSTEM usage: 18 instances
Issues
- Build Complexity: 2^N possible build configurations (N=2 → 4 combinations)
- Testing Burden: Each combination requires separate CI/CD pipeline
- Maintenance Cost: Changes must be validated across all modes
- Code Readability: Control flow obscured by preprocessor directives
- Technical Debt: Increasing over time as new integrations added
Example of Current Pattern
#include <kcenon/common/interfaces/logger_interface.h>
#include <kcenon/common/interfaces/monitoring_interface.h>
class logger :
public common::interfaces::ILogger,
public common::interfaces::IMonitorable
{
};
Proposed Solution: Adapter Pattern
Replace compile-time branching with runtime polymorphism using the Adapter Pattern.
Architecture
┌─────────────────────────────────────────────────────────────┐
│ logger_core │
│ (Pure implementation, no #ifdef) │
└─────────────────────┬───────────────────────────────────────┘
│
┌───────────┴──────────┬──────────────────┐
│ │ │
┌───────▼──────────┐ ┌────────▼────────┐ ┌─────▼──────────┐
│ standalone_ │ │ thread_system_ │ │ common_system_ │
│ adapter │ │ adapter │ │ adapter │
└──────────────────┘ └─────────────────┘ └────────────────┘
│ │ │
┌───────▼──────────┐ ┌────────▼────────┐ ┌─────▼──────────┐
│ Direct usage │ │ thread_system:: │ │ common:: │
│ │ │ logger_interface│ │ IMonitorable │
└──────────────────┘ └─────────────────┘ └────────────────┘
Benefits
✅ Single Build Configuration: One binary works for all modes ✅ Runtime Selection: Choose integration mode at runtime ✅ Easier Testing: Test all modes with single test suite ✅ Better Readability: Clear, linear code flow ✅ Maintainability: Changes affect single code path ✅ Extensibility: Add new integrations without recompiling
Trade-offs
❌ Virtual Function Overhead: ~1-2ns per call (negligible for logging) ❌ Binary Size: Larger binary includes all adapters (~10-20KB) ❌ Complexity Shift: From compile-time to runtime configuration
Implementation Plan
Phase 3.1: Analysis and Documentation ✅
- Count conditional directives
- Identify integration patterns
- Propose refactoring strategy
Phase 3.2: Core Interface Design
- Design factory pattern for adapter selection
- Create configuration system for runtime mode selection
Phase 3.3: Adapter Implementation
- Add unit tests for each adapter
Phase 3.4: Migration
- Remove conditional compilation from public headers
- Update CMakeLists.txt to simplify build
- Update documentation and examples
Phase 3.5: Validation
- Benchmark performance impact
- Verify all integration modes work
- Update CI/CD to single configuration
Detailed Design
Core Logger Interface
public:
explicit logger_core(
bool async =
true,
size_t buffer_size = 8192);
void log(log_level level, const std::string& message);
void log(log_level level, const std::string& message,
const std::string& file, int line, const std::string& function);
void flush();
void start();
void stop();
void set_min_level(log_level level);
log_level get_min_level() const;
void add_writer(std::unique_ptr<base_writer> writer);
void clear_writers();
void enable_metrics_collection(bool enable = true);
logger_performance_stats get_current_metrics() const;
private:
class impl;
std::unique_ptr<impl> pimpl_;
};
}
Adapter Interface
public:
: core_(std::move(core)) {}
void log(log_level level, const std::string& message) {
core_->
log(level, message);
}
void flush() { core_->flush(); }
void start() { core_->start(); }
void stop() { core_->stop(); }
protected:
std::shared_ptr<logger_core> core_;
};
}
void log(const std::string &message)
Thread System Adapter
#include <kcenon/thread/interfaces/logger_interface.h>
#include "logger_core.h"
, public thread_system::logger_interface {
public:
void log(thread_system::log_level level, const std::string& message) override {
auto logger_level = convert_log_level(level);
core_->log(logger_level, message);
}
void flush() override {
core_->flush();
}
private:
logger::log_level convert_log_level(thread_system::log_level level);
};
}
Standalone logger adapter for use without common_system DI.
Common System Adapter
#include <kcenon/common/interfaces/monitoring_interface.h>
#include "logger_core.h"
, public common::interfaces::IMonitorable {
public:
get_monitoring_data() override {
auto stats = core_->get_current_metrics();
return convert_to_metrics_snapshot(stats);
}
health_check() override {
health_check_result{}
);
}
std::string get_component_name() const override {
return "logger_system::logger";
}
private:
common::interfaces::metrics_snapshot
convert_to_metrics_snapshot(const logger_performance_stats& stats);
};
}
Factory Pattern
};
public:
static std::unique_ptr<logger_adapter> create(
bool async = true,
size_t buffer_size = 8192
) {
auto core = std::make_shared<logger_core>(async, buffer_size);
switch (mode) {
return std::make_unique<standalone_adapter>(core);
return std::make_unique<thread_system_adapter>(core);
return std::make_unique<common_system_adapter>(core);
return std::make_unique<full_integration_adapter>(core);
default:
throw std::invalid_argument("Unknown integration mode");
}
}
};
}
Migration Strategy
Step 1: Extract Core (1 week)
Step 2: Implement Adapters (1 week)
Step 3: Update Public Interface (3 days)
- Update logger.h to use factory pattern
- Deprecate old constructors
- Add migration guide
Step 4: Remove Conditional Compilation (2 days)
- Remove #ifdef from all public headers
- Simplify CMakeLists.txt
- Update build documentation
Step 5: Testing and Validation (3 days)
- Test all integration modes
- Benchmark performance
- Update CI/CD pipeline
- Update documentation
Total Estimated Effort: 2.5 weeks
Performance Considerations
Virtual Function Overhead
void benchmark_logging_overhead() {
adapter->log(level, message);
}
Analysis: +2ns overhead (~1.3%) is negligible for logging operations which are I/O bound and typically take microseconds to complete.
Binary Size Impact
Current (with #ifdef):
- Standalone build: 250KB
- Thread integrated: 275KB
- Common integrated: 260KB
- Full integrated: 290KB
Proposed (single binary):
- Unified build: 310KB (+20KB, ~7% increase)
Analysis: 20KB increase is acceptable for improved maintainability.
Risk Mitigation
Risks
- Performance Regression: Virtual function overhead
- Mitigation: Benchmark before/after, optimize hot paths
- Binary Size Increase: Including all adapters
- Mitigation: Acceptable trade-off for maintainability
- API Breaking Changes: Existing code needs updates
- Mitigation: Deprecation period, migration guide
- Testing Coverage: Must test all modes
- Mitigation: Automated tests for each adapter
Rollback Plan
If refactoring introduces critical issues:
- Revert to previous commit
- Keep conditional compilation for one more release
- Address issues in separate branch
- Re-attempt refactoring in next version
Success Criteria
- Zero conditional compilation in public headers
- All integration modes pass tests
- Performance overhead < 5%
- Binary size increase < 10%
- CI/CD simplified to single configuration
- Documentation updated with migration guide
References
- Adapter Pattern: Gang of Four Design Patterns
- Performance: Benchmark results in
benchmarks/adapter_overhead.cpp
- Migration Guide:
docs/MIGRATION_TO_ADAPTERS.md (to be created)
Author: Architecture Team Reviewers: TBD Approval: Pending implementation