C++ Technical Debt: Strategic Refactoring of Legacy Codebases [#45-2]

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 leaksunique_ptr, containers, fix all exception paths.
  • Macro constantsconstexpr / enum class.
  • Implicit conversionsexplicit, stronger types.
  • Build — unify on CMake, lock compiler versions in CI.
  • Thread safety — document and fix data races; TSan in CI.

Strategy

  1. Inventory risk: crashes, security, build failures.
  2. Test harness: even minimal golden tests unlock refactors.
  3. Tooling: clang-tidy, clang-format, ASan/UBSan on test builds.
  4. Small PRs: one mechanical change at a time.
  5. 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.

  • 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.