Redux

5 posts

daangnOriginal article

Redux for Servers: Developing a (opens in new tab)

Traditional CRUD-based architectures often struggle to meet complex backend requirements such as audit logging, version history, and state rollbacks. To address these challenges, Daangn’s Frontend Core team developed **Ventyd**, an open-source TypeScript library that implements event sourcing on the server using patterns familiar to Redux users. By shifting the focus from storing "current state" to storing a "history of events," developers can build more traceable and resilient systems. ### Limitations of Traditional CRUD * Standard CRUD (Create, Read, Update, Delete) patterns only record the final state of data, losing the context of "why" or "how" a change occurred. * Implementing complex features like approval workflows or history tracking usually requires manual table management, such as adding `status` columns or creating separate history tables. * Rollback logic in CRUD is often fragile and requires complex custom code to revert data to a previous specific state. ### The Event Sourcing Philosophy * Instead of overwriting rows in a database, event sourcing records every discrete action (e.g., "Post Created," "Post Approved," "Profile Updated") as an immutable sequence. * The system provides a built-in audit log, ensuring every change is attributed to a specific user, time, and reason. * State can be reconstructed for any point in time by "replaying" events, enabling seamless "time travel" and easier debugging. * It allows for deeper business insights by providing a full narrative of data changes rather than just a snapshot. ### Redux as a Server-Side Blueprint * The library leverages the familiarity of Redux to bridge the gap between frontend and backend engineering. * Just as Redux uses **Actions** and **Reducers** to manage state in the browser, event sourcing uses **Events** and **Reducers** to manage state in the database. * The primary difference is persistence: Redux manages state in memory, while Ventyd persists the event stream to a database for permanent storage. ### Technical Implementation with Ventyd * **Type-Safe Schemas**: Developers use `defineSchema` to define the shape of both the events and the resulting state, ensuring strict TypeScript validation. * **Validation Library Support**: Ventyd is flexible, supporting various validation libraries including Valibot, Zod, TypeBox, and ArkType. * **Reducer Logic**: The `defineReducer` function centralizes how the state evolves based on incoming events, making state transitions predictable and easy to test. * **Database Agnostic**: The library is designed to be flexible regarding the underlying storage, allowing it to integrate with different database systems. Ventyd offers a robust path for teams needing more than what basic CRUD can provide, particularly for internal tools requiring high accountability. By adopting this event-driven approach, developers can simplify the implementation of complex business logic while maintaining a clear, type-safe history of every action within their system.

figma3 min readCurated summary

LiveGraph: real-time data fetching at Figma | Figma Blog

LiveGraph is Figma’s in-house real-time data-fetching layer built on PostgreSQL. It lets frontend developers declare live data views with GraphQL-like queries, while LiveGraph reads PostgreSQL’s replication stream to deliver updates within milliseconds. Figma built it to replace fragile, manually maintained client events and to support real-time subscriptions at large scale without relying on polling or a new database technology. ## Problems with Figma’s Earlier Real-Time Architecture - React clients initially loaded large data sets through Ruby HTTP endpoints and stored them in Redux. - Backend code manually emitted events whenever database records changed. - Frontends subscribed over WebSockets and applied those events to client state. - As data volumes grew, Figma split requests into incremental loads, making data ownership and availability harder to reason about. - Complex changes—such as permission updates affecting many resources—were difficult to represent with individual events. - Events could arrive out of order or fail to correspond reliably with database writes, causing client state to diverge from server state. ## Why Figma Chose Live Queries - Figma wanted developers to define data subscriptions declaratively rather than manually coordinate fetches and update events. - GraphQL provided a natural interface for describing the relevant portion of the object graph. - LiveGraph uses “live queries,” which keep query results synchronized, rather than GraphQL subscriptions in the narrower sense of consuming event streams. - The system is a query and data-fetching layer over existing PostgreSQL infrastructure, not a replacement persistence layer. ## In-House System Versus Existing Tools - Figma’s multiplayer service handles collaborative writes and conflict resolution within individual files, whereas LiveGraph focuses on reading application data. - Systems such as Hasura, Prisma, and PostGraphile offered GraphQL subscription features but were not designed primarily for Figma’s scale of concurrent live subscriptions. - Polling was rejected because it increases database load and requires developers to choose polling intervals for each query. - Figma’s collaborative product made real-time data central enough to justify building and operating a specialized internal system. - The company did not claim LiveGraph was universally superior; its value came from matching Figma’s specific scale and requirements. ## Replication-Stream-Based Updates - LiveGraph executes queries directly against PostgreSQL. - It tails the database replication log to detect changes instead of repeatedly polling tables. - Reading the replication stream enables update latency measured in milliseconds. - Because the system must process the complete volume of database changes, its architecture needs to distribute updates across machines and database shards. - This approach separates the complexity of detecting database changes from product code, allowing frontend engineers to work with declarative JSON data views. ## Frontend API - Product developers send GraphQL-like queries and receive results as JSON trees. - A schema defines server-side entities and relationships, while views expose queryable subsets of that graph. - The frontend can therefore request the data it needs and rely on LiveGraph to keep the result synchronized as the underlying PostgreSQL data changes. LiveGraph’s central recommendation is architectural: derive live client views from the database’s authoritative change stream rather than maintaining a parallel network of hand-written events. For organizations with similar scale and real-time requirements, this can improve consistency and simplify product development, though Figma’s in-house approach was justified by its unusually collaborative workload.

