As a developer, you've likely encountered situations where your carefully crafted code is rendered useless by a user's browser or environment limitations. It's as if the world outside Apiary has its own set of rules and constraints, leaving us to adapt and overcome.
In this lesson, we'll explore a technique that will help you write more resilient code: dev fallback graceful degradation. This approach ensures your application remains functional even when fancy APIs or features are unavailable, making it a valuable addition to any developer's toolkit.
The Technique
At its core, dev fallback is about anticipating potential failures and providing an alternative path forward. It involves three key components:
- Feature detection: Identify the specific feature or API being used and determine if it's available in the current environment.
- Polyfill (optional): If the feature is missing, provide a polyfill to enable basic functionality. This can be a custom implementation or a third-party library.
- Fallback UI: Design an alternate user interface that still provides value, even when the desired API or feature is unavailable.
By combining these elements, you create a robust system that degrades gracefully in the face of uncertainty.
Example 1: Using Web Storage
Let's say your application relies on web storage to store session data. However, older browsers may not support this feature. In this case:
function getSessionData() {
if ('sessionStorage' in window) {
// Modern browser, use web storage
return sessionStorage.getItem('data');
} else {
// Fallback: use a cookie or local storage alternative
const data = localStorage.getItem('data');
return data || '{}';
}
}
In this example, we first check if the sessionStorage property is available. If it is, we proceed with web storage. Otherwise, we fall back to using local storage.
Example 2: Using Fetch API
Imagine your application relies on the Fetch API for making HTTP requests. However, some older browsers may not support this feature:
function makeRequest(url) {
if (window.fetch) {
// Modern browser, use fetch API
return fetch(url)
.then(response => response.json())
.catch(error => console.error('Fetch error:', error));
} else {
// Fallback: use XMLHttpRequest or a library like Axios
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onload = () => {
if (xhr.status === 200) {
console.log(JSON.parse(xhr.responseText));
}
};
xhr.send();
}
}
Here, we check for the presence of the fetch function. If it's available, we proceed with the Fetch API. Otherwise, we fall back to using XMLHttpRequest.
Example 3: Using Web Font Support
Suppose your application relies on web fonts for its typography. However, older browsers may not support this feature:
function loadWebFonts() {
if ('FontFace' in window) {
// Modern browser, use @font-face rule
const font = new FontFace('Open Sans', 'url(https://example.com/open-sans.ttf)');
document.fonts.load(font);
} else {
// Fallback: use a generic font or a library like WebFont Loader
document.body.style.fontFamily = 'Arial, sans-serif';
}
}
In this example, we check for the presence of the FontFace property. If it's available, we proceed with loading the web font using the @font-face rule. Otherwise, we fall back to using a generic font.
When NOT to Use Dev Fallback
While dev fallback is a powerful technique, there are situations where it may not be necessary or desirable:
- When dealing with critical security features, such as encryption or authentication mechanisms.
- In cases where the feature or API is essential for core functionality and cannot be replicated through alternative means.
Related Apiary Lessons
- Feature detection: Learn how to detect specific browser features and adjust your code accordingly.
- Polyfills and shims: Discover how to create custom polyfills and shims to enable basic functionality in older browsers.
- Progressive enhancement: Understand the importance of progressive enhancement and how it relates to dev fallback.
Conclusion
Dev fallback is a vital technique for writing robust and resilient code. By anticipating potential failures and providing an alternative path forward, you can ensure your application remains functional even when fancy APIs or features are unavailable. Remember to balance feature detection, polyfills (if necessary), and fallback UI design to create a gentle degradation experience.
As the great Apiarian philosopher once said: "A bee's strength lies not in its wings, but in its ability to adapt to changing winds."