An Introduction To Full Stack Composability
This article has been kindly supported by our dear friends at Storyblok, a friendly headless CMS with a visual editor, nested components and customizable content blocks for websites and apps. Thank you!
Composability is not only about building a design system. We should create and manage reusable components in the frontend and the UX of our website, as well as coordinate with the backend and the content itself.
In this article, we’ll discuss how to go through both the server and the client sides of our projects and how to align with the content that we’ll manage. We’ll also compare how to implement composable logic into our code using different approaches provided by React-based frameworks like Remix and Next.js.
Composable Architecture
In the dynamic landscape of web development, the concept of composability has emerged as a key player in crafting scalable, maintainable, and efficient systems. It goes beyond merely constructing design systems; it encompasses the creation and management of reusable components across the entire spectrum of web development, from frontend UX to backend coordination and content management.
Composability is the art of building systems in a modular and flexible way. It emphasizes creating components that are not only reusable but can seamlessly fit together, forming a cohesive and adaptable architecture. This approach not only enhances the development process but also promotes consistency and scalability across projects.
We define “composable architecture” as the idea of building software systems from small, independent components that you can combine to form a complete system. Think of a system as a set of LEGO pieces. Putting them together, you can build cool structures, figures, and other creations. But the cool thing about those blocks is that you can exchange them, reuse them for other creations, and add new pieces to your existing models.
Parts Of A Composable Architecture
To manage a composable architecture for our projects, we have to connect two parts:
Modular Components
Break down the system into independent, self-contained modules or components. Modular components can be developed, tested, and updated independently, promoting reusability and easier maintenance.
When we talk about modular components, we are referring to units like:
- Microservices
The architectural style for developing software applications as a set of small, independent services that communicate with each other through well-defined APIs. The application is broken down into a collection of loosely coupled and independently deployable services, each responsible for a specific business capability. - Headless Applications
In a headless architecture, the application’s logic and functionality are decoupled from the presentation layer, allowing it to function independently of a specific user interface. - Packaged Business Capabilities (PBC)
A set of activities, products, and services bundled together and offered as a complete solution. It is a very common concept in the e-commerce environment.
APIs
As the components of our architecture can manage different types of data, processes, and tasks of different natures, they need a common language to communicate between them. Components should expose consistent and well-documented APIs (Application Programming Interfaces). An API is a set of rules and protocols that allows one software application to interact with another. APIs define the methods and data formats that applications can use to communicate with each other.
Benefits Of A Composable Architecture
When applying a composable approach to the architecture of our projects, we will see some benefits and advantages:
- Easy to reuse.
Components are designed to be modular and independent. This makes it easy to reuse them in different parts of the system or entirely different systems. Reusability can significantly reduce development time and effort, as well as improve consistency across different projects. - Easy to scale.
When the demand for a particular service or functionality increases, you can scale the system by adding more instances of the relevant components without affecting the entire architecture. This scalability is essential for handling growing workloads and adapting to changing business requirements. - Easy to maintain.
Each component is self-contained. If there’s a need to update or fix a specific feature, it can be done without affecting the entire system. This modularity makes it easier to identify, isolate, and address issues, reducing the impact of maintenance activities on the overall system. - Independence from vendors.
This reduces the dependence on specific vendors for components, making it easier to switch or upgrade individual parts without disrupting the entire system. - Faster development and iteration.
Development teams can work on different components concurrently. This parallel development accelerates the overall development process. Additionally, updates and improvements can be rolled out independently.
The MACH Architecture
An example of composability is what is called the MACH architecture. The MACH acronym breaks down into Microservices, API-first, Cloud-native, and Headless. This approach is focused on applying composability in a way that allows you to mold the entire ecosystem of your projects and organization to make it align with business needs.
One of the main ideas of the MACH approach is to let marketers, designers, and front-end developers do their thing without having to worry about the backend in the process. They can tweak the look and feel on the fly, run tests, and adapt to what customers want without slowing down the whole operation.
With MACH architecture, getting to an MVP (minimum viable product) is like a rocket ride. Developers can whip up quick prototypes, and businesses can test out their big ideas before going all-in.
MACH also helps to resolve poor web performance, using improved services and tools that apply specifically to each one of the different components of your organization’s ecosystem. For example, in the e-commerce game, time is money — those old-school sites using monolithic platforms lose sales to the speedy and flexible ones built with a composable approach. MACH lets you create a custom IT setup using the hottest tech out there.
Composability With React
We can dive deeper and transfer the same composability concept to the implementation of the user interface and experience of our application. React encourages developers to break down user interfaces into small, reusable components that can be composed together to create complex UIs. Each React component is designed to encapsulate a specific piece of functionality or user interface element, promoting a modular and composable architecture. This approach facilitates code reuse, as components can be easily shared and integrated into various parts of an application.
React’s component-based architecture simplifies the development process by allowing developers to focus on building small, self-contained units of functionality. These components can then be combined to create more sophisticated features and build new “higher-level” components. The reusability of React components is a key benefit, as it promotes a more efficient and maintainable codebase. With this idea in mind, we can build design systems for our projects, as well as following approaches like the Atomic Design principle.
Going Full Stack
But we can go even further and apply the composable approach to our backend and server-side logic, too. React-based frameworks, such as Remix and Next.js, provide powerful tools for implementing composability in web applications while getting the best from different rendering approaches, such as server-side rendering and static generation. Let’s see a couple of concepts applied in both Next.js and Remix that can help us implement server logic while keeping the composability of our code.
Full Stack Composability with Next.js: React Server Components
React Server Components were introduced by the React team to address challenges related to server-rendered content and enhance the composability of React applications. Composability, in the context of React Server Components, refers to the ability to break down a user interface into smaller, reusable units that can be efficiently managed on the server side. React Server Components take the idea of composability a step further by allowing certain components to be rendered and processed on the server rather than the client. This is particularly useful for large-scale applications where rendering everything on the client side might lead to performance bottlenecks.
Next.js, a React-based framework, includes React Server Components as the default approach when creating and managing components on a project, since its version 13. Some of the benefits identified when using React Server Components are:
- Move data fetching operations to the server, closer to the data source. This also reduces the amount of requests the client needs to make while using the power of processing the web servers offer, compared to the processing capacity of the client devices.
- Better security when managing and rendering content.
- Better caching strategies.
- Improved Initial Page Load and First Contentful Paint (FCP).
- Reduce bundle sizes.
Full Stack Composability With Remix: Full Stack Components
One of Remix’s key principles is the ability to create composable route components, allowing developers to build complex user interfaces by combining smaller, self-contained pieces.
Kent C. Dodds, a very valuable member of the dev community, introduced the concept of Full Stack Components to describe the way the Remix framework allows the developers to create components, encapsulating the data fetching and processing they require and involve, in a single file or module that manages both client-side and server-side logic.
With the help of Loader and Action functions, in addition to the Resource Routes, Remix allows developers to add server-side logic, like fetching or data mutations, on the same file where we define the visual representation of the component.
Aligning With The Content
Finally, one of the challenges in web development is aligning the composability of our architecture and presentation layer with the content they manage. A well-designed composable system should not only consider the technical aspects but also take into account the nature of the content it handles. To help us with that, we can use a Headless Content Management system such as Storyblok.
Storyblok: Headless CMS With A Composable Approach
Storyblok is a Headless Content Management System with many features and capabilities that help content editors, marketers, and other types of users to create and manage content efficiently. The content created with Storyblok (or any Headless CMS) can be presented in any way, as these platforms don’t force the developers to use a particular presentation layer logic.
The advantage of Storyblok, speaking about composability, is the component approach it uses to manage the content structures. Because of its Headless nature, Storyblok allows you to use the created components (or “blocks”, as they are called on the platform) with any technology or framework. Linking to the previous topic, you can create component structures to manage content in Storyblok while managing their visual representation with React components on the client-side (or server-side) of your application.
Conclusion
Composability is a powerful paradigm that transforms the way we approach web development. By fostering modularity, reusability, and adaptability, a composable architecture lays the groundwork for building robust and scalable web applications. As we navigate through both server and client sides, aligning with content management, developers can harness the full potential of composability in order to create a cohesive and efficient web development ecosystem.