Read original(opens in new tab)
figma3 min readCurated summary

React at 60fps: improving scrolling comments in Figma | Figma Blog

Figma improved comment-scrolling performance threefold by targeting unnecessary React work during canvas panning and zooming. Although comment pins must recalculate their positions on every viewport update, unrelated fixed-position UI components were also re-rendering. By isolating viewport-dependent updates and optimizing comment transformations, Figma moved closer to its goal of maintaining 60fps even in files with many comments. ## The Performance Goal - Figma aimed to render the editor at 60fps, which is substantially smoother than 15 or 30fps. - Growing numbers of comments and threads exposed slowdowns while users panned and zoomed around the canvas. - Comment pins are anchored to canvas content, so their positions must continuously respond to viewport changes. ## Figma’s Rendering Architecture - The editor combines WebGL, WebAssembly, TypeScript, and React—effectively a browser-based design tool with a dynamic React interface. - Viewport updates are stored in Redux. - Comment components read viewport state and calculate their positions relative to the canvas. - Unlike static React interfaces, comments move as part of the canvas and must update frequently. ## Diagnosing the Bottleneck - Chrome Performance tools showed that JavaScript consumed most of the frame time. - With 30 comments, approximately 68ms per frame was spent on JavaScript, producing about 19fps. - React Profiler showed that rendering the comments themselves took only about 1.8ms. - The larger problem was unnecessary re-rendering of fixed UI elements such as: - The left panel - Toolbar - Properties panel - Comments list - Other components that did not depend on viewport movement - This revealed that viewport updates were propagating too broadly through the React component tree. ## Preventing Unnecessary Re-renders - Figma narrowed which components subscribed to viewport changes. - Components that did not need changing viewport data were prevented from re-rendering. - The optimization focused on separating dynamic canvas-attached comments from fixed interface elements. - Reducing this wasted React work freed time in each frame for the comment pins that actually needed updates. ## Optimizing Comment Positioning - Comment pins must transform their positions whenever the canvas viewport changes. - Figma optimized the transformation calculations and the way those updates were applied to the components. - This reduced the JavaScript cost of moving many comment pins simultaneously. ## Results - Scrolling comments became roughly three times faster. - The improvements brought performance closer to the 60fps target. - Figma planned to continue improving performance as files and comment counts scale. The main lesson is to profile both browser execution and React rendering separately. For highly interactive views, performance depends not only on optimizing the visible components, but also on ensuring that unrelated parts of the application do not re-render in response to high-frequency state updates.

Read original(opens in new tab)
datadog2 min readCurated summary

Engineering spotlight: Marie-Laure Bardonnet

