visit
export async function updateUserHandle(handle) {
if (!isLoggedIn()){
// redirect to login screen
return;
}
let token = localStorage.getItem(jwtKey);
let decodedToken = decodeJWT(token);
const hoursDelta = 24;
if (decodedToken.exp < (Date.now() + hoursDelta*60*60) / 1000){
refreshToken();
}
return await fetch(`${domain}/v1/users/handle`, {
method: 'PUT',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
handle
})
});
}
export async function updateUserInterests(interestUUIDs) {
if (!isLoggedIn()){
// redirect to login screen
return;
}
let token = localStorage.getItem(jwtKey);
let decodedToken = decodeJWT(token);
const hoursDelta = 24;
if (decodedToken.exp < (Date.now() + hoursDelta*60*60) / 1000){
refreshToken();
}
return await fetch(`${domain}/v1/users/interests`, {
method: 'PUT',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
interestUUIDs
})
});
}
You may have noticed that the beginning of those two API calls are nearly identical - the first few lines check to see if a user is properly authenticated and sends authentication data in the respective requests. This might not be a big problem with just 2 API calls, but what if we have 30? Or maybe 1000? Instead, we can DRY up this code by writing a simple fetchWithAuth()
function that centralizes all the client’s authentication logic in a single place:
async function fetchWithAuth(url, params){
if (!isLoggedIn()){
// redirect to login screen
return;
}
let token = localStorage.getItem(jwtKey);
let decodedToken = decodeJWT(token);
const hoursDelta = 24;
if (decodedToken.exp < (Date.now() + hoursDelta*60*60) / 1000){
refreshToken();
}
if (!params.headers){
params.headers = {};
}
params.headers.Authorization = `Bearer ${token}`;
return await fetch(url, params);
}
export async function updateUserHandle(handle) {
return await fetchWithAuth(`${domain}/v1/users/handle`, {
method: 'PUT',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
handle
})
});
}
export async function updateUserInterests(interestUUIDs) {
return await fetchWithAuth(`${domain}/v1/users/interests`, {
method: 'PUT',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
interestUUIDs
})
});
}
Sometimes two pieces of code happen to be the same at a given point in time, but later on, they become distinct in some way. It’s really hard to guarantee that duplicate blocks of code will remain perfect copies of each other forever. A hypothetical example of this would be if the Facebook and Instagram APIs had the exact same way to create a social post. Just because they’re coincidentally the same, probably doesn’t mean that the logic should only be written once.
One day, Instagram might introduce something really dumb like “filters” or “stories” and all of a sudden the common abstraction needs crazy flags and parameters like:
is_story
is_instagram
filter_enum
… and those flags make the logic do different things depending on whether it’s a Facebook or an Instagram post.
The solution is likely for you to remain disciplined about spitting out code that, while it may be similar now, is only coincidentally similar. We should try to only merge code that’s fundamentally the same. A great example would be a math function like log2
. That function should work for every case where you need to calculate a logarithm - each calculation of a log is fundamentally the same.
START PROGRAM
INSTRUCTION 0
INSTRUCTION 1
INSTRUCTION 2
INSTRUCTION 3
END PROGRAM
With a highly compartmentalized project, when we see a function called getUser()
, if we want to really know what’s going on we have to peek into that function and remember the external calling context because we’re now looking at an entirely different file. The cognitive burden becomes greater and greater the more definitions we need to jump through to grok a single logical pathway.
WET stands for “write everything twice”, and forces you to think a bit harder about whether or not a piece of logic deserves an abstraction. The rule of three is an alternative that says you should wait until you’ve written something three times before breaking it out.
function getArea(height, width){
return height * width
}
function getArea(height, width, isTriangle){
if (isTriangle){
return (height * width) / 2
}
return height * width
}
function getTriangleArea(height, width){
return (height * width) / 2
}
function getRectangleArea(height, width){
return height * width
}