Fundamentals 23 min read

Refactoring Principles, Code Smells, and Refactoring Techniques

This article explains refactoring as a disciplined way to improve software structure without altering behavior, outlines common code smells, and presents a comprehensive set of refactoring techniques—including extracting functions, moving features, simplifying conditionals, and reorganizing data—illustrated with Java code examples.

Architecture Digest
Architecture Digest
Architecture Digest
Refactoring Principles, Code Smells, and Refactoring Techniques

Refactoring is a systematic approach to adjusting a software system’s internal structure while preserving its observable behavior, with the goals of improving readability, reducing maintenance cost, and facilitating future changes.

Refactoring Principles

1. What is refactoring? It is a set of transformations that restructure code without changing its external functionality. 2. Why refactor? To prevent design decay, uncover bugs, and increase development speed by keeping the code clean and understandable. 3. When to refactor? Refactoring should be done continuously, not as a separate scheduled task; the “three‑time rule” suggests refactoring when you encounter the same code for the third time.

Common Code Smells

Examples include duplicated code, overly long classes or methods, large parameter lists, divergent changes, shotgun surgery, excessive coupling, data clumps, primitive obsession, switch statements, redundant classes, and over‑commented code. Each smell indicates a specific structural problem that can be addressed with targeted refactorings.

Reorganizing Functions

Techniques such as Extract Method (create a well‑named new function for a code fragment), Inline Method (replace a simple method call with its body), and Inline Temporary Variable (replace a temporary variable with its expression) help simplify and clarify logic.

Example of extracting a temporary variable:

double basePrice = quantity * timePrice;
if (basePrice > 1000) {
    return basePrice * 9.5;
} else {
    return basePrice * 0.98;
}

After applying Extract Method and Replace Temp with Query :

if (basePrice() > 1000) {
    return basePrice() * 9.5;
} else {
    return basePrice() * 0.98;
}

private double basePrice() {
    return quantity * timePrice;
}

Moving Features Between Objects

When a class takes on too many responsibilities, Extract Class can split responsibilities into a new class. Conversely, if a class is too lightweight, Inline Class can merge it into another. Move Method and Move Field relocate behavior or data to the class that uses them most.

Example of moving a method:

public int discount(int inputVal, int quantity, int yearToDate) {
    int result = inputVal;
    if (inputVal > 50) result -= 2;
    return result;
}

After moving the calculation to a helper method:

public int discount(int inputVal, int quantity, int yearToDate) {
    int result = inputVal;
    if (inputVal > 50) result -= 2;
    return result;
}

private int adjustInput(int inputVal) {
    if (inputVal > 50) return inputVal - 2;
    return inputVal;
}

Reorganizing Data

Encapsulate public fields, replace primitive data with value objects, convert arrays to objects, and introduce constants to eliminate magic numbers. For instance, replace direct field access with getter/setter methods, or turn a range of two ints into a dedicated Range class.

Simplifying Conditionals

Techniques include extracting complex boolean expressions into well‑named methods, merging duplicate branches, removing control flags, and replacing conditionals with polymorphism (e.g., using subclass overrides instead of if (type == …) ).

Simplifying Function Calls

Rename ambiguous functions, add or remove parameters, split functions into query and command parts, replace parameter‑driven logic with separate functions, and introduce parameter objects to group related arguments.

Handling Generalization

Move common fields or methods up to a superclass, extract interfaces for shared behavior, collapse unnecessary inheritance hierarchies, and replace inheritance with delegation when appropriate.

Recommended Reading

JAVA Online Fault Diagnosis Guide

Three MySQL Large‑Table Optimization Strategies

RocketMQ Message Loss and Solutions

Optimizing Excel Import of 100,000 Rows

ElasticSearch Search Principles Illustrated with Diagrams

If you found this guide useful, please give it a like and share your feedback.

software designrefactoringclean codeobject-orientedcode smells
Architecture Digest
Written by

Architecture Digest

Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.