Don't Repeat Yourself
TL;DR: How to remove repeated code
Code Smell 11 - Subclassification for Code Reuse
Code Smell 232 - Reusable Code
Duplicated code is a severe code smell; it leads to maintainability problems and ripple effects.
Start by identifying behavior duplication.
Once you find it, you will extract it into reusable functions or classes, reducing redundancy, creating a single source of truth, and simplifying future updates.
Behavior duplication is a sign of a missing abstraction you need to create.
As always, you should search for it in the real world.
Refactoring isn't a one-time event; it's an ongoing process that should be integrated into your development workflow.
(This is the harder and not mechanical step)
(This is actual code generated by Google Gemini)
See a complete explanation in this talk
<?php
class AccessControlPanel {
private $users = [];
public function createRegularUser($username, $password, $email) {
$user = [
"username" => $username,
"email" => $email,
"type" => $this->regularUserRole(),
"creationDate" => $this->timeSource->currentTimestamp(),
"needsToChangePassword" = $this->needsToChangePassword(),
"loginPolicy" => $this->userLoginPolicy()
]
$this->users[] = $user;
$this->addCreationToJournal($user);
}
public function createAdminUser($username, $password, $email) {
$user = [
"username" => $username,
"email" => $email,
"type" => $this->regularUserRole(),
"creationDate" => $this->timeSource->currentTimestamp(),
"needsToChangePassword" = $this->needsToChangePassword(),
"loginPolicy" => $this->adminUserLoginPolicy()
]
$this->users[] = $user;
$this->addCreationToJournal($user);
return $user;
}
}
?>
<?php
class AccessControlPanel {
private $users = [];
// 1. Make a contextual copy of the repeated code
private function createUser(
$username,
$password,
$email,
$role,
$loginPolicy) {
$user = [
"username" => $username,
"email" => $email,
"type" => $role,
"creationDate" => $this->timeSource->currentTimestamp(),
"needsToChangePassword" => $this->needsToChangePassword(),
"loginPolicy" => $loginPolicy
];
$this->users[] = $user;
$this->addCreationToJournal($user);
return $user;
}
// 2. Parametrize what is different (in this case $role and $loginPolicy)
public function createRegularUser($username, $password, $email) {
// 3. Invoke the abstraction
return $this->createUser(
$username,
$password,
$email,
$this->regularUserRole(),
$this->userLoginPolicy());
}
public function createAdminUser($username, $password, $email) {
return $this->createUser(
$username,
$password,
$email,
$this->adminUserRole(),
$this->adminUserLoginPolicy());
}
// 4. Find a real-world metaphor for the abstraction
// private function createUser(
// $username,
// $password,
// $email,
// $role,
// $loginPolicy)
}
?>
The steps are defined but sometimes not about text duplication, but behavior duplication.
Since this is not a mechanical refactoring, you need good coverage on the code you modify.
You have a single source of truth, more compact code, and an easier-to-maintain solution.
This article is part of the Refactoring Series.