Datadog’s Notebooks feature demonstrates that interns can make substantial contributions when given meaningful ownership and effective mentorship. Marie-Laure Bardonnet progressed from small bug fixes to prototyping the feature, gaining hands-on experience with React, Redux, and Redux Saga. Her experience ultimately led to continued part-time work and a full-time role at Datadog. ## From Bug Fixes to Feature Ownership - Marie-Laure initially handled small issues, such as fixing a dashboard favorite-star interaction. - Gradually more complex tasks helped her learn Datadog’s codebase and application architecture. - Rather than limiting her to routine maintenance, Datadog assigned her a major project earlier than expected. ## Building Datadog Notebooks - Notebooks let users save graphs from a specific point in time alongside text and other contextual information. - The feature is designed to preserve and share organizational knowledge, helping teams respond more quickly. - Marie-Laure built most of the prototype during her seven-month internship. - The project introduced her to: - React for the frontend - Redux for state management - Redux Saga for handling side effects ## The Role of Mentorship - Team lead Ivan DiLernia gave Marie-Laure substantial autonomy while remaining available for difficult architectural decisions. - He encouraged her to investigate ideas independently, then collaborated with her when problems required deeper discussion. - Marie-Laure identified this balance between independence and guidance as one of the most valuable parts of the internship. ## Lasting Impact - The internship changed how Marie-Laure viewed her academic coursework, helping her distinguish practical engineering skills from more theoretical material. - After returning to France, she continued working part-time on Notebooks and other web-platform projects. - She later completed her studies and accepted a full-time position at Datadog. Datadog’s experience suggests that internships are most effective when they combine gradual onboarding, meaningful technical ownership, and thoughtful mentorship rather than restricting interns to low-impact tasks.

Read original(opens in new tab)
datadog3 min readCurated summary

Redux-Doghouse: Creating reusable React-Redux components through scoping

Redux-Doghouse is a Redux library for creating scoped actions and reducers, allowing reusable React/Redux components to coexist without responding to one another’s actions. It preserves Redux’s ability to coordinate state across an application while ensuring that component-local actions affect only the instance that dispatched them. Datadog developed it to support reusable Query Editors within larger editors such as dashboards and Expression Editors. ## The Problem with Reusable Redux Components - Redux reducers respond to actions based on their `TYPE`. - If multiple instances of the same component share a Redux store, an action such as `MY_ACTION` can update every instance. - This is useful for application-wide events, but incorrect when an action should affect only one component instance. - Refactoring each component to use unique action types would undermine its reusability and independence. ## Scoped Actions and Reducers - Redux-Doghouse adds a unique scope to each component instance’s actions. - Reducers are wrapped so that a scoped action is routed only to the matching component instance. - A component can therefore continue using generic action types such as `MY_ACTION` while remaining isolated from sibling instances. - Higher-level components can still observe and respond to those actions, preserving Redux’s cross-component coordination. - The parent can extend a child component’s behavior without requiring the child to know about its parent. ## Datadog’s Query Editor Use Case - Datadog’s dashboards contain Query Editor components for editing individual metrics. - Query Editors were rebuilt as miniature React/Redux applications so they could be reused in: - Dashboard graph editors - Monitor editors - Notebook editors - Other application contexts - The Expression Editor needed to render an arbitrary number of Query Editors and combine their queries with expressions such as `a + b / c`. ## Coordinating Child Editors The Expression Editor needed to: - Validate that expressions reference existing query labels, rejecting inputs such as `a + d` when query `d` does not exist. - Enforce compatible `group by` values across queries: - Queries may share a value such as `host`. - Some queries may have no grouping. - Non-empty groupings such as `host` and `device` cannot be mixed. - Ensure that a `SET_GROUP` action from Query Editor A affects only A, not Query Editor B. - Allow the Expression Editor itself to observe `SET_GROUP` and enforce rules across all queries. - Keep Query Editors independent so they remain usable outside an Expression Editor. ## How Doghouse Solves It - The parent assigns each Query Editor a scope, such as `A`, `B`, or `C`. - Actions dispatched by each editor receive metadata identifying that scope. - The parent wraps each editor’s reducers and routes actions only to the reducer with the matching scope. - The Expression Editor can still listen to the same actions at a higher level and apply cross-editor validation or coordination. Redux-Doghouse is most useful when reusable Redux components need isolated local behavior while still participating in a shared application state. It lets teams organize actions and reducers by component, rather than forcing all Redux logic to be structured around entire views.

Read original(opens in new tab)