14 - [Design patterns series] - The Facade

Hey there my little nerds, me again carrying on with my mission to write the most easy-to-digest and understandable series of posts on design patterns, and today we’re going to be looking at the Facade pattern.

The Facade pattern is one of the most satisfying patterns to use, because it simplifies your code a lot, and it also makes it easier to change.

To understand what the Facade pattern is, let’s start with the definition of the word “Facade” - “a deceptive outward appearance. “.

I bet you’ve already used this pattern without even knowing it’s called a facade.

The Facade Pattern

Let’s travel back to the early 2000’s and go back to our job as an engineer at MySpace. Things are going great for us and we’re the number one social media platform in the world, before even the definition of “social media” existed. Cousin, business is boomin’!

We’re working on a new feature for MySpace, where we’re allowing our users to put a list of their favourite last.fm songs on their profile page. Somehow we have great browser API’s in 2005 like ‘fetch’, and we basically want to call the last.fm API and display the list of songs for our user, and then call the API again for a single song, so our user can set it on their profile. Our code might look like this: [disclaimer, this is a mock last.fm API, not the real thing]:

function getAllUserSongs(userId: string) {
    return fetch(`https://api.last.fm/v1/songs/${userId}`, {
        method: 'GET',
        headers: {'Content-Type': 'application/json'}
    }).then(res => res.json());
}

function getSingleSong(songId: number) {
    return fetch(`https://api.last.fm/v1/songs/${songId}`, {
        method: 'GET',
        headers: {'Content-Type': 'application/json'}
    }).then(res => res.json());
}

function setSongForUser(userId: string, songId: number) {
    getAllUserSongs(userId).then(
        songs => getSingleSong(songs.find(song => song.songId === songId))
    );
}

Now, as you can see this is not very maintainable code, as first, the fetch API might be simple to use, but it takes a a bunch of parameter setting such as the method,the headers, the URL etc, but imagine if the function we were using wasn’t fetch, but was some very complicated code we’d have to set up every time we needed to use it.

Again, if we needed to make changes or use a different api than fetch, we’d have to change all of our methods that use fetch, and that can and will lead to human error, not to mention that we’d spend extra time on the feature. When I write code, I like to make it as simple as possible and super easy to change and evolve over time.

Let’s see what we can do to refactor our code here by using the Facade Pattern:

// our Facade function that will call the fetch API
function getLastFMResource(url: string, param: string): Promise {
    return fetch(`${url}/${param}`, {
        method: 'GET',
        headers: {'Content-Type': 'application/json'}
    }).then(res => res.json())
}


// We refactor our get user songs and get single song functions to use the facade function
function getAllUserSongs(userId: string) {
    return getLastFMResource('https://api.last.fm/v1/songs', userId);
}

function getSingleSong(songId: number) {
    return getLastFMResouce('https://api.last.fm/v1/songs', songId);
}

// our remaining code remains the same

function setSongForUser(userId: string, songId: number) {
    getAllUserSongs(userId).then(
        songs => getSingleSong(songs.find(song => song.songId === songId))
    );
}

Wow. Our code became so much simple and DRYer just by implementing our lil Facade function. And the best thing is, if we want to use axior or some new hot shot library, we just need to update our facade function:

function getLastFMResource(url: string, param: string): Promise {
    return axios({
        method: 'get',
        url: `${url}/${param}`
    });
}

And then the rest of the code that is already using our facade becomes super easy to change!

Conclusion

Like I said, you’ve probably used the Facade pattern more than once without even realising it was a thing. It’s a great way to reduce complexity in your code and have facade functions interact with complicated code. And here’s something meta about this post and it’s examples - the fetch is actually a facade itself. So we’ve been using a facade for a facade. Let that sink in.

Until next time!


Written by Emil Mladenov - a slavic software developer who decided to use a blog as a digital rubber duck

I also have a podcast