TL;DR: Avoid duplicate email validations.
Problems Addressed
Repeated email validation logic in multiple places.
Risk of inconsistent validation rules.
Bijection violation
Related Code Smells
Code Smell 122 - Primitive Obsession
Code Smell 66 - Shotgun Surgery
Code Smell 177 - Missing Small Objects
Code Smell 20 - Premature Optimization
Steps
Identify where email validation logic is duplicated.
Create an
Email Address
class to encapsulate validation rules.Refactor code to use the
Email Address
class instead of raw strings.
Sample Code
Before
public class Person {
private String emailAddress;
// Primitive Obsession
public void setEmailAddress(String emailAddress) {
// Duplicated code
if (!emailAddress.matches(
"^[\\w.%+-]+@[\\w.-]+\\.[a-zA-Z]{2,}$")) {
throw new IllegalArgumentException(
"Invalid email address format");
}
this.emailAddress = emailAddress;
}
}
public class JobApplication {
private String applicantEmailAddress;
public void setApplicantEmailAddress(String emailAddress) {
// Duplicated code
if (!emailAddress.matches(
"^[\\w.%+-]+@[\\w.-]+\\.[a-zA-Z]{2,}$")) {
throw new IllegalArgumentException(
"Invalid email address format");
}
this.applicantEmailAddress = emailAddress;
}
}
After
public class EmailAddress {
// 2. Create an `EmailAddress` class to encapsulate validation rules.
private final String value;
public EmailAddress(String value) {
// The rules are in a single place
// And all objects are created valid
if (!value.matches("^[\\w.%+-]+@[\\w.-]+\\.[a-zA-Z]{2,}$")) {
throw new IllegalArgumentException(
"Invalid email address format");
}
this.value = value;
}
}
public class Person {
private final EmailAddress emailAddress;
public Person(EmailAddress emailAddress) {
// 1. Identify where email validation logic is duplicated.
// 3. Refactor code to use the `Email Address`
// class instead of raw strings.
// No validation is required
this.emailAddress = emailAddress;
}
}
public class JobApplication {
private EmailAddress applicantEmailAddress;
public JobApplication(EmailAddress applicantEmailAddress) {
this.applicantEmailAddress = applicantEmailAddress;
}
}
Type
[X] Semi-Automatic
Safety
This refactoring is safe if you replace all occurrences of raw email strings with the 'EmailAddress' class and ensure all tests pass.
Why is the Code Better?
You make email validation consistent across your application.
Since validation rules are centralized in one place, the code becomes easier to maintain.
You also reduce the risk of bugs caused by inconsistent logic.
In the real world, Email Addresses
are small objects that exist and are not strings.
The refactored code is closer to the real world MAPPER.
Notice that bijection names are essential. It would help to create an EmailAddress
, not an Email
, since the Email should map to the actual message.
Don't let Premature Optimizators tell you this solution has a performance penalty.
They never do actual benchmarks with real world data.
Refactor with AI
Without Proper Instructions
With Specific Instructions
Tags
Encapsulation
Related Refactorings
Refactoring 007 - Extract Class
Refactoring 012 - Reify Associative Arrays
Refactoring 002 - Extract Method
Credits
Image by Gerd Altmann on Pixabay
This article is part of the Refactoring Series.