TIL Cleaner Functions
POSTED ON:
TAGS: cleancode functions patterns
This is absolutely beautiful.
I was reading Writing Clean JavaScript and I usually get one or two take-aways.
This had so many take-aways, I had to break it into two posts.
Like any 'clean code', they're kinda rules of thumbs, and opinionated.
I like these opinions.
How to write Cleaner functions #
Limit the number of arguments #
// Don't ❌
function sendPushNotification(title, message, image, isSilent, delayMs) {
// ...
}
sendPushNotification("New Message", "...", "http://...", false, 1000);
// Do ✅
function sendPushNotification({ title, message, image, isSilent, delayMs }) {
// ...
}
const notificationConfig = {
title: "New Message",
message: "...",
image: "http://...",
isSilent: false,
delayMs: 1000,
};
sendPushNotification(notificationConfig);
Very opinionated. Why is this better?
Because after 3 arguments, who knows how much it'll grow? And worst, you'll have to remember the order of your arguments.
By having your function consume a object, it'll allow you to:
- Add as many arguments as you want inside your object
- The order doesn't matter
Avoid executing multiple actions in a function #
// Don't ❌
function pingUsers(users) {
users.forEach((user) => {
const userRecord = database.lookup(user);
if (!userRecord.isActive()) {
ping(user);
}
});
}
// Do ✅
function pingInactiveUsers(users) {
users.filter(!isUserActive).forEach(ping);
}
function isUserActive(user) {
const userRecord = database.lookup(user);
return userRecord.isActive();
}
The original is tightly coupled. It's not wrong, and I have a lot of personal code just like.
The improved version makes the functions more 'atomic'. That allows us to start thinking in Higher-order functions, where we pass functions into function arguments to do some really magical things!
Avoid mutation #
// Don't ❌
// This one mutates the data directly
function enrollStudentInCourse(course, student) {
course.push({ student, enrollmentDate: Date.now() });
}
// Do ✅
// This passes back an array, with the original course, and the new change.
function enrollStudentInCourse(course, student) {
return [...course, { student, enrollmentDate: Date.now() }];
}
Avoiding non-negatives #
// Don't ❌
function isUserNotVerified(user) {
// ...
}
if (!isUserNotVerified(user)) {
// ...
}
// Do ✅
function isUserVerified(user) {
// ...
}
if (isUserVerified(user)) {
// ...
}
The !
reverses things.
By writing functions that return false, you end up with weird boolean like !false
which means true, which gets really hard to read.
Return Early #
// Don't ❌
function addUserService(db, user) {
if (!db) {
if (!db.isConnected()) {
if (!user) {
return db.insert("users", user);
} else {
throw new Error("No user");
}
} else {
throw new Error("No database connection");
}
} else {
throw new Error("No database");
}
}
// Do ✅
function addUserService(db, user) {
if (!db) throw new Error("No database");
if (!db.isConnected()) throw new Error("No database connection");
if (!user) throw new Error("No user");
return db.insert("users", user);
}
Related TILs
Tagged: cleancode