Data Clumps
Description (What)
An identical group of variables show up repeatedly.
These could be variables for connecting to a database, a client or repeatedly being passed across methods
How to Locate It (Where)
Look for repeated sets of variables in method arguments
How It Manifests (Why)
It's often easier to keep sending the list of variables to different functions.
It could also be due to 'copypasta programming'.
How to Fix It (Possible Treatments)
In Example 1, Extract Class is used to create a new class for the data clumps and the new class is passed in method arguments instead of the variables separately.
We want to be able to reduce the amount of parameters we pass to methods and also by passing an object of a class created for parameters, we make it easier to change anything about the parameters themselves in a single place instead of in all methods that take those parameters.
In Example 2, the pair of start date and end date are appearing frequently inside the parameters, then we consider Introduce Parameter Object
to wrap it as a Object, reducing the number of parameters.
Other treatments are also possible based on the specific scenario, they can be found here
Examples
Example 1
Before:
The connection variables for the MongoDB connection are an identical group of variables that need to be grouped together.
Observed Code Smells:
- Data Clumps (lines 2-5)
After:
Applied Extract Class on the variables to create their own class to be passed to the actual connecting class
Refactoring Applied:
- Data Clumps
- Extract Class (MongoDbConnectionVariables)
Observed Code Smells After Refactoring:
- None
Example 2
Before:
There are several pair of start and end dates of type Date appearing in the parameters.
No matter it is a start date for amounts, checking for overlaps or leases, they are a pair of data which can be introduced
as a Paramter Object.
After:
Apply Introduce Parameter Object by creating a new class called DateRange,
encapsulating both start and end of type Date and check for overlaps by passing in another DataRange instance.
Refactoring Applied:
- Data Clumps:
- Introduce Parameter Object (line 7-21, line 28, line 32, line 42, line 52, line 67)
Observed Code Smells After Refactoring:
- None
When to Ignore
In cases where passing an object in method parameters might create an undesirable dependency between two classes
More
- Example 1
- Example 2
- Before
- After
001 enum ConnectionState {002 CONNECTED,003 FAILURE,004 NOTCONNECTED005 }006007 class MongoDBConnector {008 private ConnectionState state;009010 public MongoDBConnector() {011 this.state = ConnectionState.NOTCONNECTED;012 }013014 public boolean isCredentialsValid(int port, String host, String username, String password) {015 if (port < 0 || port > 65535) {016 throw new IllegalArgumentException("Port is invalid");017 }018019 if (!host.startsWith("http")) {020 throw new IllegalArgumentException("Host is invalid");021 }022023 return true;024 }025026 public boolean testConnection(int port, String host, String username, String password) {027 if (Math.random() > 0.1) {028 System.out.println("Connection to: " + host + ":" + port + "/" + username + "&" + password + "successful");029 return true;030 } else {031 System.out.println("Connection to: " + host + ":" + port + "/" + username + "&" + password + "failed");032 return false;033 }034 }035036 public void connectToDatabase(int port, String host, String username, String password)037 throws IllegalArgumentException {038 if (!isCredentialsValid(port, host, username, password)) {039 this.state = ConnectionState.FAILURE;040 throw new IllegalArgumentException("Invalid database credentials");041 }042043 System.out.println("Testing connection...");044045 if (!testConnection(port, host, username, password)) {046 this.state = ConnectionState.FAILURE;047 throw new IllegalArgumentException(048 "Failed trying to connect to database: " + host + ":" + port + "/" + username + "&" + password);049 }050051 System.out052 .println("Connection to database estabilished: " + host + ":" + port + "/" + username + "&" + password);053 this.state = ConnectionState.CONNECTED;054 }055056 public String getCurrentState() {057 return "State: " + this.state;058 }059 }060061 public class DCBE1 {062 public static void main(String[] args) {063 MongoDBConnector mongodb = new MongoDBConnector();064 mongodb.connectToDatabase(27017, "http://localhost", "yash", "fn023uc");065 }066 }067