{}const=>[]async()letfn</>var
DevelopmentBasics

Code refactoring: how to improve existing code and make it readable

Learn what refactoring is and how to properly improve existing code. Practical examples in JavaScript and Python, basic techniques, tools and rules for safe refactoring for beginner developers.

К

Kodik

Author

6 min read

Imagine: you open the code that you wrote six months ago, and you can't understand what is happening in the 200-line function with the variables data1, data2, temp. Sound familiar? This is a signal that the code needs refactoring.

What is refactoring?

Refactoring is the process of changing the internal structure of the code without changing its external behavior. It's like tidying up an apartment: things remain the same, but it becomes much easier to find them.

It is important to understand that refactoring is not about fixing bugs or adding new features. It is an improvement in the quality of the existing code to make it easier to work with in the future.

🔥 100,000+ students already with us

Tired of reading theory?
Time to code!

Kodik — an app where you learn to code through practice. AI mentor, interactive lessons, real projects.

🤖 AI 24/7
🎓 Certificates
💰 Free
🚀 Start learning
Joined today

When code needs refactoring

There are several clear signs that it's time to refactor. Code duplication is a classic example: if you copy the same block to different places, this is the first candidate for a separate function. Long functions that do too many different things also need to be divided into smaller and more understandable parts.

Poorly named variables and functions create cognitive load. When a variable is called x or arr, you have to keep in mind what it means. And a name like activeUsers or calculateTotalPrice speaks for itself.

Confused logic with many nested conditions turns the code into a maze. If you see more than three levels of nesting if, you should consider refactoring.

Basic refactoring techniques

Extracting a function

This is the most common technique. You take a piece of code and put it into a separate function with a clear name.

// Before refactoring
function processOrder(order) {
    // Validation
    if (!order.items || order.items.length === 0) {
        throw new Error('Order is empty');
    }
    if (!order.userId) {
        throw new Error('No user specified');
    }
    
    // Calculation of the amount
    let total = 0;
    for (let item of order.items) {
        total += item.price * item.quantity;
    }
    
    // Discount application
    if (order.promoCode) {
        total *= 0.9;
    }
    
    return total;
}

// After refactoring
function processOrder(order) {
    validateOrder(order);
    const total = calculateTotal(order.items);
    return applyDiscount(total, order.promoCode);
}

function validateOrder(order) {
    if (!order.items || order.items.length === 0) {
        throw new Error('Order is empty');
    }
    if (!order.userId) {
        throw new Error('No user specified');
    }
}

function calculateTotal(items) {
    return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
}

function applyDiscount(total, promoCode) {
    return promoCode ? total * 0.9 : total;
}

Now the processOrder function reads like a book: validate the order, calculate the amount, apply the discount. Each operation is encapsulated in its function.

Renaming

A good name is half the battle. The variable should reflect what is stored in it, and the function — what it does.

# To
def calc(a, b, c):
    return a * b * c / 100

# After
def calculate_discount_amount(price, quantity, discount_percent):
    return price * quantity * discount_percent / 100

Simplification of conditions

Complex conditions can be moved to functions with descriptive names or use early return.

// To
function canUserEdit(user, document) {
    if (user.isAuthenticated) {
        if (user.role === 'admin' || document.authorId === user.id) {
            if (!document.isLocked) {
                return true;
            }
        }
    }
    return false;
}

// After
function canUserEdit(user, document) {
    if (!user.isAuthenticated) return false;
    if (document.isLocked) return false;
    
    return user.role === 'admin' || document.authorId === user.id;
}

Replacing magic numbers with constants

Magic numbers are values whose meaning is incomprehensible without context.

# To
if user.age >= 18:
    grant_access()

# After
MINIMUM_AGE_FOR_ACCESS = 18

if user.age >= MINIMUM_AGE_FOR_ACCESS:
    grant_access()

Refactoring classes

When working with object-oriented code, you often come across classes that do too much. The principle of single responsibility states that a class should have only one reason to change.

# Before: the class does too much
class User:
    def __init__(self, name, email):
        self.name = name
        self.email = email
    
    def save_to_database(self):
        # Logic of saving in the database
        pass
    
    def send_welcome_email(self):
        # Email sending logic
        pass
    
    def generate_report(self):
        # Report generation logic
        pass

# After: shared responsibility
class User:
    def __init__(self, name, email):
        self.name = name
        self.email = email

class UserRepository:
    def save(self, user):
        # Logic of saving in the database
        pass

class EmailService:
    def send_welcome_email(self, user):
        # Email sending logic
        pass

class UserReportGenerator:
    def generate(self, user):
        # Report generation logic
        pass

Rules for safe refactoring

Refactoring without tests is a game of Russian roulette. Before changing the code, make sure you have tests that cover its functionality. If there are no tests, write them before refactoring.

Take small steps. Don't try to rewrite everything at once. It is better to do one small refactoring, run the tests, make sure everything works, and only then move on to the next one.

Commit frequently. Each successful refactoring step is a separate commit. If something goes wrong, you can roll back.

When not to refactor

Refactoring is not an end in itself. There are situations when it is better to leave the code as it is. If you are working on a prototype that can be discarded, deep refactoring does not make sense. If the code has been working stably for years and nobody touches it, it may be better not to take any chances.

Also, do not refactor code that you do not understand. First, figure out how it works, write tests, and only then improve the structure.

Refactoring tools

Modern IDEs make refactoring much easier. PyCharm, VS Code, or WebStorm have automatic renaming of variables and functions, extraction of methods, and changing of function signatures. Use these tools — they help to avoid mistakes.

Linters like ESLint for JavaScript or Pylint for Python help detect problem areas in the code. They point out duplication, functions that are too complex, and unused variables.

Refactoring as part of the development culture

The best approach is to do a little refactoring regularly, rather than accumulate technical debt. The Boy Scout rule says: leave the code cleaner than it was before you. Working with a function? Improve its name. See duplication? Move it to a common function.

Code review is a great opportunity for refactoring. A colleague's fresh perspective often notices what the code author missed.

Want to learn how to write clean code from the very beginning?

Appendix Code created specifically for those who are taking their first steps in programming. Here you don't just learn the theory, but immediately apply your knowledge in practice, creating real projects. The courses are designed so that from day one you write code that works and that you can be proud of. And when you learn how to write code, you will learn how to make it even better through refactoring.

Join our Telegram channel!

We have a friendly community of developers, where everyone can ask any question — from the simplest to the most professional. Every day we analyze the top topics in development: from the basics to advanced techniques. Here it is not shameful to ask and they will always help you to understand. It is more interesting to learn together!

🎯Stop procrastinating

Liked the article?
Time to practice!

In Kodik, you don't just read — you write code immediately. Theory + practice = real skills.

Instant practice
🧠AI explains code
🏆Certificate

No registration • No card