C++ Technical Debt: Strategic Refactoring of Legacy Codebases [#45-2]
이 글의 핵심
Replace big-bang rewrites with phased modernization: Clang-Tidy, tests, sanitizer gates, RAII, and compiler upgrades aligned with your platform constraints.
Introduction: “Scary codebases”
Legacy C++ mixes raw pointers, macros, C style, and tangled builds. Big-bang rewrites rarely ship safely. Strategic refactoring means prioritizing, incremental changes, and preserving behavior with verification.
Topics: prioritization, RAII / smart pointers, STL, Clang-Tidy, Sanitizers, CI, migration phases, production patterns.
Scenarios (examples)
- Memory leaks → unique_ptr, containers, fix all exception paths.
- Macro constants →
constexpr/enum class. - Implicit conversions →
explicit, stronger types. - Build — unify on CMake, lock compiler versions in CI.
- Thread safety — document and fix data races; TSan in CI.
Strategy
- Inventory risk: crashes, security, build failures.
- Test harness: even minimal golden tests unlock refactors.
- Tooling: clang-tidy, clang-format, ASan/UBSan on test builds.
- Small PRs: one mechanical change at a time.
- Boundaries: introduce interfaces at module edges before rewriting internals.
Example direction
// Legacy style
// FILE*, malloc, manual fclose risk
// Modern style
std::ifstream file(path);
std::vector<char> buffer(4096);
// RAII closes and frees on all paths
Production patterns
- Feature flags for new paths.
- Dual-run critical outputs during migration.
- ABI awareness when crossing DLL boundaries.
Related posts
- unique_ptr advanced
- Smart pointer basics
Summary
Modernize legacy C++ by combining tests + static/dynamic analysis with small, reversible steps. Align compiler upgrades with dependency and platform reality—no single recipe fits every codebase.