Composable Execution Layer (CEL)

By Everett Quebral
Picture of the author
Published on
image alt attribute

Revolutionizing Frontend Architecture with React

Introduction to CEL

The Composable Execution Layer (CEL) provides a modern, modular approach to building frontend applications. With CEL, core business logic is decoupled from the rendering layer, enabling you to build reusable, flexible, and reactive components. This approach allows you to build once, deploy everywhere, enhancing both development speed and consistency across multiple platforms (web, mobile, etc.).

Why CEL?

In a world where frontend architectures are becoming more distributed, CEL provides a way to structure your application into small, reusable pieces that can be composed together to form rich, dynamic user interfaces. By using CEL with React, you can take advantage of a reactive, component-based design while maintaining modularity and reusability.

Core Principles of CEL in React

  1. Componentization: React’s component-based architecture aligns perfectly with CEL. Each component can be encapsulated with its logic and UI rendering, allowing it to be reused in different contexts without modifying the underlying business logic.

  2. Reactive Execution: CEL leverages React’s reactive nature, where components automatically update the UI based on changes in state or props. This ensures that the user interface remains consistent and reflects the current state without manual intervention.

  3. Platform-Agnostic Adapters: With CEL, React components interact with platform-specific adapters, which are responsible for adapting the core logic to work with different UI rendering engines (React, React Native, etc.).

  4. Composable and Dynamic UI: CEL enables the creation of dynamic and composable UIs. In React, you can dynamically render components based on state or props, creating rich, responsive user interfaces.


How CEL Works in React: Architecture Breakdown

CEL is designed around a layered architecture that separates the core logic, adapters, and rendering logic. Here's how each component works in the context of React:

1. Core Logic

The core logic holds the business rules and processes. It’s independent of the UI framework and can be reused across various environments. In the context of React, the core logic doesn’t worry about how data is rendered or displayed on the screen.

Example: Core Logic for a Product Page in React
// coreLogic.js
class ProductPageLogic {
  constructor(productService) {
    this.productService = productService;
    this.cartService = new CartService();
  }

  async loadProduct(productId) {
    const product = await this.productService.getProductDetails(productId);
    this.product = product;
    this.productAvailability = product.stock > 0;
    return product;
  }

  addToCart() {
    this.cartService.addItemToCart(this.product);
  }
}

export default ProductPageLogic;

In this example, ProductPageLogic handles loading the product data, checking stock, and adding the product to the shopping cart. The logic is separate from the UI rendering, and it can be reused across different platforms.


2. Contracts

Contracts define the interface between the core logic and the external systems (adapters). The contract ensures that data is passed in a consistent way, maintaining the separation between logic and presentation.

Example: ProductService Contract
// IProductService.js
class IProductService {
  async getProductDetails(productId) {
    throw new Error('Method not implemented');
  }
}

export default IProductService;

In this example, the IProductService contract specifies that any adapter implementing this service must have the getProductDetails method. The core logic will use this method without worrying about how the data is fetched (whether from a REST API, GraphQL, or some other source).


3. Adapters

Adapters connect the core logic to the platform-specific rendering layer. They are responsible for implementing the contracts and interacting with external data sources, transforming the data into a format that React components can use.

Example: Web Adapter for Fetching Product Data
// WebProductAdapter.js
import IProductService from './IProductService';

class WebProductAdapter extends IProductService {
  constructor() {
    super();
    this.apiUrl = "https://api.example.com/products";
  }

  async getProductDetails(productId) {
    const response = await fetch(`${this.apiUrl}/${productId}`);
    const product = await response.json();
    return product;
  }
}

export default WebProductAdapter;

Here, the WebProductAdapter fetches product details from an API and implements the IProductService contract. This adapter can be used by the core logic to get product data, and it abstracts away the platform-specific details (e.g., how data is fetched).


4. Renderers in React

The renderers are platform-specific components that take the data provided by the adapters and render it to the screen. In React, these are the actual UI components that use the core logic to render dynamic content.

Example: React Component to Display Product
// ProductPage.js (React Component)
import React, { useState, useEffect } from 'react';
import ProductPageLogic from './coreLogic';
import WebProductAdapter from './WebProductAdapter';

const ProductPage = ({ productId }) => {
  const [product, setProduct] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  
  const logic = new ProductPageLogic(new WebProductAdapter());

  useEffect(() => {
    const fetchProduct = async () => {
      try {
        const productData = await logic.loadProduct(productId);
        setProduct(productData);
      } catch (err) {
        setError('Failed to load product');
      } finally {
        setLoading(false);
      }
    };
    
    fetchProduct();
  }, [productId, logic]);

  const handleAddToCart = () => {
    logic.addToCart();
    alert('Product added to cart');
  };

  if (loading) {
    return <div>Loading...</div>;
  }

  if (error) {
    return <div>{error}</div>;
  }

  return (
    <div>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      <p>Price: ${product.price}</p>
      <button onClick={handleAddToCart}>Add to Cart</button>
    </div>
  );
};

export default ProductPage;

Here, the ProductPage React component uses the ProductPageLogic class (with the WebProductAdapter) to load product data and render it to the screen. The component is entirely focused on the presentation of the data, while the core logic handles all the business rules. This separation allows you to reuse the same core logic in different environments (e.g., web, mobile).


Benefits of CEL in React

  1. Separation of Concerns: CEL keeps business logic separate from rendering logic. This ensures that UI components focus solely on displaying data, while the core logic handles processing. It makes your application more modular and easier to maintain.

  2. Reusable Components: The core logic is reusable across different platforms, and you only need to write platform-specific adapters once. This allows you to build once, deploy everywhere.

  3. Dynamic and Reactive UIs: By using React’s built-in reactivity, CEL ensures that your UIs update automatically whenever the underlying data changes, resulting in smooth user interactions.

  4. Easier Testing: Since core logic is decoupled from the UI, it can be easily unit tested. You can test the business logic without worrying about the UI, making it easier to ensure correctness.


Conclusion

The Composable Execution Layer (CEL) combined with React offers a powerful solution for building modern, scalable, and flexible frontend architectures. By separating the core business logic from the UI layer, CEL enables componentization, reusability, and platform-agnostic development, all while leveraging React’s reactive design for dynamic, real-time user interfaces.

With CEL, you can focus on building high-quality business logic and reusable components, ensuring consistency across multiple platforms while accelerating development cycles.

Stay Tuned

Want to become a Next.js pro?
The best articles, links and news related to web development delivered once a week to your inbox.