Converting your anemic dictionaries is easy
TL;DR: Convert your key/value into full behavioral objects
Problems Addressed ๐
- Associative arrays
- Fail Fast principle violation
- Bijection Fault
- Hard to find method references
Related Code Smells ๐จ
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-vi-cmj31om?embedable=true
Context ๐ฌ
You have anemic associative arrays that hold unstructured data.
You want richer objects with stricter controls.
Static typed languages can also add type checking to these objects.
Steps ๐ฃ
- Find the references to the object or associative array
- Reify it
- Replace generic calls with setters and getters for every key.
You can also debug them better this way.
- Add parameter and return type hinting to interfaces.
Do this if your language supports it.
- Add stronger assertions on the setters between different keys.
(if you are using TCR, you can do baby refactoring steps)
Sample Code ๐ป
Before ๐จ
<?
class AuthenticationHelper extends Singleton {
private $data = [];
function setParameter(string $key, ?$value) {
// no type checking
// value as the name is too generic
// Since SOME parameters might be null
// You can't check a single parameter for not null
$this->data[$key] = value;
}
function getParameter(string $key) {
// no return type hinting
return $this->data[$key] ?? null;
}
}
// Usages
AuthenticationHelper::getInstance
->setParameter('oauth2_token', []);
// type error not caught
AuthenticationHelper::getInstance
->setParameter('scopes', null);
// We need to enforce this not to be NULL
AuthenticationHelper::getInstance
->setParameter('user', 'Elon');
// This should not mutate
// No validation with business rules
$credential =
AuthenticationHelper::getInstance
->getParameter('oauth2token');
// Typo not detected
// You can not easily find
// references to methods setting the oauth2_token
After ๐
<?
class AuthenticationCredentials {
private $user;
private $oauth2_token;
function __construct(User $user) {
$this->validateUser($user);
// Specific validation rules
$this->user = $user;
// Can't mutate
}
function oauth2_token(string $token): void {
// You can add specific validations
$this->oauth2_token = $token;
}
function oauth2_token(): string {
// Return type hinting
return $this->oauth2_token;
}
}
// Usages
$credentials = new AuthenticationCredentials(new User('Elon'));
// Valid since creation
$credentials->oauth2_token([]);
// type errors are caught
$credentials->oauth2_token(null);
// can't be null. Fail fast
$credentials->scope();
// Typo detected
Now, you have an anemic data class.
Also known as aย DTO.
It is time to give it behavior.
You can also remove some getters and setters.
Type ๐
[X] Semi-Automatic
You can perform this refactor with the aid of an IDE.
Safety ๐ก๏ธ
This is not an automatic refactoring.
Small steps are safe if you have good coverage.
Why is the Code Better? โจ
Your new object fails fast and is more declarative.
You can debug it easily and find the referencing methods.
How Does it Improve the Bijection? ๐บ๏ธ
An associative array is a generic container with no real-world meaning.
Its keys are strings that could hold anything, valid or not.
A reified object gives each key a name, a type, and a purpose.
Code should map to the real world, following theย Bijectionย principle.
Every concept in the domain needs a counterpart in the code.
That is the core idea behind theย MAPPER.
The new object’s name and methods describe what it represents.
Limitations โ ๏ธ
Dynamically typed languages can’t enforce type or domain restrictions.
This applies to the values inside the object.
Tags ๐ท๏ธ
- Anemic Models
Level ๐
[X] Beginner
Related Refactorings ๐
https://hackernoon.com/improving-the-code-one-line-at-a-time?embedable=true
Refactor with AI ๐ค
Suggested Prompt: 1. Find the references to the object or associative array.2. Reify it into a full object.3. Replace generic calls with setters and getters for every key.4. Add parameter and return type hinting to interfaces.5. Add stronger assertions between different keys.
Without Proper Instructions ๐ต
With Specific Instructions ๐ฉโ๐ซ
Conclusion ๐
Associative arrays are convenient until they grow into hidden domain models.
Once several parts of your code read and write the same keys, reify them.
A dedicated object turns implicit rules into explicit, testable behavior.
You gain type safety, fail-fast validation, and traceable references.
See also ๐
https://refactoring.guru/replace-data-value-with-object?embedable=true
Credits ๐
Image byย MustangJoeย fromย Pixabay
This article is part of the Refactoring Series.
https://maximilianocontieri.com/how-to-improve-your-code-with-easy-refactorings