because making even seemingly small and simple changes to the old version of the shop was extremely difficult and costly in terms of engineering time
?
Are the people who built browse bad developers?
NO!
// writing code is the easy bit
ADDING FEATURES IS THE HARD BIT
OK, we've got the first version of browse shipped! 🎉
OK, we've got the first version of browse shipped! 🎉
Now we're adding Essentials
OK, we've got the first version of browse shipped! 🎉
Now we're adding Essentials
Let's add the "SALE" pill
and before you know it...
computers are fantastic at understanding code
Â
humans...less so
writing code that computers understand is the easy part
writing code that humans understand is the hard part
const newFiltersetToUrl = ({
newFilterset,
categoryApplicableFilters,
oldMatchParams = {},
alwaysIncludeBaseUrl = false,
}) => {
const newUrlOfQueryParams = parseFilterSetToShopQueryParams(newFilterset);
/* see if we have just one top level category requiredId
* in which case we'll ditch it as a requiredID param
* and take the user to the nice URL for that category
*/
const { fromId } = whitelistedUrlsForCategories(categoryApplicableFilters);
const requiredIdsThatAreCategories = Array.from(
newFilterset.requiredIds
).filter(id => fromId.has(id));
const hadBrowseList = oldMatchParams.browseListId;
const newFiltersetHasBrowseList = newFilterset.requiredIds.has(
oldMatchParams.browseListId
);
const shouldSwapToNiceCategoryUrl =
newFiltersetHasBrowseList === false &&
requiredIdsThatAreCategories.length === 1;
const generateUrlToReturn = () => {
if (shouldSwapToNiceCategoryUrl) {
return generateUrlForMatchedCategory({
filterset: newFilterset,
fromId,
categoryId: requiredIdsThatAreCategories[0],
});
} else if (hadBrowseList && newFiltersetHasBrowseList) {
return generateUrlForBrowseList({
filterset: newFilterset,
browseListId: oldMatchParams.browseListId,
});
} else if (oldMatchParams.niceUrl || oldMatchParams.browseListId) {
// we had a nice URL before and now we don't
// so we need to put the baseUrl in here
return baseUrl + newUrlOfQueryParams;
} else {
/* but if we're here and are not sure how to deal with the URL change
* in a way that maintains the "nice" URLs
* let's just use query params, which will work totally fine
*/
return newUrlOfQueryParams;
}
};
const url = generateUrlToReturn();
if (url.includes(baseUrl) || alwaysIncludeBaseUrl === false) {
return url;
} else {
return baseUrl + url;
}
};
const generateUrlForBrowseList = ({ filterset, browseListId }) => {
const newUrlForBrowseList = urlForBrowseList(browseListId);
const filtersetWithBrowseListRemoved = mapFilterset(filterset, filterset => {
filterset.requiredIds = filterSet(
filterset.requiredIds,
id => id !== browseListId
);
return filterset;
});
const newQueryParams = parseFilterSetToShopQueryParams(
filtersetWithBrowseListRemoved
);
return newUrlForBrowseList + (newQueryParams === '?' ? '' : newQueryParams);
};
const generateUrlForMatchedCategory = ({ filterset, fromId, categoryId }) => {
// take the user to the nice URL for this category
const newUrlForCategory = baseUrl + fromId.get(categoryId);
// now we remove that requiredId
const filtersetWithCategoryIdRemoved = mapFilterset(filterset, filterset => {
return {
...filterset,
requiredIds: filterSet(filterset.requiredIds, id => id !== categoryId),
};
});
const newQueryParams = parseFilterSetToShopQueryParams(
filtersetWithCategoryIdRemoved
);
return newUrlForCategory + (newQueryParams === '?' ? '' : newQueryParams);
};
export default newFiltersetToUrl;
Tear it down and start again
time
ground up rewrite
value added
time to reach feature parity
shipped and building new features
?
So how do we avoid constant rewrites?
time
incremental improvements
value added
incremental improvements
and feature shipping
time
incremental improvements
value added
incremental improvements
and feature shipping
feature parity + then new features
Writing code with the future in mind
We cannot predict the future
this isn't how it normally goes!
we just need to quickly add feature X in time for the next sale
0.5 days
2 days
so this is better for the code...but is it better for the company?
Uncomfortably Fast
Tech work and investigation
This tension is good!
TECH
DEBT
Cutting corners to let us ship today
TECH
DEBT
SHIPPING
PACE
TECH
DEBT
SHIPPING
PACE
TECH
DEBT
SHIPPING
PACE
TECH
DEBT
SHIPPING
PACE
Time to rewrite!
How do we avoid getting to this stage?
knowing when to take the time to place these bricks is hard
Past Jack
Present Jack
Future Jack
(Well, Jack's dad)
Past Jack
Present Jack
Future Jack
(Well, Jack's dad)
Past Jack makes a lot of mistakes
Past Jack
Present Jack
Future Jack
(Well, Jack's dad)
Present Jack learns from those mistakes
Past Jack
Present Jack
Future Jack
(Well, Jack's dad)
to hopefully make Future Jack's life easier
Was that decision I made on the shop the right one?
Where am I?!
Q&A?
Shop L&L Thread
By Jack Franklin
Shop L&L Thread
- 918