Summary
Refactor the centralized error code registry to allow each system to define its own error codes locally while common_system provides only conversion utilities and base categories, improving system isolation and reducing coupling.
Background (Why)
Current design: centralized error code registry in common_system
All systems must register their error codes in common_system
Creates tight coupling between common_system and dependent systems
Adding new error codes requires modifying common_system
Kent Beck's "Loose Coupling": systems should be independently evolvable
Error codes should be defined where they're used
Current centralization problem :
// common_system/error/error_codes.h
namespace kcenon ::common::error_codes {
// Common errors
constexpr int SUCCESS = 0 ;
constexpr int UNKNOWN_ERROR = 1 ;
// Logger system errors (why is this here?)
constexpr int LOG_WRITE_FAILED = 1000 ;
constexpr int LOG_QUEUE_FULL = 1001 ;
// Network system errors (why is this here?)
constexpr int NETWORK_CONNECTION_FAILED = 2000 ;
constexpr int NETWORK_TIMEOUT = 2001 ;
// Database system errors (why is this here?)
constexpr int DB_CONNECTION_FAILED = 3000 ;
// ... more system-specific codes
}
Scope (What)
Current State (Centralized Registry)
common_system/
└── error/
└── error_codes.h ← Contains ALL error codes for ALL systems
Proposed State (Decentralized with Common Base)
// common_system/error/error_category.h
namespace kcenon ::common {
// Base error category interface
class error_category {
public:
virtual ~error_category () = default ;
virtual std::string_view name () const noexcept = 0;
virtual std::string message (int code) const = 0;
virtual bool equivalent (int code, const error_category& other, int other_code) const ;
};
// Common error category (shared across all systems)
class common_error_category : public error_category {
public:
static const common_error_category& instance ();
std::string_view name () const noexcept override { return " common" ; }
std::string message (int code) const override ;
// Common error codes
enum codes {
success = 0 ,
unknown_error = 1 ,
invalid_argument = 2 ,
out_of_range = 3 ,
not_implemented = 4 ,
operation_cancelled = 5 ,
// Only truly common errors here
};
};
// Error code that carries its category
class error_code {
public:
error_code () = default ;
error_code (int code, const error_category& category);
int value () const noexcept { return code_; }
const error_category& category () const noexcept { return *category_; }
std::string message () const { return category_->message (code_); }
explicit operator bool () const noexcept { return code_ != 0 ; }
bool operator ==(const error_code& other) const ;
private:
int code_ = 0 ;
const error_category* category_ = &common_error_category::instance ();
};
// Helper to create error codes
template <typename Category>
error_code make_error_code (typename Category::codes code) {
return error_code (static_cast <int >(code), Category::instance ());
}
} // namespace kcenon::common
System-Specific Error Categories
// logger_system/error/logger_error_category.h
namespace kcenon ::logger {
class logger_error_category : public common ::error_category {
public:
static const logger_error_category& instance ();
std::string_view name () const noexcept override { return " logger" ; }
std::string message (int code) const override ;
enum codes {
write_failed = 1 ,
queue_full = 2 ,
writer_not_found = 3 ,
invalid_format = 4 ,
// Logger-specific errors defined HERE, not in common_system
};
};
// Convenience function
inline common::error_code make_logger_error (logger_error_category::codes code) {
return common::make_error_code<logger_error_category>(code);
}
} // namespace kcenon::logger
// network_system/error/network_error_category.h
namespace kcenon ::network {
class network_error_category : public common ::error_category {
public:
static const network_error_category& instance ();
std::string_view name () const noexcept override { return " network" ; }
std::string message (int code) const override ;
enum codes {
connection_failed = 1 ,
timeout = 2 ,
address_in_use = 3 ,
connection_refused = 4 ,
// Network-specific errors defined HERE
};
};
} // namespace kcenon::network
Result Integration
// common_system/patterns/result.h
template <typename T>
class Result {
public:
// Accept any error_code (from any category)
static Result<T> error (common::error_code ec) {
return Result<T>(ec);
}
// Error info includes category for debugging
common::error_code error_code () const ;
std::string error_message () const {
return error_code ().message ();
}
std::string_view error_category_name () const {
return error_code ().category ().name ();
}
};
// Usage in logger_system
Result<void > logger::write (const log_entry& entry) {
if (queue_full) {
return Result<void >::error (
make_logger_error (logger_error_category::queue_full)
);
}
// ...
}
// Usage in network_system
Result<void > connection::connect () {
if (failed) {
return Result<void >::error (
make_network_error (network_error_category::connection_failed)
);
}
// ...
}
Impact Analysis (Where)
Before
After
Benefit
Error codes in common_system
Error codes in each system
Better isolation
Modify common for new errors
Modify only relevant system
Less coupling
Single namespace for all errors
Category-based namespacing
Clearer error origin
Error code collisions possible
Category prevents collisions
Type safety
Implementation Plan (How)
Phase 1: Infrastructure
Create error_category base class
Create common_error_category for shared errors
Create error_code class with category support
Update Result<T> to use new error_code
Phase 2: Migration - Common System
Identify truly common error codes
Move common errors to common_error_category
Deprecate old error code constants
Phase 3: Migration - Dependent Systems
Create logger_error_category in logger_system
Create network_error_category in network_system
Create database_error_category in database_system
Create container_error_category in container_system
Phase 4: Cleanup
Remove system-specific errors from common_system
Update all error creation sites
Update documentation
Acceptance Criteria
Breaking Change Assessment
Aspect
Details
Breaking Change
Yes - error code handling
Migration Path
Wrapper functions + documentation
Deprecation Period
1 major version
Benefit
Better system isolation, clearer error origin
Labels
refactor
architecture
breaking-change
Summary
Refactor the centralized error code registry to allow each system to define its own error codes locally while common_system provides only conversion utilities and base categories, improving system isolation and reducing coupling.
Background (Why)
Current centralization problem:
Scope (What)
Current State (Centralized Registry)
Proposed State (Decentralized with Common Base)
System-Specific Error Categories
Result Integration
Impact Analysis (Where)
Implementation Plan (How)
Phase 1: Infrastructure
error_categorybase classcommon_error_categoryfor shared errorserror_codeclass with category supportResult<T>to use newerror_codePhase 2: Migration - Common System
common_error_categoryPhase 3: Migration - Dependent Systems
logger_error_categoryin logger_systemnetwork_error_categoryin network_systemdatabase_error_categoryin database_systemcontainer_error_categoryin container_systemPhase 4: Cleanup
Acceptance Criteria
Breaking Change Assessment
Labels
refactorarchitecturebreaking-change