liveBook · Manning

Refactoring

As explained in Refactoring to Rust

A software-engineering process of restructuring existing code to improve qualities such as performance or maintainability without replacing the whole system.

Refactoring restructures existing code to make it perform better, become easier to maintain, or meet another improvement goal. Unlike a rewrite, it changes the smallest useful part rather than replacing a whole application. The aim is to improve a running system without giving up the service it already provides. section 1.1 section 1.0

A practical refactor proceeds in small, verifiable steps:

  • Find the part that needs the most help, such as a performance bottleneck, instead of assuming the entire system needs replacing. section 1.1 section 8.6
  • Change and deploy a small piece at a time. If a problem appears, a small deployment makes its cause easier to identify. section 1.1
  • Reuse existing tests to check that the changed code fulfills the same contract. If there are no automated tests, add them as part of the effort. section 1.1

Rust can replace a selected component while the surrounding application remains in its original language. That can improve performance, memory safety, or maintainability without demanding a wholesale rewrite. But the change still needs an operational plan: frequent deployment must be feasible, the environment must allow the new code to run, and someone must be able to maintain it. A new project does not need refactoring merely to start in Rust. section 1.10 section 1.5

Replace one Python bottleneck

Suppose a Python application spends too long generating a Mandelbrot image. The image-generating function can move into a Rust module exposed through PyO3, while Python continues to call it. A further change can release Python’s global interpreter lock during the Rust work so other threads can run. The application remains a Python application; the targeted computation changes. section 8.6

Listing 8.11 lib.rs: Adding a thread-safe function
#[pyfunction]
fn mandelbrot_fast(
    py: Python<'_>,
    size: u32,
    path: &str,
    range_x0: f64,
    range_y0: f64,
    range_x1: f64,
    range_y1: f64,
) {
    py.allow_threads(|| mandelbrot_func(size, path, range_x0, range_y0,
range_x1, range_y1))  #1
}

#[pymodule]
fn mandelbrot(_py: Python, m: &PyModule) -> PyResult<()> {
   ...
       m.add_function(wrap_pyfunction!(mandelbrot_fast, m)?)?;

    Ok(())
}

The thread-safe Rust function shows a second, focused change: PyO3’s allow_threads wraps the image computation without requiring another application-wide replacement. section 8.6

How Refactoring to Rust covers it

How deep it goes
Defines the scope of a refactor and gives deployment and testing rationale, then illustrates language integration through a concrete replacement.
Examples
Uses a Python Mandelbrot function moved into a PyO3 Rust module, with a later change that releases the global interpreter lock.
What it assumes
Assumes an existing project and some procedural-language experience, but not Rust expertise.
What you can do after
Practice/perform a small replacement, verify its existing contract, and deploy it in changes whose failures can be traced.
How it connects
Connects refactoring to rewriting, automated testing, deployment, Rust interoperability, and the Python global interpreter lock.

Also explained in

Compare how 22 books explain refactoring →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Refactoring to Rust. The section links point to the parts of the book it draws on.