• Shift Elevate
  • Posts
  • Long Parameter List: Introduce Parameter Object | Clean Code

Long Parameter List: Introduce Parameter Object | Clean Code

Methods with many parameters are a common code smell that reduces readability and maintainability.

We will see how we can refactor them using parameter objects.

Clean Code Reference

⚠️ Code Smell: Long Parameter List
Refactoring: Introduce Parameter Object
🎯 Goal: Cohesive parameter grouping for better readability

The Long Parameter List code smell occurs when methods have too many parameters, making them difficult to understand and maintain. The Introduce Parameter Object refactoring technique groups related parameters into cohesive objects that better represent the method's intent.

The Code Smell: Long Parameter List

Long Parameter List is a code smell that makes methods difficult to read, understand, and maintain. When methods have more than 3-4 parameters, they become hard to call correctly and the parameter order becomes critical. This often indicates that the method is doing too much or that related data should be grouped together.

Symptoms

Impact

Methods with 4+ parameters

Reduced readability

Parameter order dependency

Easy to make mistakes

Related parameters scattered

Poor cohesion

Here's a typical example of long parameter list code smell:

public class UserService {
    public User createUser(
        String firstName, 
        String lastName, 
        String email, 
        String phoneNumber, 
        String address, 
        String city, 
        String state, 
        String zipCode, 
        String country,
        LocalDate dateOfBirth,
        String password,
        boolean isActive
    ) {
        // Validate all parameters
        if (firstName == null || firstName.trim().isEmpty()) {
            throw new IllegalArgumentException("First name is required");
        }
        if (lastName == null || lastName.trim().isEmpty()) {
            throw new IllegalArgumentException("Last name is required");
        }
        if (email == null || !email.matches("^[A-Za-z0-9+_.-]+@(.+)$")) {
            throw new IllegalArgumentException("Valid email is required");
        }
        // ... more validation logic
        
        // Create user object
        User user = new User();
        user.setFirstName(firstName);
        user.setLastName(lastName);
        user.setEmail(email);
        user.setPhoneNumber(phoneNumber);
        user.setAddress(address);
        user.setCity(city);
        user.setState(state);
        user.setZipCode(zipCode);
        user.setCountry(country);
        user.setDateOfBirth(dateOfBirth);
        user.setPassword(password);
        user.setActive(isActive);
        
        return userRepository.save(user);
    }
    
    public void updateUserProfile(
        Long userId,
        String firstName, 
        String lastName, 
        String email, 
        String phoneNumber, 
        String address, 
        String city, 
        String state, 
        String zipCode, 
        String country
    ) {
        // Similar validation and update logic
        // ... implementation
    }
}

This method has 12 parameters, making it extremely difficult to call correctly. The parameter order is critical, and it's easy to pass parameters in the wrong order. The method is also doing too many things: validation, object creation, and persistence.

The Refactoring: Introduce Parameter Object

The Introduce Parameter Object refactoring technique groups related parameters into cohesive objects that better represent the method's intent. This improves readability, reduces the chance of errors, and makes the code more maintainable.

Step by Step Refactoring Process:

  1. Identify related parameters that logically belong together.

  2. Create a parameter object that encapsulates these related parameters.

  3. Replace the long parameter list with the parameter object.

  4. Update method calls to use the new parameter object.

  5. Consider creating multiple parameter objects if parameters belong to different logical groups.

Here's the refactored version:

// Parameter objects
public class UserRegistrationData {
    private final String firstName;
    private final String lastName;
    private final String email;
    private final String phoneNumber;
    private final Address address;
    private final LocalDate dateOfBirth;
    private final String password;
    private final boolean isActive;
    
