The Natural Order of Refactoring Under the Microscope Part 3: Extract Method

Table of Contents

Analyzing Class and Method Responsibilities

In the next step, we examine the responsibilities of individual classes and methods, checking if they align with the intended responsibility of the class. It is best to analyze all methods and group them based on performing similar operations. We look for a place for these in other classes or a new class. Remember: if there is a significant private method in a class (longer than 3-4 lines), it should be moved to another class.

Example: Extracting Methods for Clarity

In our example, the methods mainly revolve around discrete operations aimed at obfuscating text and ensuring operations are performed with a certain probability. We can extract classes corresponding to these operations: TextObfuscatorMethods and Probability.

Refactored Code Example

The code after this change might look like this:

public class TextObfuscator
{
    // ...
    public string Obfuscate(string text)
    {
        List<TextPart> parts = methods.ParseTextForWordsAndNonWords(text);
        methods.ChangeWordsOrderRandomly(parts);
        methods.AddMeaninglessWordsRandomly(parts);
        methods.RemoveSeparators(parts);
        methods.AddSeparatorsRandomly(parts);
        methods.RemoveSpaces(parts);
        // ...
    }
}

public class TextObfuscatorMethods
{
    // ...
    public virtual void RemoveSpaces(List<TextPart> parts)
    {
        for (int i = 0; i < parts.Count; i++)
        {
            RemoveSpacesFromTextPart(parts, i);
            RemoveTextPartIfEmpty(parts, i);
        }
    }

    private static void RemoveSpacesFromTextPart(List<TextPart> parts, int i)
    {
        parts[i] = parts[i].ReplaceContents(" ", "");
    }

    public virtual void RemoveSeparators(List<TextPart> parts)
    {
        for (int i = 0; i < parts.Count; i++)
        {
            RemoveSeparatorsFromTextPart(parts, i);
            RemoveTextPartIfEmpty(parts, i);
        }
    }

    public virtual void AddSeparatorsRandomly(List<TextPart> parts)
    {
        for (int i = 0; i < parts.Count; i++)
        {
            if (ShouldAddSeparator())
            {
                parts.Insert(i, TextPart.NewSeparator(DrawSeparator())); i++;
            }
        }
    }

    private bool ShouldAddSeparator()
    {
        return probability.ShouldBeDone(ADDING_SEPARATOR_PROBABILITY);
    }
    // ...
}

public class Probability
{
    private Random random = new Random();

    public bool ShouldBeDone(double probability)
    {
        if (probability < 0.0 || probability > 1.0)
        {
            throw new ProbabilityException("Probability should be in range [0.0, 0.1]");
        }

        return random.NextDouble() < probability;
    }
}

This refactoring approach helps to maintain a clean codebase by ensuring that each class has a single responsibility and methods are organized according to their functionalities.

(Text translated and moved from original old blog automatically by AI. May contain inaccuracies.)

Related Posts

Clean Code

The Importance of Clean Code

There are ongoing philosophical discussions on whether clean code matters and if it is worth investing time to read it. I won’t engage directly in this debate. Instead, a small example should suffice:

Read More

Technical Leader Worries: I Have Too Many Things to Do

Technical Leader Worries: I Have Too Many Things to Do

Those wonderful days when the only thing you did was writing code are gone. Now you are a leader. You are doing everything: attending or conducting meetings, removing impediments, mediating between team members and the rest of the organization, reading or writing some kind of reports (and you deceive yourself that spending two hours in Excel counts as programming because of some smartly used formulas) and so on. You are in a hurry all the time, and it never ends.

Read More

The Natural Order of Refactoring - A Conceptual Sketch

The Natural Order of Refactoring

In software development, refactoring is a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior. This process, often visualized in a conceptual sketch, can help developers understand the natural flow and order in which refactoring should occur.

Read More