Summary
Document database_system's adapter pattern as a best practice reference for managing optional dependencies across the ecosystem.
5W1H Specification
- Who: database_system maintainers, ecosystem documentation
- What: Document the runtime backend selection pattern used by database_system
- Where:
docs/ADAPTER_PATTERNS.md, README.md
- When: v0.4.0.0 release cycle
- Why:
- database_system has the most sophisticated optional dependency handling
- Pattern achieves ZERO circular dependency risk despite many integrations
- Other modules can adopt same pattern
- How: Document patterns with code examples
Priority
LOW - Documentation task, no code changes required
Current State Analysis
database_system demonstrates excellent optional dependency management:
database_system (Tier 3)
│
├── common_system (REQUIRED)
├── thread_system (OPTIONAL - adapter pattern)
├── container_system (OPTIONAL - protocol container)
├── monitoring_system (OPTIONAL - metrics adapter)
└── External: PostgreSQL, MySQL, SQLite, MongoDB, Redis
Risk Assessment: NONE
- All optional dependencies use runtime backend selection
- PIMPL idiom hides implementation dependencies
- Factory patterns allow late binding
Adapter Pattern Examples
1. Monitoring Adapter Pattern
// database_system/integrated/adapters/monitoring_adapter.h
class monitoring_backend {
public:
virtual ~monitoring_backend() = default;
virtual void record_query_time(std::chrono::nanoseconds) = 0;
virtual void record_connection_acquired() = 0;
virtual void record_error(std::string_view) = 0;
};
// Fallback when monitoring_system unavailable
class fallback_monitoring_backend : public monitoring_backend {
public:
void record_query_time(std::chrono::nanoseconds ns) override {
total_query_time_ += ns;
query_count_++;
}
// Internal storage, no external dependency
private:
std::atomic<std::size_t> query_count_{0};
std::atomic<std::chrono::nanoseconds::rep> total_query_time_{0};
};
#if USE_MONITORING_SYSTEM
class system_monitoring_backend : public monitoring_backend {
// Uses monitoring_system for real metrics
};
#endif
// Factory selects at runtime
auto create_monitoring_backend() -> std::unique_ptr<monitoring_backend> {
#if USE_MONITORING_SYSTEM
if (monitoring_available()) {
return std::make_unique<system_monitoring_backend>();
}
#endif
return std::make_unique<fallback_monitoring_backend>();
}
2. Thread Pool Adapter Pattern
// database_system/adapters/thread_pool_adapter.h
class thread_backend {
public:
virtual ~thread_backend() = default;
virtual void submit(std::function<void()> task) = 0;
};
// Fallback using std::thread
class std_thread_backend : public thread_backend {
void submit(std::function<void()> task) override {
std::thread(std::move(task)).detach();
}
};
#if USE_THREAD_SYSTEM
class thread_system_backend : public thread_backend {
void submit(std::function<void()> task) override {
pool_->submit(std::move(task));
}
};
#endif
Documentation Structure
Proposed docs/ADAPTER_PATTERNS.md
-
Pattern Overview
- When to use adapter pattern vs direct dependency
- Benefits: testability, isolation, flexibility
-
Implementation Checklist
- [ ] Define abstract backend interface
- [ ] Implement fallback backend (no external deps)
- [ ] Implement real backend with #if guard
- [ ] Create factory function for runtime selection
- [ ] Use PIMPL to hide implementation details
-
Anti-Patterns to Avoid
- Direct
#include without interface abstraction
- Compile-time only switching (no runtime fallback)
- Fallback that silently drops functionality
-
Code Examples
- Monitoring adapter
- Thread pool adapter
- Logger adapter
Tasks
Best Practices Checklist
## Adapter Pattern Checklist
### Interface Design
- [ ] Abstract base class with virtual destructor
- [ ] Pure virtual methods for all operations
- [ ] No dependency on external types in interface
### Fallback Implementation
- [ ] Works without any optional dependencies
- [ ] Provides meaningful (not stub) functionality
- [ ] Can be used for testing
### Real Implementation
- [ ] Guarded with `#if USE_*` preprocessor
- [ ] Uses external dependency internally only
- [ ] Same interface as fallback
### Factory
- [ ] Runtime detection of dependency availability
- [ ] Returns fallback when unavailable
- [ ] Single point of backend creation
Acceptance Criteria
Dependencies
- None - Documentation only
Parent Epic
Related Issues
- Documents patterns used in monitoring_adapter, thread_pool_adapter, logger_adapter
Summary
Document database_system's adapter pattern as a best practice reference for managing optional dependencies across the ecosystem.
5W1H Specification
docs/ADAPTER_PATTERNS.md,README.mdPriority
LOW - Documentation task, no code changes required
Current State Analysis
database_system demonstrates excellent optional dependency management:
Risk Assessment: NONE
Adapter Pattern Examples
1. Monitoring Adapter Pattern
2. Thread Pool Adapter Pattern
Documentation Structure
Proposed
docs/ADAPTER_PATTERNS.mdPattern Overview
Implementation Checklist
Anti-Patterns to Avoid
#includewithout interface abstractionCode Examples
Tasks
docs/ADAPTER_PATTERNS.mdBest Practices Checklist
Acceptance Criteria
docs/ADAPTER_PATTERNS.mdexists with examplesDependencies
Parent Epic
Related Issues