One Level of Abstraction: The Key to Clean Functions
56kode
Posted on October 29, 2024
Ever looked at a function and felt lost in its complexity? Let's explore a fundamental principle of clean code: functions should maintain only one level of abstraction.
Here's a real-world example of user creation in a web application:
// ❌ A function doing too many things at different abstraction levels
function createUser(userData) {
// Validate data
if (!userData.email || !userData.email.includes('@')) {
return 'Invalid email';
}
if (userData.password.length < 8) {
return 'Password too short';
}
// Hash password
const salt = generateSalt();
const hashedPassword = hashWithSalt(userData.password, salt);
// Format user data
const user = {
email: userData.email.toLowerCase(),
password: hashedPassword,
salt: salt,
createdAt: new Date()
};
// Save to DB
saveUserToDatabase(user);
}
This function mixes different levels of abstraction:
- High-level business logic (user creation flow)
- Mid-level operations (data validation, formatting)
- Low-level details (password hashing)
Let's refactor it following the single level of abstraction principle:
// ✅ Clean version with one level of abstraction
function createUser(userData) {
const validationError = validateUserData(userData);
if (validationError) return validationError;
const securePassword = hashPassword(userData.password);
const formattedUser = formatUserData(userData.email, securePassword);
return saveUserToDatabase(formattedUser);
}
function validateUserData({ email, password }) {
if (!email || !email.includes('@')) return 'Invalid email';
if (password.length < 8) return 'Password too short';
return null;
}
function hashPassword(password) {
const salt = generateSalt();
return {
hash: hashWithSalt(password, salt),
salt
};
}
function formatUserData(email, securePassword) {
return {
email: email.toLowerCase(),
password: securePassword.hash,
salt: securePassword.salt,
createdAt: new Date()
};
}
Benefits of This Approach
- Readability: The main function reads like a story, describing what happens at a high level
- Maintainability: Each function has a single responsibility, making changes safer
- Testability: You can test each piece of logic independently
- Reusability: These focused functions can be reused in other contexts
Key Takeaways
When writing functions:
- Keep them focused on one level of abstraction
- Extract complex operations into well-named functions
- Make the main function tell a story
- Think of each function as a single step in your process
Remember: If you're mixing "how" and "what" in the same function, you're probably dealing with multiple levels of abstraction. Split them up!
💖 💪 🙅 🚩
56kode
Posted on October 29, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
cleancode Avoiding Frontend Development Failure: Proven Practices for Writing Clean Code
October 1, 2024