    public UserRegistrationData(
        String firstName, 
        String lastName, 
        String email, 
        String phoneNumber, 
        Address address,
        LocalDate dateOfBirth,
        String password,
        boolean isActive
    ) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
        this.phoneNumber = phoneNumber;
        this.address = address;
        this.dateOfBirth = dateOfBirth;
        this.password = password;
        this.isActive = isActive;
    }
    
    // Getters
    public String getFirstName() { return firstName; }
    public String getLastName() { return lastName; }
    public String getEmail() { return email; }
    public String getPhoneNumber() { return phoneNumber; }
    public Address getAddress() { return address; }
    public LocalDate getDateOfBirth() { return dateOfBirth; }
    public String getPassword() { return password; }
    public boolean isActive() { return isActive; }
}

public class Address {
    private final String street;
    private final String city;
    private final String state;
    private final String zipCode;
    private final String country;
    
    public Address(String street, String city, String state, String zipCode, String country) {
        this.street = street;
        this.city = city;
        this.state = state;
        this.zipCode = zipCode;
        this.country = country;
    }
    
    // Getters
    public String getStreet() { return street; }
    public String getCity() { return city; }
    public String getState() { return state; }
    public String getZipCode() { return zipCode; }
    public String getCountry() { return country; }
}

// Refactored service
public class UserService {
    public User createUser(UserRegistrationData registrationData) {
        validateRegistrationData(registrationData);
        
        User user = new User();
        user.setFirstName(registrationData.getFirstName());
        user.setLastName(registrationData.getLastName());
        user.setEmail(registrationData.getEmail());
        user.setPhoneNumber(registrationData.getPhoneNumber());
        user.setAddress(registrationData.getAddress().getStreet());
        user.setCity(registrationData.getAddress().getCity());
        user.setState(registrationData.getAddress().getState());
        user.setZipCode(registrationData.getAddress().getZipCode());
        user.setCountry(registrationData.getAddress().getCountry());
        user.setDateOfBirth(registrationData.getDateOfBirth());
        user.setPassword(registrationData.getPassword());
        user.setActive(registrationData.isActive());
        
        return userRepository.save(user);
    }
    
    private void validateRegistrationData(UserRegistrationData data) {
        if (data.getFirstName() == null || data.getFirstName().trim().isEmpty()) {
            throw new IllegalArgumentException("First name is required");
        }
        if (data.getLastName() == null || data.getLastName().trim().isEmpty()) {
            throw new IllegalArgumentException("Last name is required");
        }
        if (data.getEmail() == null || !data.getEmail().matches("^[A-Za-z0-9+_.-]+@(.+)$")) {
            throw new IllegalArgumentException("Valid email is required");
        }
        // ... more validation logic
    }
    
    public void updateUserProfile(Long userId, UserRegistrationData profileData) {
        // Similar refactored logic
        // ... implementation
    }
}

Benefits of Introduce Parameter Object

Benefit

Description

Improved Readability

The method signature clearly shows what data is needed through the parameter object name, making it easier to understand the method's purpose and requirements.

Reduced Parameter Order Dependency

Parameters are grouped logically, eliminating the need to remember the exact order of many individual parameters and reducing the chance of passing parameters incorrectly.

Better Encapsulation

Related data is grouped together in cohesive objects, making the code more maintainable and allowing for easier validation and processing of related parameters.

When to Apply Introduce Parameter Object Refactoring

  • Methods with 4 or more parameters.

  • When parameters are logically related and often used together.

  • When parameter order is critical and error-prone.

  • When the same parameter groups are used across multiple methods.

  • When you want to improve method readability and maintainability.

Apply Introduce Parameter Object refactoring to one method with a long parameter list in your current project today. Start with the method that has the most parameters and is called most frequently.

Repository & Resources

Complete Code Examples: Clean Code Repository

Find the complete implementation of Long Parameter List refactoring and other clean code techniques in our dedicated repository. Each example includes:

  • Before and after code comparisons

  • Unit tests demonstrating the improvements

Found this helpful? Share it with a colleague who's struggling with long parameter lists. Have questions about refactoring parameter objects in your codebase? Email us directly, we read every message and the best questions become future newsletter topics.