This content originally appeared on Bits and Pieces - Medium and was authored by Ashan Fernando
Why Fault Isolation and Component Reusability Are Key to Building Robust Microfrontends
As software systems scale, ensuring reliability while keeping the speed of delivery becomes pivotal. To achieve this, a widely accepted practice is to distribute the development and ownership into smaller teams with more autonomy. In the frontend world, this is achieved by using micro frontends.
Microfrontends break down monolithic frontend applications into smaller, manageable pieces that allow different teams to work independently.
Yet there are many challenges teams need to overcome in terms of properly setting up the frontend architecture to reduce friction between the teams and boundaries while ensuring a cohesive and reliable integration of micro frontends.
This article explores two key architectural patterns — Cell Architecture and Composable Architecture that fundamentally address these challenges. Cell Architecture focuses on fault isolation, ensuring that failures in one part of the system don’t impact the rest. At the same time, Composable Architecture emphasizes building reusable, modular components that can be composed together to create software systems.
Understanding Cell Architecture and Fault Tolerance
Cell Architecture is inspired by the concept of bulkheads in ships, which contain damage within one compartment to prevent the spread of failures. In software systems, cells are units that handle specific functionality. These cells may consist of a limited number of components. Each cell operates independently, with its own set of resources, and failures within one cell are isolated to that cell alone.
How Cell Architecture Helps Manage Failures in Microfrontends
Microfrontends often require independent teams to work on separate parts of the frontend. Without fault isolation, a single failure in one part of the system could bring down the entire application. Failures in microfrontends can occur in various forms:
- Build-time errors: Version mismatches, dependency issues, and interface discrepancies can cause build failures.
- Runtime errors: Issues like failed API calls, script loading errors, or unhandled exceptions can cause parts of the frontend to crash.
- Security vulnerabilities: Without proper isolation, a compromised component can expose the entire system to security risks.
Cell Architecture helps manage these risks by isolating functionality within distinct cells so that failures are contained and do not affect the rest of the application. For example, if a cell managing user authentication fails, other application parts, such as product browsing or checkout, continue to function without disruption.
Example of Fault Isolation in Microfrontends
Consider an e-commerce platform where the frontend makes several API calls to fetch user data, product information and handle payments. If an API call to retrieve user data fails, the entire frontend could crash or display a blank page.
With Cell Architecture, you can isolate this error to the User Data Cell as follows.
- Graceful error handling: The User Data Cell can display a fallback error message without disrupting the rest of the application.
- Retry mechanisms: For network-related failures, the system can retry the operation, allowing other cells to remain unaffected.
- Preventing cascading failures: If the User Data Cell fails, other cells like the Product Display or Checkout Cells continue to function.
This ensures that even if one part of the system encounters an issue, the rest of the application remains operational.
The Power of Composability in Microfrontends
Composable Architecture takes modularity one step further by enabling developers to create applications from independent, reusable components. This design philosophy allows teams to build smaller, self-contained components that can be combined to form more complex systems.
In a composable architecture, components are designed to be modular and reusable. For instance, a ButtonComponent or a UserProfileComponent can be reused across multiple microfrontends. This reduces duplication and ensures consistency across the application. Composability allows developers to make targeted updates to individual components and their dependents without affecting the entire system.
Benefits of Composable Architecture:
- Reduced duplication: Common UI components, such as buttons or forms, are reused across different parts of the system, improving development speed and consistency.
- Clear boundary: Each component has well-defined interfaces with clear boundaries.
- Improved maintainability: Changes to components are isolated, making updates easier to manage without needing full application testing.
- Enhanced collaboration: Teams can work independently on different components, reducing the risk of breaking changes and improving productivity.
- Uniform architecture style: The fundamental unit is a component in composable architecture. These components can be composed together to build complex components all the way up to the final application.
How Cell Architecture and Composability Work Together
Cell Architecture and Composable Architecture have a unique relationship with Microfrontends.
- The Composable Architecture breaks the application code into discrete sets of components and their compositions.
- We can group these components by microfrontends with ownership for independent teams.
- Cell Architecture can identify compositions of components (sub-groups) within each microfrontend that requires fault isolation.
For example, a user management cell could consist of several components:
- UserProfileComponent: Displays user details.
- UserSettingsComponent: Manages user preferences.
- UserDataComponent: Fetches user data from an API.
These components work together to form a single, self-contained user management cell. If an error occurs within this cell, such as an API failure in UserDataComponent, the error is contained and doesn’t affect other parts of the system, like product browsing or checkout processes.
Example: Isolating an API Call with React and Cell Boundaries
Here’s a practical example of how Cell and Composable Architecture work together in a React-based microfrontend.
import React, { useState, useEffect } from 'react';
// A reusable React component that fetches user data
const UserDataComponent = ({ userId }) => {
const [userData, setUserData] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchUserData = async () => {
try {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
setUserData(data);
} catch (error) {
setError(error.message);
} finally {
setLoading(false);
}
};
fetchUserData();
}, [userId]);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return (
<div>
<h1>{userData.name}</h1>
<p>Email: {userData.email}</p>
</div>
);
};
export default UserDataComponent;
In this example, UserDataComponent is a single component within a cell. If the API call fails, the error is handled gracefully within the component, preventing the failure from affecting other parts of the system. The rest of the frontend continues to function.
In this case, the cell boundary maps directly to the component boundary in composable architecture. This approach ensures fault isolation and allows granular control over system behavior.
Identifying Fault Boundary with Dependency Graph and Isolated Builds
Whenever a failure is detected in the frontend application, if it is a bug in a microfrontend, we need to identify the cell and the components responsible for it.
This is where the dependency graph of components becomes useful. Following is an example of the dependency graph when implementing composable architecture using Bit platform.
Dependency Graph
The dependency graph is a visual tool provided by Bit that shows how components are connected and how changes in one component affect others. It allows developers to:
- Visualize dependencies: Understand the relationships between components, which helps identify the ripple effects of a failure or change.
- Simplify maintenance: Quickly identify which components depend on a faulty component and isolate the issue.
Isolated Builds
Once the issue is fixed, ensuring all the affected components are tested and built before releasing a fix is important.
Ripple CI is a feature in Bit that ensures only the affected components and their dependents are rebuilt when changes are made. This drastically reduces the time needed for testing and deployment, as the entire application doesn’t necessarily need to be rebuilt or tested.
Here’s how Ripple CI works:
- Identify affected components: Bit’s dependency graph shows how components are interconnected. If UserDataComponent fails, it identifies which other components are dependent on it.
- Isolate builds: Ripple CI isolates the build process to just the modified components and their dependents, reducing build time and minimizing the risk of introducing new issues.
- Faster testing and deployment: By focusing only on the affected parts of the system, Ripple CI allows for faster testing and more efficient deployments.
Conclusion
Developers can build reliable, scalable, and fault-tolerant microfrontend systems by combining Cell and Composable Architecture styles. Cell Architecture ensures that failures are isolated within specific system parts, while Composable Architecture allows for modularity and reusability across different microfrontends.
With its dependency graph and Ripple CI, platforms like Bit help streamline the development process by isolating builds and reducing deployment time.
These architectures and tools enable teams to build resilient systems that scale efficiently while maintaining high reliability and fault tolerance.
Thanks for reading !!
Learn More
- Composable Software Architectures are Trending: Here’s Why
- Design Principles for Composable Architectures
- How “Code Reuse” Affects Different Architecture Styles
- 6 Patterns for Microfrontends
- Increasing Agility in Microfrontend Design: A Developer’s Guide
Composability Meets Cell Architecture: How to Develop Resilient Microfrontends was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.
This content originally appeared on Bits and Pieces - Medium and was authored by Ashan Fernando
Ashan Fernando | Sciencx (2024-09-06T13:31:39+00:00) Composability Meets Cell Architecture: How to Develop Resilient Microfrontends. Retrieved from https://www.scien.cx/2024/09/06/composability-meets-cell-architecture-how-to-develop-resilient-microfrontends/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.